diff --git a/.gitignore b/.gitignore index c2ed4ecb0acd28126d8703e17e86775ccbed1bb6..d47ecbb26d72ad88f639b6bb4cdb2c8aff195fff 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,6 @@ all.config # Kdevelop4 *.kdev4 + +# fetched Android config fragments +kernel/configs/android-*.cfg diff --git a/AndroidKernel.mk b/AndroidKernel.mk index d28f7bab5244193b5e696aef457287586f665a73..2a8d506597846389e38795c6ee1d2982d4bac0e0 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -6,6 +6,13 @@ ifeq ($(KERNEL_TARGET),) INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel endif +TARGET_KERNEL_MAKE_ENV := $(strip $(TARGET_KERNEL_MAKE_ENV)) +ifeq ($(TARGET_KERNEL_MAKE_ENV),) +KERNEL_MAKE_ENV := +else +KERNEL_MAKE_ENV := $(TARGET_KERNEL_MAKE_ENV) +endif + TARGET_KERNEL_ARCH := $(strip $(TARGET_KERNEL_ARCH)) ifeq ($(TARGET_KERNEL_ARCH),) KERNEL_ARCH := arm @@ -88,8 +95,8 @@ TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb endif KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr -KERNEL_MODULES_INSTALL := system -KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules +KERNEL_MODULES_INSTALL ?= system +KERNEL_MODULES_OUT ?= $(PRODUCT_OUT)/$(KERNEL_MODULES_INSTALL)/lib/modules TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL) @@ -121,26 +128,26 @@ $(KERNEL_OUT): mkdir -p $(KERNEL_OUT) $(KERNEL_CONFIG): $(KERNEL_OUT) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG) $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL) $(hide) echo "Building kernel..." $(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install $(mv-modules) $(clean-module-folder) $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install;\ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \ + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install;\ if [ -d "$(KERNEL_HEADERS_INSTALL)/include/bringup_headers" ]; then \ cp -Rf $(KERNEL_HEADERS_INSTALL)/include/bringup_headers/* $(KERNEL_HEADERS_INSTALL)/include/ ;\ fi ;\ @@ -148,20 +155,20 @@ $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \ echo "Used a different defconfig for header generation"; \ rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi $(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \ echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \ echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG) - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG) env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig env KCONFIG_NOTIMESTAMP=true \ - $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig + $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig cp $(KERNEL_OUT)/defconfig $(TARGET_KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG) endif diff --git a/Documentation/ABI/testing/sysfs-bus-usb-lvstest b/Documentation/ABI/testing/sysfs-bus-usb-lvstest index 5151290cf8e75f27642d1c4d52ede0cd039f3d24..ee0046dc41928ae01e537026d443c832c73b83ab 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb-lvstest +++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest @@ -45,3 +45,16 @@ Contact: Pratyush Anand Description: Write to this node to issue "U3 exit" for Link Layer Validation device. It is needed for TD.7.36. + +What: /sys/bus/usb/devices/.../enable_compliance +Date: July 2017 +Description: + Write to this node to set the port to compliance mode to test + with Link Layer Validation device. It is needed for TD.7.34. + +What: /sys/bus/usb/devices/.../warm_reset +Date: July 2017 +Description: + Write to this node to issue "Warm Reset" for Link Layer Validation + device. It may be needed to properly reset an xHCI 1.1 host port if + compliance mode needed to be explicitly enabled. diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 49874173705507f72fac2f5f55da46fc34c3cc52..dfd56ec7a850c1c3b722fe09403e74ea8ca849d7 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -350,3 +350,19 @@ Contact: Linux ARM Kernel Mailing list Description: AArch64 CPU registers 'identification' directory exposes the CPU ID registers for identifying model and revision of the CPU. + +What: /sys/devices/system/cpu/vulnerabilities + /sys/devices/system/cpu/vulnerabilities/meltdown + /sys/devices/system/cpu/vulnerabilities/spectre_v1 + /sys/devices/system/cpu/vulnerabilities/spectre_v2 +Date: January 2018 +Contact: Linux kernel mailing list +Description: Information about CPU vulnerabilities + + The files are named after the code names of CPU + vulnerabilities. The output of those files reflects the + state of the CPUs in the system. Possible output values: + + "Not affected" CPU is not affected by the vulnerability + "Vulnerable" CPU is affected and no mitigation in effect + "Mitigation: $M" CPU is affected and mitigation $M is in effect diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt index d534246475c8810a1ff45804c9edb0523b9ab72b..01e865d2dd3c8b30cacb4c4cafb98d109f44feed 100644 --- a/Documentation/DMA-attributes.txt +++ b/Documentation/DMA-attributes.txt @@ -182,6 +182,11 @@ DMA_ATTR_FORCE_COHERENT When passed to a DMA map call the DMA_ATTR_FORCE_COHERENT DMA attribute can be used to force a buffer to be mapped as IO coherent. + +When the DMA_ATTR_FORCE_COHERENT attribute is set during a map call ensure +that it is also set during for the matching unmap call to ensure that the +correct cache maintenance is carried out. + This DMA attribute is only currently supported for arm64 stage 1 IOMMU mappings. @@ -193,5 +198,10 @@ attribute can be used to force a buffer to not be mapped as IO coherent. The DMA_ATTR_FORCE_NON_COHERENT DMA attribute overrides the buffer IO coherency configuration set by making the device IO coherent. + +When the DMA_ATTR_FORCE_NON_COHERENT attribute is set during a map call +ensure that it is also set during for the matching unmap call to ensure +that the correct cache maintenance is carried out. + This DMA attribute is only currently supported for arm64 stage 1 IOMMU mappings. diff --git a/Documentation/arm/msm/remote_debug_drv.txt b/Documentation/arm/msm/remote_debug_drv.txt new file mode 100644 index 0000000000000000000000000000000000000000..13a35f43e86befa1ea75d4133d44f883c3a95ea9 --- /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- + 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/arm/msm/rpm.txt b/Documentation/arm/msm/rpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5be6a7e28901c5e8e5f17167baf3b9cee36625f --- /dev/null +++ b/Documentation/arm/msm/rpm.txt @@ -0,0 +1,157 @@ +Introduction +============ + +Resource Power Manager (RPM) + +RPM is a dedicated hardware engine for managing shared SoC resources, +which includes buses, clocks, power rails, etc. The goal of RPM is +to achieve the maximum power savings while satisfying the SoC's +operational and performance requirements. RPM accepts resource +requests from multiple RPM masters. It arbitrates and aggregates the +requests, and configures the shared resources. The RPM masters are +the application processor, the modem processor, as well as some +hardware accelerators. + +The RPM driver provides an API for interacting with RPM. Kernel code +calls the RPM driver to request RPM-managed, shared resources. +Kernel code can also register with the driver for RPM notifications, +which are sent when the status of shared resources change. + +Hardware description +==================== + +RPM exposes a separate region of registers to each of the RPM masters. +In general, each register represents some shared resource(s). At a +very basic level, a master requests resources by writing to the +registers, then generating an interrupt to RPM. RPM processes the +request, writes acknowledgment to the registers, then generates an +interrupt to the master. + +In addition to the master-specific regions, RPM also exposes a shared +region that contains the current status of the shared resources. Only +RPM can write to the status region, but every master can read from it. + +RPM contains internal logics that aggregate and arbitrate among +requests from the various RPM masters. It interfaces with the PMIC, +the bus arbitration block, and the clock controller block in order to +configure the shared resources. + +Software description +==================== + +The RPM driver encapsulates the low level RPM interactions, which +rely on reading/writing registers and generating/processing +interrupts, and provides a higher level synchronuous set/clear/get +interface. Most functions take an array of id-value pairs. +The ids identify the RPM registers which would correspond to some +RPM resources, the values specify the new resource values. + +The RPM driver synchronizes accesses to RPM. It protects against +simultaneous accesses from multiple tasks, on SMP cores, in task +contexts, and in atomic contexts. + +Design +====== + +Design goals: +- Encapsulate low level RPM interactions. +- Provide a synchronuous set/clear/get interface. +- Synchronize simultaneous software accesses to RPM. + +Power Management +================ + +RPM is part of the power management architecture for MSM 8660. RPM +manages shared system resources to lower system power. + +SMP/multi-core +============== + +The RPM driver uses mutex to synchronize client accesses among tasks. +It uses spinlocks to synchronize accesses from atomic contexts and +SMP cores. + +Security +======== + +None. + +Performance +=========== + +None. + +Interface +========= + +msm_rpm_get_status(): +The function reads the shared status region and returns the current +resource values, which are the arbitrated/aggregated results across +all RPM masters. + +msm_rpm_set(): +The function makes a resource request to RPM. + +msm_rpm_set_noirq(): +The function is similar to msm_rpm_set() except that it must be +called with interrupts masked. If possible, use msm_rpm_set() +instead, to maximize CPU throughput. + +msm_rpm_clear(): +The function makes a resource request to RPM to clear resource values. +Once the values are cleared, the resources revert back to their default +values for this RPM master. RPM internally uses the default values as +the requests from this RPM master when arbitrating and aggregating with +requests from other RPM masters. + +msm_rpm_clear_noirq(): +The function is similar to msm_rpm_clear() except that it must be +called with interrupts masked. If possible, use msm_rpm_clear() +instead, to maximize CPU throughput. + +msm_rpm_register_notification(): +The function registers for RPM notification. When the specified +resources change their status on RPM, RPM sends out notifications +and the driver will "up" the semaphore in struct +msm_rpm_notification. + +msm_rpm_unregister_notification(): +The function unregisters a notification. + +msm_rpm_init(): +The function initializes the RPM driver with platform specific data. + +Driver parameters +================= + +None. + +Config options +============== + +MSM_RPM + +Dependencies +============ + +None. + +User space utilities +==================== + +None. + +Other +===== + +None. + +Known issues +============ + +None. + +To do +===== + +None. diff --git a/Documentation/arm64/tagged-pointers.txt b/Documentation/arm64/tagged-pointers.txt index d9995f1f51b3eb9e678a557a471e4d387db49ca8..a25a99e82bb1c9811ee3e8cb111d356fa53fc979 100644 --- a/Documentation/arm64/tagged-pointers.txt +++ b/Documentation/arm64/tagged-pointers.txt @@ -11,24 +11,56 @@ in AArch64 Linux. The kernel configures the translation tables so that translations made via TTBR0 (i.e. userspace mappings) have the top byte (bits 63:56) of the virtual address ignored by the translation hardware. This frees up -this byte for application use, with the following caveats: +this byte for application use. - (1) The kernel requires that all user addresses passed to EL1 - are tagged with tag 0x00. This means that any syscall - parameters containing user virtual addresses *must* have - their top byte cleared before trapping to the kernel. - (2) Non-zero tags are not preserved when delivering signals. - This means that signal handlers in applications making use - of tags cannot rely on the tag information for user virtual - addresses being maintained for fields inside siginfo_t. - One exception to this rule is for signals raised in response - to watchpoint debug exceptions, where the tag information - will be preserved. +Passing tagged addresses to the kernel +-------------------------------------- - (3) Special care should be taken when using tagged pointers, - since it is likely that C compilers will not hazard two - virtual addresses differing only in the upper byte. +All interpretation of userspace memory addresses by the kernel assumes +an address tag of 0x00. + +This includes, but is not limited to, addresses found in: + + - pointer arguments to system calls, including pointers in structures + passed to system calls, + + - the stack pointer (sp), e.g. when interpreting it to deliver a + signal, + + - the frame pointer (x29) and frame records, e.g. when interpreting + them to generate a backtrace or call graph. + +Using non-zero address tags in any of these locations may result in an +error code being returned, a (fatal) signal being raised, or other modes +of failure. + +For these reasons, passing non-zero address tags to the kernel via +system calls is forbidden, and using a non-zero address tag for sp is +strongly discouraged. + +Programs maintaining a frame pointer and frame records that use non-zero +address tags may suffer impaired or inaccurate debug and profiling +visibility. + + +Preserving tags +--------------- + +Non-zero tags are not preserved when delivering signals. This means that +signal handlers in applications making use of tags cannot rely on the +tag information for user virtual addresses being maintained for fields +inside siginfo_t. One exception to this rule is for signals raised in +response to watchpoint debug exceptions, where the tag information will +be preserved. The architecture prevents the use of a tagged PC, so the upper byte will be set to a sign-extension of bit 55 on exception return. + + +Other considerations +-------------------- + +Special care should be taken when using tagged pointers, since it is +likely that C compilers will not hazard two virtual addresses differing +only in the upper byte. diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt index ad440a2b8051cfadad0f3d89c7cc76cb99b5508c..e926aea1147d49a06aadb5bc39cd4802afba7053 100644 --- a/Documentation/devicetree/bindings/arm/arch_timer.txt +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt @@ -31,6 +31,12 @@ to deliver its interrupts via SPIs. This also affects writes to the tval register, due to the implicit counter read. +- hisilicon,erratum-161010101 : A boolean property. Indicates the + presence of Hisilicon erratum 161010101, which says that reading the + counters is unreliable in some cases, and reads may return a value 32 + beyond the correct value. This also affects writes to the tval + registers, due to the implicit counter read. + ** Optional properties: - arm,cpu-registers-not-fw-configured : Firmware does not initialize diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index fe53218d9214d8d0a523eefbc6dca06ab82f2aba..9a9a6d068f3be697064b32673f449c781aa57766 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -39,6 +39,8 @@ its hardware characteristcs. - System Trace Macrocell: "arm,coresight-stm", "arm,primecell"; [1] + - Trigger Generation Unit: + "arm,primecell"; * reg: physical base address and length of the register set(s) of the component. @@ -76,6 +78,7 @@ its hardware characteristcs. - "qcom,coresight-remote-etm" - "qcom,coresight-hwevent" - "qcom,coresight-dummy" + - "qcom,coresight-dbgui" * port or ports: same as above. @@ -86,6 +89,16 @@ its hardware characteristcs. * qcom,dummy-sink: Configure the device as sink. +* Additional required property for coresight-tgu devices: + * tgu-steps: must be present. Indicates number of steps supported + by the TGU. + * tgu-conditions: must be present. Indicates the number of conditions + supported by the TGU. + * tgu-regs: must be present. Indicates the number of regs supported + by the TGU. + * tgu-timer-counters: must be present. Indicates the number of timers and + counters available in the TGU to do a comparision. + * Optional properties for all components: * reg-names: names corresponding to each reg property value. @@ -141,10 +154,42 @@ its hardware characteristcs. * qcom,msr-fix-req: boolean, indicating if MSRs need to be programmed after enabling the subunit. + * qcom,dump-enable: boolean, specifies to dump MCMB data. +* Optional properties for CTI: + + * qcom,cti-gpio-trigin: cti trigger input driven by gpio. + + * qcom,cti-gpio-trigout: cti trigger output sent to gpio. + + * pinctrl-names: names corresponding to the numbered pinctrl. The + allowed names are subset of the following: cti-trigin-pinctrl, + cti-trigout-pctrl. + + * pinctrl-: list of pinctrl phandles for the different pinctrl + states. Refer to + "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + * Required property for Remote ETMs: * qcom,inst-id: must be present. QMI instance id for remote ETMs. +* Optional properties for funnels: + + * qcom,duplicate-funnel: boolean, indicates its a duplicate of an + existing funnel. Funnel devices are now capable of supporting + multiple-input and multiple-output configuration with in built + hardware filtering for TPDM devices. Each set of input-output + combination is treated as independent funnel device. + funnel-base-dummy and funnel-base-real reg-names must be specified + when this property is enabled. + + * reg-names: funnel-base-dummy: dummy register space used by a + duplicate funnel. Should be a valid register address space that + no other device is using. + + * reg-names: funnel-base-real: actual register space for the + duplicate funnel. + Example: 1. Sinks @@ -357,7 +402,7 @@ Example: }; }; -4. CTIs +5. CTIs cti0: cti@6010000 { compatible = "arm,coresight-cti", "arm,primecell"; reg = <0x6010000 0x1000>; @@ -369,5 +414,21 @@ Example: clock-names = "apb_pclk"; }; +6. TGUs + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06B0C000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; [1]. There is currently two version of STM: STM32 and STM500. Both have the same HW interface and as such don't need an explicit binding name. diff --git a/Documentation/devicetree/bindings/arm/msm/board-id.txt b/Documentation/devicetree/bindings/arm/msm/board-id.txt new file mode 100644 index 0000000000000000000000000000000000000000..e07a1c9e6dcb06f0a7e24fda496eb308b73045f3 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/board-id.txt @@ -0,0 +1,64 @@ +* BOARD-ID + +The qcom,board-id entry specifies the MSM platform and subtype revision. +It can optionally be an array of these to indicate multiple hardware that use +the same device tree. It is expected that the bootloader will use this +information at boot-up to decide which device tree to use when given multiple +device trees, some of which may not be compatible with the actual hardware. It +is the bootloader's responsibility to pass the correct device tree to the kernel. + +Legacy format: + +It is expected that the qcom,board-id entry be at the top level of the device +tree structure. The format of the entry is: + + qcom,board-id = [, ...] + +where platform_id and subtype_id are the numeric values for the platform and +subtype of the current hardware. + +The "subtype_id" cell is a 32-bit integer whose bit values are defined as follows: + bits 31-20 = Reserved bits + bits 19-16 = Boot Device Type. + MSM: + 0: default (eMMC) + 2: EMMC_SDC1 + 4: BOOT_UFS + MDM: + 0: default (NAND) + 3: EMMC_SDC1 + bits 15-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1, default value as 0x0 + bits 7-0 = Platform Subtype + +In the event that a given device tree is applicable to all hardware versions +matching a given Platform Type / Subtype ID, the major/minior platform version +fields in the board_id property shall both be specified as 0xff. + +Modern format: +The cell layout of the qcom,board-id property is as follows: + + qcom,board-id = + +where board_id is a 32-bit integer whose bit values are defined as follows: + bits 31-24 = Platform Subtype ID + bits 23-16 = Platform Version (Major) + bits 15-8 = Platform Version (Minor) + bits 7-0 = Platform Type ID + +and the 'reserved' cell is a 32-bit integer whose bit values are defined as follows: + bits 31-13 = Reserved Bits + bits 12-11 = Panel Detection. 00 - limit to HD, 01 - limit to 720p, + 10 - limit to qHD, 11 - limit to FWVGA + bits 10-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1, + default value as 0x0 + bits 7-0 = Platform Subtype + +In the event that a given device tree is applicable to all hardware versions +matching a given Platform Type / Subtype ID, the major/minior platform version +fields in the board_id property shall both be specified as 0xff. + +Example: + qcom,board-id = <15 0>; + qcom,board-id = <0x01040708, 0>; + qcom,board-id = <0x01ffff08, 0>; + qcom,board-id = <8, 0x100>; diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cc49a597d4ef945343e275396c4750997e1c53f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt @@ -0,0 +1,67 @@ +Qualcomm Technologies MSM Clock controller + +Qualcomm Technologies MSM Clock controller devices contain PLLs, root clock +generators and other clocking hardware blocks that provide stable, low power +clocking to hardware blocks on Qualcomm Technologies SOCs. The clock controller +device node lists the power supplies needed to be scaled using the vdd_*-supply +property. + +Minor differences between hardware revisions are handled in code by re-using +the compatible string to indicate the revision. + +Required properties: +- compatible: Must be one of following, + "qcom,gcc-8953" + "qcom,cc-debug-8953" + "qcom,gcc-mdss-8953" + "qcom,gcc-gfx-8953" + "qcom,gcc-gfx-sdm450" + +- reg: Pairs of physical base addresses and region sizes of + memory mapped registers. +- reg-names: Names of the bases for the above registers. Currently, + there is one expected base: "cc_base". Optional + reg-names are "apcs_base", "meas", "mmss_base", + "lpass_base", "apcs_c0_base", "apcs_c1_base", + "apcs_cci_base", "efuse". + +Optional properties: +- vdd_dig-supply: The digital logic rail supply. +- _dig-supply: Some PLLs might have separate digital supply on some + targets. These properties will be provided on those + targets for specific PLLs. +- _analog-supply: Some PLLs might have separate analog supply on some + targets. These properties will be provided on those + targets for specific PLLs. +- vdd_gpu_mx-supply: MX rail supply for the GPU core. +- #clock_cells: If this device will also be providing controllable + clocks, the clock_cells property needs to be specified. + This will allow the common clock device tree framework + to recognize _this_ device node as a clock provider. +- qcom,-corner-: List of frequency voltage pairs that the clock can + operate at. Drivers can use the OPP library API to + operate on the list of OPPs registered using these + values. +- qcom,-speedbinX: A table of frequency (Hz) to voltage (corner) mapping + that represents the max frequency possible for each + supported voltage level for the clock. + 'X' is the speed bin into which the device falls into - + a bin will have unique frequency-voltage relationships. + The value 'X' is read from efuse registers, and the right + table is picked from multiple possible tables. +- qcom,-opp-handle: phandle references to the devices for which OPP + table is filled with the clock frequency and voltage + values. +- qcom,-opp-store-vcorner: phandle references to the devices for + which OPP table is filled with the clock frequency + and voltage corner/level. + +Example: + clock_gcc: qcom,gcc@fc400000 { + compatible = "qcom,gcc-8974"; + reg = <0xfc400000 0x4000>; + reg-names = "cc_base"; + vdd_dig-supply = <&pm8841_s2_corner>; + #clock-cells = <1>; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/clock-cpu-8953.txt b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8953.txt new file mode 100644 index 0000000000000000000000000000000000000000..85316abb8524834d7234700e6fb669024e4d577d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/clock-cpu-8953.txt @@ -0,0 +1,70 @@ +Qualcomm Technologies MSM8953 CPU clock tree + +clock-cpu-8953 is a device that represents the MSM8953 CPU subystem clock +tree. It lists the various power supplies that need to be scaled when the +clocks are scaled and also other HW specific parameters like fmax tables etc. + +The root clock generator could have the ramp controller in built. +Ramp control will allow programming the sequence ID for pulse swallowing, +enable sequence and for linking sequence IDs. + +Required properties: +- compatible: Must be "qcom,clock-cpu-8953". + +- reg: Pairs of physical base addresses and region sizes of + memory mapped registers. +- reg-names: Names of the bases for the above registers. Expected + bases are: + "c0-pll", "c1-pll", "c0-mux", "c1-mux", "cci-mux", + "efuse", "perf_base"(optional), "rcgwr-c0-base(optional)", + "rcgwr-c1-base(optional)". +- clocks: The clocks sources used by the cluster/cci mux. +- clock-names: Name of the clocks for the above clocks. +- vdd-mx-supply: The regulator powering all the PLLs of clusters & cci. +- vdd-cl-supply: The regulator powering the clusters & cci. +- qcom,speedX-bin-vY-ZZZ: + A table of CPU frequency (Hz) to voltage (corner) + mapping that represents the max frequency possible + for each supported voltage level for a CPU. 'X' is + the speed bin into which the device falls into - a + bin will have unique frequency-voltage relationships. + 'Y' is the characterization version, implying that + characterization (deciding what speed bin a device + falls into) methods and/or encoding may change. The + values 'X' and 'Y' are read from efuse registers, and + the right table is picked from multiple possible tables. + 'ZZZ' can be cl for(c0 & c1) or cci depending on whether + the table for the clusters or cci. + +Optional Properties: +- qcom,enable-qos: Boolean property to indicate the pm qos is required + during set rate of the cluster clocks, which would not + allow the cluster cores to go to low power mode. + +Example: + clock_cpu: qcom,cpu-clock-8953@b116000 { + compatible = "qcom,cpu-clock-8953"; + reg = <0xb114000 0x68>, + <0xb014000 0x68>, + <0xb116000 0x400>, + <0xb111050 0x08>, + <0xb011050 0x08>, + <0xb1d1050 0x08>, + <0x00a412c 0x08>; + reg-names = "rcgwr-c0-base", "rcgwr-c1-base", + "c0-pll", "c0-mux", "c1-mux", + "cci-mux", "efuse"; + vdd-mx-supply = <&pm8953_s7_level_ao>; + vdd-cl-supply = <&apc_vreg_corner>; + clocks = <&clock_gcc clk_xo_a_clk_src>; + clock-names = "xo_a"; + qcom,num-clusters = <2>; + qcom,speed0-bin-v0-cl = + < 0 0>, + < 2208000000 7>; + qcom,speed0-bin-v0-cci = + < 0 0>, + < 883200000 7>; + #address-cells = <1>; + #size-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/arm/msm/cmd-db.txt b/Documentation/devicetree/bindings/arm/msm/cmd-db.txt index b989d8a1f72ce0431fd5d42210ebf56e6016cc26..e704d70ed895449153869836d2d3507855986523 100644 --- a/Documentation/devicetree/bindings/arm/msm/cmd-db.txt +++ b/Documentation/devicetree/bindings/arm/msm/cmd-db.txt @@ -24,10 +24,12 @@ PROPERTIES: Value type: Definition: First element is the base address of shared memory Second element is the size of the shared memory region + Points to the dictionary address that houses the command DB + start address and the size of the command DB region Example: qcom,cmd-db@861e0000 { compatible = "qcom,cmd-db"; - reg = <0x861e0000 0x4000>; + reg = <0xc3f000c 0x8>; } diff --git a/Documentation/devicetree/bindings/arm/msm/glink_smem_native_xprt.txt b/Documentation/devicetree/bindings/arm/msm/glink_smem_native_xprt.txt index f68c8e4a45548370b7b80be8f0306e322e56b4de..7011d5cf4bf5ed1ed8d30148d7411db8dedbf665 100644 --- a/Documentation/devicetree/bindings/arm/msm/glink_smem_native_xprt.txt +++ b/Documentation/devicetree/bindings/arm/msm/glink_smem_native_xprt.txt @@ -11,6 +11,7 @@ Required properties: -label : the name of the subsystem this link connects to Optional properties: +-cpu-affinity: Cores to pin the interrupt and receiving work thread to. -qcom,qos-config: Reference to the qos configuration elements.It depends on ramp-time. -qcom,ramp-time: Worst case time in microseconds to transition to this power @@ -36,6 +37,7 @@ Example: qcom,irq-mask = <0x1000>; interrupts = <0 25 1>; label = "lpass"; + cpu-affinity = <1 2>; qcom,qos-config = <&glink_qos_adsp>; qcom,ramp-time = <0x10>, <0x20>, diff --git a/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt b/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt new file mode 100644 index 0000000000000000000000000000000000000000..e63d09b4c6da246630f1165f9573bd0de433a991 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt @@ -0,0 +1,44 @@ +* Memory Share Driver (MEMSHARE) + +The Memshare driver implements a Kernel QMI service on the +LA-APSS, which is responsible for providing contiguous physical +memory to MPSS for use cases when the modem requires additional +memory (e.g. GPS). + +Required properties for Memshare + +-Root Node- + +- compatible: Must be "qcom,memshare" + +Required properties for child nodes: + +- compatible: Must be "qcom,memshare-peripheral" + +- qcom,peripheral-size: Indicates the size (in bytes) required for that child. + +- qcom,client-id: Indicates the client id of the child node. + +- label: Indicates the peripheral information for the node. Should be one of + the following: + - modem /* Represent Modem Peripheral */ + - adsp /* Represent ADSP Peripheral */ + - wcnss /* Represent WCNSS Peripheral */ + +Optional properties for child nodes: + +- qcom,allocate-boot-time: Indicates whether clients needs boot time memory allocation. + +Example: + +qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x200000>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; +}; diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt index eaa7146b0746a076647df2a94a723774338527c4..440628d02630740cbac0a96dc97ed171b50dce39 100644 --- a/Documentation/devicetree/bindings/arm/msm/imem.txt +++ b/Documentation/devicetree/bindings/arm/msm/imem.txt @@ -46,6 +46,12 @@ Required properties: -compatible: "qcom,msm-imem-restart_reason -reg: start address and size of restart_reason region in imem +Download Mode Type: +------------------- +Required properties: +-compatible: "qcom,msm-imem-dload-type" +-reg: start address and size of dload type region in imem + Download Mode: -------------- Required properties: @@ -67,6 +73,11 @@ USB Diag Cookies: Memory region used to store USB PID and serial numbers to be used by bootloader in download mode. +SSR Minidump Offset +------------------- +-Compatible: "qcom,msm-imem-minidump" +-reg: start address and size of ssr imem region + Required properties: -compatible: "qcom,msm-imem-diag-dload" -reg: start address and size of USB Diag download mode region in imem @@ -115,4 +126,9 @@ Example: compatible = "qcom,msm-imem-emergency_download_mode"; reg = <0xfe0 12>; }; + + ss_mdump@b88 { + compatible = "qcom,msm-imem-minidump"; + reg = <0xb88 28>; + }; }; diff --git a/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt b/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f57d0ad9e23d1c4604264d0e4b85eea208c1200 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt @@ -0,0 +1,32 @@ +* JTAG-MM + +The jtag-mm entry specifies the memory mapped addresses for the debug and ETM +registers. The jtag-mm driver uses these to save and restore the registers +using memory mapped access during power collapse so as to retain their state +across power collapse. This is necessary in case cp14 access to the registers +is not permitted. + +Required Properties: +compatible: component name used for driver matching, should be: + "qcom,jtag-mm" - for jtag-mm device + "qcom,jtagv8-mm" - for jtagv8-mm device supporting ARMv8 targets + + reg: physical base address and length of the register set + reg-names: should be "etm-base" for etm register set and "debug-base" + for debug register set. + qcom,coresight-jtagmm-cpu: specifies phandle for the cpu associated + with the jtag-mm device + qcom,si-enable : boolean, indicating etm save and restore is + supported via system instructions + qcom,save-restore-disable : boolean, to disable etm save and restore + functionality + +Example: +jtag_mm: jtagmm@fc332000 { + compatible = "qcom,jtag-mm"; + reg = <0xfc332000 0x1000>, + <0xfc333000 0x1000>; + reg-names = "etm-base","debug-base"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; +}; diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt index ae476d07466ea02be23fbe3941d05504294ed734..55d06b25b2de6f5284ec6f4e8ed2e2a361fd378b 100644 --- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt +++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt @@ -19,18 +19,14 @@ Required properties: [Node bindings for qcom,pm-cluster] Required properties: - reg - The numeric cluster id - - label: Identifies the cluster name. The name will be - used when reporting the stats for each low power mode. - - qcom,spm-device-names: List of SPM device names which control the - low power modes for this driver. The lpm driver uses the device name - to obtain a handle to the SPM driver that controls the cluster's low - power mode. This is only required if "qcom,use-psci" is not defined. - - qcom,default-level: The default low power level that a cluster is - programmed. The SPM of the corresponding device is configured at this - low power mode by default. - - qcom,cpu: List of CPU phandles to identify the CPUs associated with - this cluster. This property is required if and only if the cluster - node contains a qcom,pm-cpu node. + - label: Identifies the cluster name. The name is used when reporting + the stats for each low power mode. + - qcom,psci-mode-shift: The property is used to determine with bit + location of the cluster mode in the composite state ID used to define + cluster low power modes in PSCI. + - qcom,psci-mode-mask: The property is used to determine with bit + mask of the cluster mode in the composite state ID used to define + cluster low power modes in PSCI. qcom,pm-cluster contains qcom,pm-cluster-level nodes which identify the various low power modes that the cluster can enter. The @@ -42,20 +38,7 @@ Required properties: - reg: The numeric cluster level id - label: Name to identify the low power mode in stats module. - - qcom,spm--mode: For each SPM device defined in - qcom,spm-devices-names, a corresponding entry identifying the low - power mode is expected. For example, the qcom,pm-cluster node contains - a SPM device by name "l2" then the cluster level should contain a - qcom,spm-l2-mode. When a cluster level is chosen ,the SPM device is - programmed with its - corresponding low power mode. The accepted values for this property - are: - - "active" - - "wfi" - - "retention" - - "gdhs" - - "pc" - - "fpc" + - qcom,psci-mode: ID to be passed into the PSCI firmware. - qcom,min-child-idx: The minimum level that a child CPU should be in before this level can be chosen. This property is required for all non-default level. @@ -67,31 +50,13 @@ Required properties: this level in mWatts.uSec - qcom,time-overhead: The time spent in entering and exiting this level in uS + Optional properties: - - qcom,notify-rpm: When set, the driver flushes the RPM sleep set and - configures the virtual MPM driver in prepration for a RPM assisted - sleep. - - qcom,last-level - When set, the cluster level is applied only when - there is 1 online core. - - qcom,disable-dynamic-int-routing: When set disables the dynamic - routing of rpm-smd and mpm interrupts to next wake up core. - - qcom,use-psci: This boolean property allows the LPM modules to - terminate in PSCI to configure SPM for low power modes. - - qcom,psci-mode-shift: The property is used to determine with bit - location of the cluster mode in the composite state ID used to define - cluster low power modes in PSCI v1.0. Required only if qcom,use-psci - is defined at the lpm-levels root node. - - qcom,psci-mode-mask: The property is used to determine with bit - mask of the cluster mode in the composite state ID used to define - cluster low power modes in PSCI v1.0. Required only if qcom,use-psci - is defined at the lpm-levels root node. - - qcom,psci-mode: ID to be passed into the PSCI firmware. Required - only if qcom,use-psci is defined at the lpm-levels root node. - - qcom,is-reset: This boolean property will tell whether - cluster level need power management notifications to be sent out - or not for the drivers to prepare for cluster collapse. - - qcom,hyp-psci: This property is used to determine if the cpu - enters the low power mode within hypervisor. + - qcom,notify-rpm: When set, the driver configures the sleep and wake + sets. It also configures the next wakeup time for APPS. + - qcom,is-reset: This boolean property tells whether cluster level need + power management notifications to be sent out or not for the drivers to + prepare for cluster collapse. - qcom,reset-level: This property is used to determine in this low power mode only control logic power collapse happens or memory logic power collapse aswell happens or retention state. @@ -103,19 +68,23 @@ Required properties: power collapse (PC) [Node bindings for qcom,pm-cpu] -qcom,pm-cpu contains the low power modes that a cpu could enter. Currently it -doesn't have any required properties and is a container for -qcom,pm-cpu-levels. +qcom,pm-cpu contains the low power modes that a cpu could enter and the CPUs +that share the parameters.It contains the following properties. + - qcom,cpu: List of CPU phandles to identify the CPUs associated with + this cluster. + - qcom,psci-mode-shift: Same as cluster level fields. + - qcom,psci-mode-mask: Same as cluster level fields. + - qcom,pm-cpu-levels: The different low power modes that a CPU could + enter. The following section explains the required properties of this + node. + -qcom,use-prediction: This optional property is used to indicate the + the LPM governor is to apply sleep prediction to this cluster. [Node bindings for qcom,pm-cpu-levels] Required properties: - reg: The numeric cpu level id - - qcom,spm-cpu-mode: The sleep mode of the processor, values for the - property are: - "wfi" - Wait for Interrupt - "retention" - Retention - "standalone_pc" - Standalone power collapse - "pc" - Power Collapse + - label: Name to identify the low power mode in stats + - qcom,psci-cpu-mode: ID to be passed into PSCI firmware. - qcom,latency-us: The latency in handling the interrupt if this level was chosen, in uSec - qcom,ss-power: The steady state power expelled when the processor is @@ -124,201 +93,188 @@ qcom,pm-cpu-levels. this level in mWatts.uSec - qcom,time-overhead: The time spent in entering and exiting this level in uS - - qcom,use-broadcast-timer: Indicates that the timer gets reset during - power collapse and the cpu relies on Broadcast timer for scheduled - wakeups. Required only for states where the CPUs internal timer state - is lost. Optional properties: - - qcom,psci-mode-shift: Same as cluster level fields. - - qcom,psci-mode-mask: Same as cluster level fields. - - qcom,psci-cpu-mode: ID to be passed into PSCI firmware. - - qcom,jtag-save-restore: A boolean specifying jtag registers save and restore - required are not. - qcom,is-reset: This boolean property maps to "power state" bit in PSCI state_id configuration. This property will tell whether CPU get reset for - a particular LPM or not. This property will also be used to notify the - drivers in case of cpu reset. + a particular LPM or not. This property is also used to notify the drivers + in case of cpu reset. + - qcom,use-broadcast-timer: Indicates that the timer gets reset during + power collapse and the cpu relies on Broadcast timer for scheduled wakeups. + Required only for states where the CPUs internal timer state is lost. [Example dts] -qcom,lpm-levels { - #address-cells = <1>; - #size-cells = <0>; - compatible = "qcom,lpm-levels"; - - qcom,pm-cluster@0 { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; #address-cells = <1>; #size-cells = <0>; - reg = <0>; - label = "system"; - qcom,spm-device-names = "cci"; - qcom,default-level = <0>; - qcom,pm-cluster-level@0{ + qcom,pm-cluster@0 { reg = <0>; - label = "system-cci-retention"; - qcom,spm-cci-mode = "retention"; - qcom,latency-us = <100>; - qcom,ss-power = <1000>; - qcom,energy-overhead = <300000>; - qcom,time-overhead = <100>; - }; - - qcom,pm-cluster-level@2{ - reg = <1>; - label = "system-cci-pc"; - qcom,spm-cci-mode = "pc"; - qcom,latency-us = <30000>; - qcom,ss-power = <83>; - qcom,energy-overhead = <2274420>; - qcom,time-overhead = <6605>; - qcom,min-child-idx = <1>; - qcom,notify-rpm; - }; - - qcom,pm-cluster@0{ #address-cells = <1>; #size-cells = <0>; - reg = <0>; - label = "a53"; - qcom,spm-device-names = "l2"; - qcom,default-level=<0>; - qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + label = "L3"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xfff>; - qcom,pm-cluster-level@0{ + qcom,pm-cluster-level@0 { /* D1 */ reg = <0>; - label = "a53-l2-retention"; - qcom,spm-l2-mode = "retention"; - qcom,latency-us = <100>; - qcom,ss-power = <1000>; - qcom,energy-overhead = <300000>; - qcom,time-overhead = <100>; + label = "l3-wfi"; + qcom,psci-mode = <0x1>; + qcom,latency-us = <51>; + qcom,ss-power = <452>; + qcom,energy-overhead = <69355>; + qcom,time-overhead = <99>; }; - qcom,pm-cluster-level@1{ + qcom,pm-cluster-level@1 { /* D2 */ reg = <1>; - label = "a53-l2-pc"; - qcom,spm-l2-mode = "pc"; - qcom,latency-us = <30000>; - qcom,ss-power = <83>; - qcom,energy-overhead = <2274420>; - qcom,time-overhead = <6605>; + label = "l3-dyn-ret"; + qcom,psci-mode = <0x2>; + qcom,latency-us = <659>; + qcom,ss-power = <434>; + qcom,energy-overhead = <465725>; + qcom,time-overhead = <976>; + qcom,min-child-idx = <1>; + }; + + qcom,pm-cluster-level@2 { /* D4, D3 is not supported */ + reg = <2>; + label = "l3-pc"; + qcom,psci-mode = <0x4>; + qcom,latency-us = <4562>; + qcom,ss-power = <408>; + qcom,energy-overhead = <2421840>; + qcom,time-overhead = <5376>; + qcom,min-child-idx = <2>; + qcom,is-reset; + }; + + qcom,pm-cluster-level@3 { /* Cx off */ + reg = <3>; + label = "cx-off"; + qcom,psci-mode = <0x224>; + qcom,latency-us = <5562>; + qcom,ss-power = <308>; + qcom,energy-overhead = <2521840>; + qcom,time-overhead = <6376>; qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; }; - qcom,pm-cpu { + qcom,pm-cluster-level@4 { /* LLCC off, AOSS sleep */ + reg = <4>; + label = "llcc-off"; + qcom,psci-mode = <0xC24>; + qcom,latency-us = <6562>; + qcom,ss-power = <108>; + qcom,energy-overhead = <2621840>; + qcom,time-overhead = <7376>; + qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { #address-cells = <1>; #size-cells = <0>; - qcom,pm-cpu-level@0 { + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ reg = <0>; - qcom,spm-cpu-mode = "wfi"; - qcom,latency-us = <1>; - qcom,ss-power = <715>; - qcom,energy-overhead = <17700>; - qcom,time-overhead = <2>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <43>; + qcom,ss-power = <454>; + qcom,energy-overhead = <38639>; + qcom,time-overhead = <83>; }; - qcom,pm-cpu-level@1 { + qcom,pm-cpu-level@1 { /* C2D */ reg = <1>; - qcom,spm-cpu-mode = "retention"; - qcom,latency-us = <35>; - qcom,ss-power = <542>; - qcom,energy-overhead = <34920>; - qcom,time-overhead = <40>; + label = "ret"; + qcom,psci-cpu-mode = <0x2>; + qcom,latency-us = <86>; + qcom,ss-power = <449>; + qcom,energy-overhead = <78456>; + qcom,time-overhead = <167>; }; - qcom,pm-cpu-level@2 { + qcom,pm-cpu-level@2 { /* C3 */ reg = <2>; - qcom,spm-cpu-mode = "standalone_pc"; - qcom,latency-us = <300>; - qcom,ss-power = <476>; - qcom,energy-overhead = <225300>; - qcom,time-overhead = <350>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <612>; + qcom,ss-power = <436>; + qcom,energy-overhead = <418225>; + qcom,time-overhead = <885>; + qcom,is-reset; }; - qcom,pm-cpu-level@3 { + qcom,pm-cpu-level@3 { /* C4 */ reg = <3>; - qcom,spm-cpu-mode = "pc"; - qcom,latency-us = <500>; - qcom,ss-power = <163>; - qcom,energy-overhead = <577736>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <700>; + qcom,ss-power = <400>; + qcom,energy-overhead = <428225>; qcom,time-overhead = <1000>; + qcom,is-reset; }; }; - }; - - qcom,pm-cluster@1{ - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - label = "a57"; - qcom,spm-device-names = "l2"; - qcom,default-level=<0>; - qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; - - qcom,pm-cluster-level@0{ - reg = <0>; - label = "a57-l2-retention"; - qcom,spm-l2-mode = "retention"; - qcom,latency-us = <100>; - qcom,ss-power = <1000>; - qcom,energy-overhead = <300000>; - qcom,time-overhead = <100>; - }; - - qcom,pm-cluster-level@2{ - reg = <1>; - label = "a57-l2-pc"; - qcom,spm-l2-mode = "pc"; - qcom,latency-us = <30000>; - qcom,ss-power = <83>; - qcom,energy-overhead = <2274420>; - qcom,time-overhead = <6605>; - qcom,min-child-idx = <3>; - }; - qcom,pm-cpu { + qcom,pm-cpu@1 { #address-cells = <1>; #size-cells = <0>; - qcom,pm-cpu-level@0 { + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ reg = <0>; - qcom,spm-cpu-mode = "wfi"; - qcom,latency-us = <1>; - qcom,ss-power = <715>; - qcom,energy-overhead = <17700>; - qcom,time-overhead = <2>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <43>; + qcom,ss-power = <454>; + qcom,energy-overhead = <38639>; + qcom,time-overhead = <83>; }; - qcom,pm-cpu-level@1 { + qcom,pm-cpu-level@1 { /* C2D */ reg = <1>; - qcom,spm-cpu-mode = "retention"; - qcom,latency-us = <35>; - qcom,ss-power = <542>; - qcom,energy-overhead = <34920>; - qcom,time-overhead = <40>; + label = "ret"; + qcom,psci-cpu-mode = <0x2>; + qcom,latency-us = <86>; + qcom,ss-power = <449>; + qcom,energy-overhead = <78456>; + qcom,time-overhead = <167>; }; - qcom,pm-cpu-level@2 { + qcom,pm-cpu-level@2 { /* C3 */ reg = <2>; - qcom,spm-cpu-mode = "standalone_pc"; - qcom,latency-us = <300>; - qcom,ss-power = <476>; - qcom,energy-overhead = <225300>; - qcom,time-overhead = <350>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <612>; + qcom,ss-power = <436>; + qcom,energy-overhead = <418225>; + qcom,time-overhead = <885>; + qcom,is-reset; }; - qcom,pm-cpu-level@3 { + qcom,pm-cpu-level@3 { /* C4 */ reg = <3>; - qcom,spm-cpu-mode = "pc"; - qcom,latency-us = <500>; - qcom,ss-power = <163>; - qcom,energy-overhead = <577736>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <700>; + qcom,ss-power = <400>; + qcom,energy-overhead = <428225>; qcom,time-overhead = <1000>; + qcom,is-reset; }; }; }; }; - - -}; diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt index a6537ebd2512cb743f1f4bc11fdb452256c4b2e5..30961bedd82fb810a1d2880728b69d60eb48c61c 100644 --- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt +++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt @@ -7,7 +7,7 @@ to be reset. Required Properties: - compatible: The bus devices need to be compatible with "qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom, ext-mdm9x45", - "qcom,ext-mdm9x55". + "qcom,ext-mdm9x55", "qcom,ext-sdxpoorwills". Required named gpio properties: - qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor @@ -110,6 +110,10 @@ Optional driver parameters: on behalf of the subsystem driver. - qcom,mdm-link-info: a string indicating additional info about the physical link. For example: "devID_domain.bus.slot" in case of PCIe. +- qcom,mdm-auto-boot: Boolean. To indicate this instance of esoc boots independently. +- qcom,mdm-statusline-not-a-powersource: Boolean. If set, status line to esoc device is not a + power source. +- qcom,mdm-userspace-handle-shutdown: Boolean. If set, userspace handles shutdown requests. Example: mdm0: qcom,mdm0 { diff --git a/Documentation/devicetree/bindings/arm/msm/msm-id.txt b/Documentation/devicetree/bindings/arm/msm/msm-id.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2431541a144ac8097796d378d35a0e9fc0524bc --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/msm-id.txt @@ -0,0 +1,33 @@ +* MSM-ID + +The qcom,msm-id entry specifies the MSM chipset, platform, hardware revision +and optional manufactured foundry. It can optionally be an array of these to +indicate multiple hardware that use the same device tree. It is expected that +the bootloader will use this information at boot-up to decide which device tree +to use when given multiple device trees, some of which may not be compatible +with the actual hardware. It is the bootloader's responsibility to pass the +correct device tree to the kernel. + +Format: + +It is expected that the qcom,msm-id entry be at the top level of the device +tree structure. The format can take one of the two forms below: + + qcom,msm-id = [, ...] + qcom,msm-id = [, ...] + +If the second format is used one must also define the board-id. + +The "chipset_foundry_id" consists of three fields as below: + + bits 0-15 = The unique MSM chipset id. + bits 16-23 = The optional foundry id. If bootloader doesn't find a device + tree which has exact matching foundry-id with hardware it + chooses the device tree with foundry-id = 0. + bits 24-31 = Reserved. + +Example: + qcom,msm-id = <0x1007e 15 0>; + + qcom,board-id= <15 2>; + qcom,msm-id = <0x1007e 0>; diff --git a/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt b/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt new file mode 100644 index 0000000000000000000000000000000000000000..28f6e7d4b073206044436a02a98542ced6cd4903 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt @@ -0,0 +1,63 @@ +Msm Machine Name + +Machine name is used to: + 1. show up in the beginning of kernel message. + Example: + [ 0.000000] Machine: Qualcomm Technologies, Inc. MSM8953 PMI8950 MTP + 2. show up as arch description when do dump stack. + Example: + [ 1.222319] WARNING: CPU: 2 PID: 1 at kernel/lib/debugobjects.c:263 debug_print_object+0xa8/0xb0 + [ 1.222334] Modules linked in: + [ 1.222362] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.9.65+ #71 + [ 1.222376] Hardware name: Qualcomm Technologies, Inc. MSM8953 PMI8950 MTP (DT) + [ 1.222392] task: ffffffc0ed1b0080 task.stack: ffffffc0ed1b8000 + [ 1.222408] PC is at debug_print_object+0xa8/0xb0 + [ 1.222424] LR is at debug_print_object+0xa8/0xb0 + +Msm machine name is a string concatenated from: + 1. constant string contain msm information: "Qualcomm Technologies, Inc.". + 2. string of device tree property "qcom,msm-name". + 3. string of device tree property "qcom,pmic-name". + 4. string of device tree property "model". + +The reason for using msm machine Name is single board overlay device tree +may applied to multiple soc device trees. The "model" property in soc device +tree is overwritten with board overlay device tree. So the final string in +"model" property can only contain Board information. And "qcom,msm-name" +and "qcom,pmic-name" property is introduced. + +Optional properties: +- qcom,msm-name: The name string of MSM SoC chip +- qcom,pmic-name: The name string of MSM Pmic chip + +Required properties: +- model: in soc device tree + Contain the soc and pmic information. + Will be overwritten by model string in board overlay device tree. + It will be used in bootloader for debug purpose. +- model: in board overlay device tree + Contain the board information. It is the final model string that + kernel can see. + +Note: +When device tree property qcom,msm-name and qcom,pmic-name exist, it will +use concatenated msm machine name string for final machine name. +When device tree property qcom,msm-name and qcom,pmic-name doesn't exist, +it will use model property string for final machine name. + +Example: +* In soc device tree: + / { + model = "Qualcomm Technologies, Inc. APQ 8953 + PMI8950 SOC"; + compatible = "qcom,apq8053"; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; + qcom,pmic-name = "PMI8950"; + qcom,msm-id = <293 0x0>; + qcom,msm-name = "APQ8053"; + }; +* In board overlay device tree: + / { + model = "MTP"; + compatible = "qcom,mtp"; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index bf93a2ab429bb4e96b97c87dfbd97470aa4ce660..9bc81683a87f05139e9e9f65d5df3f38e0ef2300 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -89,8 +89,14 @@ SoCs: - SDM845 compatible = "qcom,sdm845" -- SDM830 - compatible = "qcom,sdm830" +- SDM670 + compatible = "qcom,sdm670" + +- QCS605 + compatible = "qcom,qcs605" + +- SDA670 + compatible = "qcom,sda670" - MSM8952 compatible = "qcom,msm8952" @@ -101,6 +107,15 @@ SoCs: - MSM8953 compatible = "qcom,msm8953" +- SDM450 + compatible = "qcom,sdm450" + +- SDM632 + compatible = "qcom,sdm632" + +- SDA632 + compatible = "qcom,sda632" + - MSM8937 compatible = "qcom,msm8937" @@ -157,7 +172,14 @@ Generic board variants: - RUMI device: compatible = "qcom,rumi" +- VR device: + compatible = "qcom,qvr" + +- HDK device: + compatible = "qcom,hdk" +- IPC device: + compatible = "qcom,ipc" Boards (SoC type + board variant): @@ -188,6 +210,7 @@ compatible = "qcom,apq8017-cdp" compatible = "qcom,apq8017-mtp" compatible = "qcom,apq8053-cdp" compatible = "qcom,apq8053-mtp" +compatible = "qcom,apq8053-ipc" compatible = "qcom,mdm9630-cdp" compatible = "qcom,mdm9630-mtp" compatible = "qcom,mdm9630-sim" @@ -267,10 +290,19 @@ compatible = "qcom,sdm845-cdp" compatible = "qcom,sdm845-mtp" compatible = "qcom,sdm845-mtp" compatible = "qcom,sdm845-qrd" -compatible = "qcom,sdm830-sim" -compatible = "qcom,sdm830-rumi" -compatible = "qcom,sdm830-cdp" -compatible = "qcom,sdm830-mtp" +compatible = "qcom,sdm845-qvr" +compatible = "qcom,sda845-cdp" +compatible = "qcom,sda845-mtp" +compatible = "qcom,sda845-qrd" +compatible = "qcom,sda845-hdk" +compatible = "qcom,sdm670-rumi" +compatible = "qcom,sdm670-cdp" +compatible = "qcom,sdm670-mtp" +compatible = "qcom,sdm670-qrd" +compatible = "qcom,qcs605-cdp" +compatible = "qcom,qcs605-mtp" +compatible = "qcom,sda670-cdp" +compatible = "qcom,sda670-mtp" compatible = "qcom,msm8952-rumi" compatible = "qcom,msm8952-sim" compatible = "qcom,msm8952-qrd" @@ -289,8 +321,13 @@ compatible = "qcom,msm8953-rumi" compatible = "qcom,msm8953-sim" compatible = "qcom,msm8953-cdp" compatible = "qcom,msm8953-mtp" +compatible = "qcom,msm8953-ipc" compatible = "qcom,msm8953-qrd" compatible = "qcom,msm8953-qrd-sku3" +compatible = "qcom,sdm450-mtp" +compatible = "qcom,sdm450-cdp" +compatible = "qcom,sdm450-qrd" +compatible = "qcom,sdm632-rumi" compatible = "qcom,mdm9640-cdp" compatible = "qcom,mdm9640-mtp" compatible = "qcom,mdm9640-rumi" @@ -306,3 +343,5 @@ compatible = "qcom,mdmcalifornium-mtp" compatible = "qcom,apq8009-cdp" compatible = "qcom,apq8009-mtp" compatible = "qcom,sdxpoorwills-rumi" +compatible = "qcom,sdxpoorwills-mtp" +compatible = "qcom,sdxpoorwills-cdp" diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt index b3f3431adcc39a22ebed4a514317ecf8ad2a0fa4..0d955eda2fd0616a3a71e98733811044099caae9 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt @@ -139,6 +139,7 @@ qcom,bcm-name: The name used to fetch details about the bcm device from the command DB driver. qcom,drv-id: The DRV id associated with the RSC, used to differentiate between RSCS owned by different execution environments. +qcom,defer-init-qos: Flag to force defer initial QoS configuration at probe time. Example: diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt index 6bf6a57ca62983f84193f45596f9bb7a862cdfe2..8aeaf774e48e47e88b9f5f5a3bbac49350dab6e7 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt @@ -121,6 +121,20 @@ qcom,blacklist: An array of phandles that represent devices that this de cannot connect to either directly or via any number of intermediate nodes. qcom,agg-ports: The number of aggregation ports on the bus. +qcom,node-qos-bcms: Optional property to target specific BCMs to toggle during QoS configuration, + this is to ensure QoS register space is clocked and accessible. Array is + defined as follows: BCM node ID, VoteX, VoteY. The vectors must be defined in + sets of the three values aforementioned. +qcom,prio: Default fixed priority for bus master. +qcom,qos-lim-params: Array containing QoS limiter configurations defined as: Bandwidth, Saturation. + Must define "qcom,qos-lim-en" for these settings to take effect. +qcom,qos-lim-en: Boolean to enable limiter settings, default is disabled. +qcom,qos-reg-params: Array containing QoS regulator configurations defined as: Low Priority, High + Priority, Bandwidth, Saturation. Must define "qcom,qos-reg-regmode" for these + settings to take effect. +qcom,qos-reg-mode: Array containing QoS regulator mode enablement: Read Enable, Write Enable, + default is disabled. +qcom,forwarding: Boolean indicate Urgent Forwarding enablement. The following properties are optional as collecting data via coresight might and are present on child nodes that represent NOC devices. The documentation @@ -172,6 +186,12 @@ Example: <&clock_gcc clk_q1_clk>; q0-clk-supply = <&gdsc_q0_clk>; }; + qcom,node-qos-bcms = <0x7011 0 1>; + qcom,prio = 1; + qcom,qos-lim-params = <1000 1000>; + qcom,qos-lim-en: + qcom,qos-reg-params = <1 2 1000 1000>; + qcom,qos-reg-mode = <1 1>; }; mm_int_bimc: mm-int-bimc { diff --git a/Documentation/devicetree/bindings/arm/msm/msm_core.txt b/Documentation/devicetree/bindings/arm/msm/msm_core.txt deleted file mode 100644 index f3859157a26fbdc760da4d3c7f0e1deb31001e68..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/arm/msm/msm_core.txt +++ /dev/null @@ -1,71 +0,0 @@ -MSM Core Energy Aware driver - -The Energy Aware driver provides per core power and temperature -information to the scheduler for it to make more power efficient -scheduling decision. - -The required properties for the Energy-aware driver are: - -- compatible: "qcom,apss-core-ea" -- reg: Physical address mapped to this device - -Required nodes: -- ea@X: Parent node that has the sensor mapping for each cpu. - This node's phandle is provided within cpu node - to invoke/probe energy-aware only for available cpus. - There should be one such node present for each cpu. - -Optional properties: -- qcom,low-hyst-temp: Degrees C below which the power numbers - need to be recomputed for the cores and reset - the threshold. If this is not present, the default - value is 10C. -- qcom,high-hyst-temp: Degrees C above which the power numbers - need to be recomputed for the cores and reset - the threshold. If this property is not present, - the default value is 5C. -- qcom,polling-interval: Interval for which the power numbers - need to be recomputed for the cores if there - is no change in threshold. If this property is not - present, the power is recalculated only on - temperature threshold notifications. --qcom,throttling-temp: Temperature threshold for cpu frequency mitigation. - The value should be set same as the threshold temperature - in thermal module - 5 C, such that there is a bandwidth to - control the cores before frequency mitigation happens. - -[Second level nodes] -Require properties to define per core characteristics: -- sensor: Sensor phandle to map a particular sensor to the core. - If this property is not present, then the core is assumed - to be at 40C for all the power estimations. No sensor - threshold is set. This phandle's compatible property is - "qcom,sensor-information". This driver relies on the - sensor-type and scaling-factor information provided in this - phandle. - -Example - -qcom,msm-core@0xfc4b0000 { - compatible = "qcom,apss-core-ea"; - reg = <0xfc4b0000 0x1000>; - qcom,low-hyst-temp = <10>; - qcom,high-hyst-temp = <5>; - qcom,polling-interval = <50>; - - ea0: ea0 { - sensor = <&sensor_information0>; - }; - - ea1: ea1 { - sensor = <&sensor_information1>; - }; - -}; - -CPU0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a53"; - reg = <0x0>; - qcom,ea = <&ea0>; -}; diff --git a/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt b/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt index 9e1d230432cff1eee626956eb4725f9c37da6772..c5d052cd603997605516e0542579a9c737f44a60 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt @@ -17,6 +17,8 @@ Optional properties: by pil. Absence of this property indicates that subsystem loading through pil voting is disabled for that subsystem. +-qcom,dynamic-wakeup-source: Boolean property to indicate that G-Link + transport supports dynamic wakeup source Example: qcom,ipc_router_modem_xprt { diff --git a/Documentation/devicetree/bindings/arm/msm/msm_memory_dump.txt b/Documentation/devicetree/bindings/arm/msm/msm_memory_dump.txt new file mode 100644 index 0000000000000000000000000000000000000000..a415c8fbe81ac71d8acfcc354194f1d0203c64d1 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/msm_memory_dump.txt @@ -0,0 +1,31 @@ +Qualcomm Technologies Inc. memory dump driver + +QTI memory dump driver allows various client subsystems to register and allocate respective +dump regions. At the time of deadlocks or cpu hangs these dump regions +are captured to give a snapshot of the system at the time of the crash. + +Required properties: + +-compatible: "qcom,mem-dump" +-memory-region: phandle to the CMA region. The size of the CMA region + should be greater than sum of size of all child nodes + to account for padding. + +If any child nodes exist the following property are required: + +-qcom,dump-size: The size of memory that needs to be allocated for the + particular node. +-qcom,dump-id: The ID within the data dump table where this entry needs + to be added. + +Example: + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh_dump { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xEC>; + }; + }; diff --git a/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt index 0a5c0b300e1a14af59cd99363a4f08d91647476f..5fb3e65cb321f80a6c073728af6f21cccdab7a41 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt @@ -13,6 +13,7 @@ Required properties: - qcom,irq-mask : the bitmask to trigger an interrupt. - interrupt : the receiving interrupt line. - mbox-desc-offset : offset of mailbox descriptor from start of the msgram. +- priority : the priority of this mailbox compared to other mailboxes. - #mbox-cells: Common mailbox binding property to identify the number of cells required for the mailbox specifier, should be 1. @@ -33,6 +34,7 @@ Example: qcom,irq-mask = <0x1>; interrupt = <0 389 1>; mbox-desc-offset = <0x100>; + priority = <1>; mbox-offset = <0x500>; mbox-size = <0x400>; #mbox-cells = <1>; diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt index 50488b43dc304171876b3b7eeb1f6ce9adf3b805..90bc36823a8312373d49f8e5065166b7270be073 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -31,6 +31,9 @@ Reports single and double bit errors in the data and tag ram of LLCC. 4. LLCC AMON Driver: Keeps track of the data progress within the internal channels of LLCC. +5. LLCC Performance Monitor +Used to monitor the events of LLCC sub blocks. + == llcc device == Require Properties: @@ -81,6 +84,10 @@ Optional Properties: -qcom,fg-cnt : The value of fine grained counter of activity monitor block. +compatible devices: + qcom,sdm845-llcc, + qcom,sdm670-llcc + Example: qcom,llcc@01300000 { @@ -103,6 +110,10 @@ Example: compatible = "qcom,llcc-amon"; qcom,fg-cnt = <0x7>; }; + + qcom,llcc-perfmon { + compatible = "qcom,llcc-perfmon"; + }; }; == Client == diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt index 23474774581bd94999b523360cfbb507d2d1b992..64154590e34acaeebd9c508b6fb80838756b1a16 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt @@ -9,324 +9,44 @@ Properties: - compatible Usage: required Value type: - Definition: must be "qcom,clk-cpu-osm". + Definition: must be "qcom,clk-cpu-osm", "qcom,clk-cpu-osm-v2" or + "qcom,clk-cpu-osm-sdm670". - reg Usage: required Value type: - Definition: Addresses and sizes for the memory of the OSM controller, - cluster PLL management, and APCS common register regions. - Optionally, the address of the efuse registers used to - determine the pwrcl or perfcl speed-bins and/or the ACD - register space to initialize prior to enabling OSM. + Definition: Addresses and sizes for the memory of the OSM controller. - reg-names Usage: required Value type: Definition: Address names. Must be "osm_l3_base", "osm_pwrcl_base", - "osm_perfcl_base", "l3_pll", "pwrcl_pll", "perfcl_pll", - "l3_sequencer", "pwrcl_sequencer", "perfcl_sequencer". - Optionally, "l3_efuse", "pwrcl_efuse", "perfcl_efuse". + "osm_perfcl_base". Must be specified in the same order as the corresponding addresses are specified in the reg property. -- vdd-l3-supply - Usage: required - Value type: - Definition: phandle of the underlying regulator device that manages - the voltage supply of the L3 cluster. +- qcom,mx-turbo-freq + Usage: optional + Value type: + Definition: List of frequencies for the 3 clock domains (following the + order of L3, power, and performance clusters) that denote + the lowest rate that requires a TURBO vote on the MX rail. -- vdd-pwrcl-supply - Usage: required +- vdd_l3_mx_ao-supply + Usage: required if qcom,mx-turbo-freq is specified Value type: - Definition: phandle of the underlying regulator device that manages - the voltage supply of the Power cluster. + Definition: Phandle to the MX active-only regulator device. -- vdd-perfcl-supply - Usage: required +- vdd_pwrcl_mx_ao-supply + Usage: required if qcom,mx-turbo-freq is specified Value type: - Definition: phandle of the underlying regulator device that manages - the voltage supply of the Performance cluster. - -- interrupts - Usage: required - Value type: - Definition: OSM interrupt specifier. - -- interrupt-names - Usage: required - Value type: - Definition: Interrupt names. this list must match up 1-to-1 with the - interrupts specified in the 'interrupts' property. - "pwrcl-irq" and "perfcl-irq" must be specified. - -- qcom,l3-speedbinX-v0 - Usage: required - Value type: - Definition: Array which defines the frequency in Hertz, frequency, - PLL override data, ACC level, and virtual corner used - by the OSM hardware for each supported DCVS setpoint - of the L3 cluster. - -- qcom,pwrcl-speedbinX-v0 - Usage: required - Value type: - Definition: Array which defines the frequency in Hertz, frequency, - PLL override data, ACC level, and virtual corner used - by the OSM hardware for each supported DCVS setpoint - of the Power cluster. - -- qcom,perfcl-speedbinX-v0 - Usage: required - Value type: - Definition: Array which defines the frequency in Hertz, frequency, - PLL override data, ACC level and virtual corner used - by the OSM hardware for each supported DCVS setpoint - of the Performance cluster. - -- qcom,l3-min-cpr-vc-binX - Usage: required - Value type: - Definition: First virtual corner which does not use PLL post-divider - for the L3 clock domain. - -- qcom,pwrcl-min-cpr-vc-binX - Usage: required - Value type: - Definition: First virtual corner which does not use PLL post-divider - for the power cluster. - -- qcom,perfcl-min-cpr-vc-binX - Usage: required - Value type: - Definition: First virtual corner which does not use PLL post-divider - for the performance cluster. - -- qcom,osm-no-tz - Usage: optional - Value type: - Definition: Boolean flag which indicates that there is no programming - of the OSM hardware performed by the secure world. - -- qcom,osm-pll-setup - Usage: optional - Value type: - Definition: Boolean flag which indicates that the PLL setup sequence - must be executed for each clock domain managed by the OSM - controller. - -- qcom,up-timer - Usage: optional - Value type: - Definition: Array which defines the DCVS up timer value in nanoseconds - for each of the three clock domains managed by the OSM - controller. - -- qcom,down-timer - Usage: optional - Value type: - Definition: Array which defines the DCVS down timer value in nanoseconds - for each of the three clock domains managed by the OSM - controller. - -- qcom,pc-override-index - Usage: optional - Value type: - Definition: Array which defines the OSM performance index to be used - when each cluster enters certain low power modes. - -- qcom,set-ret-inactive - Usage: optional - Value type: - Definition: Boolean flag which indicates if domains in retention must - be treated as inactive. - -- qcom,enable-llm-freq-vote - Usage: optional - Value type: - Definition: Boolean flag which indicates if Limits hardware frequency - votes must be honored by OSM. - -- qcom,llm-freq-up-timer - Usage: optional - Value type: - Definition: Array which defines the LLM frequency up timer value in - nanoseconds for each of the three clock domains managed by - the OSM controller. - -- qcom,llm-freq-down-timer - Usage: optional - Value type: - Definition: Array which defines the LLM frequency down timer value in - nanoseconds for each of the three clock domains managed by - the OSM controller. - -- qcom,enable-llm-volt-vote - Usage: optional - Value type: - Definition: Boolean flag which indicates if Limits hardware voltage - votes must be honored by OSM. - -- qcom,llm-volt-up-timer - Usage: optional - Value type: - Definition: Array which defines the LLM voltage up timer value in - nanoseconds for each of the three clock domains managed by - the OSM controller. - -- qcom,llm-volt-down-timer - Usage: optional - Value type: - Definition: Array which defines the LLM voltage down timer value in - nanoseconds for each of the three clock domains managed by - the OSM controller. + Definition: Phandle to the MX active-only regulator device. -- qcom,cc-reads - Usage: optional - Value type: - Definition: Defines the number of times the cycle counters must be - read to determine the performance level of each clock - domain. - -- qcom,l-val-base - Usage: required - Value type: - Definition: Array which defines the register addresses of the L_VAL - control register for each of the three clock domains - managed by the OSM controller. - -- qcom,apcs-pll-user-ctl - Usage: required - Value type: - Definition: Array which defines the register addresses of the PLL - user control register for each of the three clock domains - managed by the OSM controller. - -- qcom,perfcl-apcs-apm-threshold-voltage - Usage: required - Value type: - Definition: Specifies the APM threshold voltage in microvolts. If the - VDD_APCC supply voltage is above or at this level, then the - APM is switched to use VDD_APCC. If VDD_APCC is below - this level, then the APM is switched to use VDD_MX. - -- qcom,apm-mode-ctl - Usage: required - Value type: - Definition: Array which defines the register addresses of the APM - control register for each of the two clusters managed - by the OSM controller. - -- qcom,apm-status-ctrl - Usage: required - Value type: - Definition: Array which defines the register addresses of the APM - controller status register for each of the three clock - domains managed by the OSM controller. - -- qcom,perfcl-isense-addr - Usage: required - Value type: - Definition: Contains the ISENSE register address. - -- qcom,l3-mem-acc-addr - Usage: required if qcom,osm-no-tz is specified - Value type: - Definition: Array which defines the addresses of the mem-acc - configuration registers for the L3 cluster. - The array must contain exactly three elements. - -- qcom,pwrcl-mem-acc-addr - Usage: required if qcom,osm-no-tz is specified - Value type: - Definition: Array which defines the addresses of the mem-acc - configuration registers for the Power cluster. - The array must contain exactly three elements. - -- qcom,perfcl-mem-acc-addr - Usage: required if qcom,osm-no-tz is specified - Value type: - Definition: Array which defines the addresses of the mem-acc - configuration registers for the Performance cluster. - The array must contain exactly three elements. - - corresponding CPRh device. - -- qcom,perfcl-apcs-mem-acc-threshold-voltage - Usage: optional - Value type: - Definition: Specifies the highest MEM ACC threshold voltage in - microvolts for the Performance cluster. This voltage is - used to determine which MEM ACC setting is used for the - highest frequencies. If specified, the voltage must match - the MEM ACC threshold voltage specified for the - corresponding CPRh device. - -- qcom,apcs-cbc-addr - Usage: required - Value type: - Definition: Array which defines the addresses of the APCS_CBC_ADDR - registers for all three clock domains. - -- qcom,apcs-ramp-ctl-addr - Usage: required - Value type: - Definition: Array which defines the addresses of the APCS_RAMP_CTL_ADDR - registers for all three clock domains. - -- qcom,red-fsm-en - Usage: optional - Value type: - Definition: Boolean flag which indicates if the reduction FSM - should be enabled. - -- qcom,boost-fsm-en - Usage: optional - Value type: - Definition: Boolean flag which indicates if the boost FSM should - be enabled. - -- qcom,safe-fsm-en - Usage: optional - Value type: - Definition: Boolean flag which indicates if the safe FSM should - be enabled. - -- qcom,ps-fsm-en - Usage: optional - Value type: - Definition: Boolean flag which indicates if the PS FSM should be - enabled. - -- qcom,droop-fsm-en - Usage: optional - Value type: - Definition: Boolean flag which indicates if the droop FSM should - be enabled. - -- qcom,set-c3-active - Usage: optional - Value type: - Definition: Boolean flag which indicates if the cores in C3 are to - be treated as active for core count calculations. - -- qcom,set-c2-active - Usage: optional - Value type: - Definition: Boolean flag which indicates if the cores in C2 are to - be treated as active for core count calculations. - -- qcom,disable-cc-dvcs - Usage: optional - Value type: - Definition: Boolean flag which indicates if core count based DCVS is - to be disabled. - -- qcom,apcs-pll-min-freq - Usage: required - Value type: - Definition: Contains the addresses of the RAILx_CLKDOMy_PLL_MIN_FREQ - registers for the three clock domains. +- l3-devs + Usage: optional + Value type: + Definition: List of phandles to devices that the OPP tables with the L3 + frequency and voltage mappings are loaded for. - clock-names Usage: required @@ -343,132 +63,15 @@ Example: compatible = "qcom,clk-cpu-osm"; reg = <0x17d41000 0x1400>, <0x17d43000 0x1400>, - <0x17d45800 0x1400>, - <0x178d0000 0x1000>, - <0x178c0000 0x1000>, - <0x178b0000 0x1000>, - <0x17d42400 0x0c00>, - <0x17d44400 0x0c00>, - <0x17d46c00 0x0c00>; - reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base", - "l3_pll", "pwrcl_pll", "perfcl_pll", - "l3_sequencer", "pwrcl_sequencer", - "perfcl_sequencer"; - - vdd-l3-supply = <&apc0_l3_vreg>; - vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; - vdd-perfcl-supply = <&apc1_perfcl_vreg>; - - qcom,l3-speedbin0-v0 = - < 300000000 0x000c000f 0x00002020 0x1 1 >, - < 422400000 0x50140116 0x00002020 0x1 2 >, - < 499200000 0x5014021a 0x00002020 0x1 3 >, - < 576000000 0x5014031e 0x00002020 0x1 4 >, - < 652800000 0x501c0422 0x00002020 0x1 5 >, - < 729600000 0x501c0526 0x00002020 0x1 6 >, - < 806400000 0x501c062a 0x00002222 0x1 7 >, - < 883200000 0x4024072b 0x00002525 0x1 8 >, - < 960000000 0x40240832 0x00002828 0x2 9 >; - - qcom,pwrcl-speedbin0-v0 = - < 300000000 0x000c000f 0x00002020 0x1 1 >, - < 422400000 0x50140116 0x00002020 0x1 2 >, - < 499200000 0x5014021a 0x00002020 0x1 3 >, - < 576000000 0x5014031e 0x00002020 0x1 4 >, - < 652800000 0x501c0422 0x00002020 0x1 5 >, - < 748800000 0x501c0527 0x00002020 0x1 6 >, - < 825600000 0x401c062b 0x00002222 0x1 7 >, - < 902400000 0x4024072f 0x00002626 0x1 8 >, - < 979200000 0x40240833 0x00002929 0x1 9 >, - < 1056000000 0x402c0937 0x00002c2c 0x1 10 >, - < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >, - < 1209600000 0x402c0b3f 0x00003333 0x1 12 >, - < 1286400000 0x40340c43 0x00003636 0x1 13 >, - < 1363200000 0x40340d47 0x00003939 0x1 14 >, - < 1440000000 0x403c0e4b 0x00003c3c 0x1 15 >, - < 1516800000 0x403c0f4f 0x00004040 0x2 16 >, - < 1593600000 0x403c1053 0x00004343 0x2 17 >; - - qcom,perfcl-speedbin0-v0 = - < 300000000 0x000c000f 0x00002020 0x1 1 >, - < 422400000 0x50140116 0x00002020 0x1 2 >, - < 499200000 0x5014021a 0x00002020 0x1 3 >, - < 576000000 0x5014031e 0x00002020 0x1 4 >, - < 652800000 0x501c0422 0x00002020 0x1 5 >, - < 729600000 0x501c0526 0x00002020 0x1 6 >, - < 806400000 0x501c062a 0x00002222 0x1 7 >, - < 883200000 0x4024072b 0x00002525 0x1 8 >, - < 960000000 0x40240832 0x00002828 0x1 9 >, - < 1036800000 0x40240936 0x00002b2b 0x1 10 >, - < 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >, - < 1190400000 0x402c0b3e 0x00003232 0x1 12 >, - < 1267200000 0x40340c42 0x00003535 0x1 13 >, - < 1344000000 0x40340d46 0x00003838 0x1 14 >, - < 1420800000 0x40340e4a 0x00003b3b 0x1 15 >, - < 1497600000 0x403c0f4e 0x00003e3e 0x1 16 >, - < 1574400000 0x403c1052 0x00004242 0x2 17 >, - < 1651200000 0x403c1156 0x00004545 0x2 18 >, - < 1728000000 0x4044125a 0x00004848 0x2 19 >, - < 1804800000 0x4044135e 0x00004b4b 0x2 20 >, - < 1881600000 0x404c1462 0x00004e4e 0x2 21 >, - < 1958400000 0x404c1566 0x00005252 0x3 22 >; - - qcom,l3-min-cpr-vc-bin0 = <7>; - qcom,pwrcl-min-cpr-vc-bin0 = <6>; - qcom,perfcl-min-cpr-vc-bin0 = <7>; - - qcom,up-timer = - <1000 1000 1000>; - qcom,down-timer = - <100000 100000 100000>; - qcom,pc-override-index = - <0 0 0>; - qcom,set-ret-inactive; - qcom,enable-llm-freq-vote; - qcom,llm-freq-up-timer = - <1000 1000 1000>; - qcom,llm-freq-down-timer = - <327675 327675 327675>; - qcom,enable-llm-volt-vote; - qcom,llm-volt-up-timer = - <1000 1000 1000>; - qcom,llm-volt-down-timer = - <327675 327675 327675>; - qcom,cc-reads = <10>; - qcom,cc-delay = <5>; - qcom,cc-factor = <100>; - qcom,osm-clk-rate = <100000000>; - qcom,xo-clk-rate = <19200000>; - - qcom,l-val-base = - <0x178d0004 0x178c0004 0x178b0004>; - qcom,apcs-pll-user-ctl = - <0x178d000c 0x178c000c 0x178b000c>; - qcom,apcs-pll-min-freq = - <0x17d41094 0x17d43094 0x17d45894>; - qcom,apm-mode-ctl = - <0x0 0x0 0x17d20010>; - qcom,apm-status-ctrl = - <0x0 0x0 0x17d20000>; - qcom,perfcl-isense-addr = <0x17871480>; - qcom,l3-mem-acc-addr = <0x17990170 0x17990170 0x17990170>; - qcom,pwrcl-mem-acc-addr = <0x17990160 0x17990164 0x17990164>; - qcom,perfcl-mem-acc-addr = <0x17990168 0x1799016c 0x1799016c>; - qcom,cfg-gfmux-addr =<0x178d0084 0x178c0084 0x178b0084>; - qcom,apcs-cbc-addr = <0x178d008c 0x178c008c 0x178b008c>; - qcom,apcs-ramp-ctl-addr = <0x17840904 0x17840904 0x17830904>; + <0x17d45800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base"; + vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>; + vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>; - qcom,perfcl-apcs-apm-threshold-voltage = <800000>; - qcom,perfcl-apcs-mem-acc-threshold-voltage = <852000>; - qcom,boost-fsm-en; - qcom,safe-fsm-en; - qcom,ps-fsm-en; - qcom,droop-fsm-en; - qcom,osm-no-tz; - qcom,osm-pll-setup; + qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>; + l3-devs = <&l3_cpu0 &l3_cpu4 &l3_cdsp>; clock-names = "xo_ao"; clocks = <&clock_rpmh RPMH_CXO_CLK_A>; #clock-cells = <1>; - #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/arm/msm/qdss_mhi.txt b/Documentation/devicetree/bindings/arm/msm/qdss_mhi.txt new file mode 100644 index 0000000000000000000000000000000000000000..928a4f4269a3f718621500dfd77e829554e86c4d --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qdss_mhi.txt @@ -0,0 +1,15 @@ +Qualcomm Technologies, Inc. QDSS bridge Driver + +This device will enable routing debug data from modem +subsystem to APSS host. + +Required properties: +-compatible : "qcom,qdss-mhi". +-qcom,mhi : phandle of MHI Device to connect to. + +Example: + qcom,qdss-mhi { + compatible = "qcom,qdss-mhi"; + qcom,mhi = <&mhi_0>; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/qmp-debugfs-client.txt b/Documentation/devicetree/bindings/arm/msm/qmp-debugfs-client.txt new file mode 100644 index 0000000000000000000000000000000000000000..655bf89559c55e568c86f40af66fe898860ed1b2 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qmp-debugfs-client.txt @@ -0,0 +1,17 @@ +QMP debugfs client: +----------------- + +QTI Messaging Protocol(QMP) debugfs client is an interface for clients to +send data to the Always on processor using QMP. + +Required properties : +- compatible : must be "qcom,debugfs-qmp-client" +- mboxes : list of QMP mailbox phandle and channel identifier tuples. +- mbox-names : names of the listed mboxes + +Example : + qcom,qmp-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; diff --git a/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..442ad52b4bf6e471d2c310db2ce053012b1b8163 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt @@ -0,0 +1,30 @@ +Qualcomm Technologies, Inc. Secure Execution Environment IPC Interrupt Bridge + +[Root level node] +Required properties: +-compatible : should be "qcom,qsee-ipc-irq-bridge"; + +[Second level nodes] +qcom,qsee-ipc-irq-subsystem +Required properties: +-qcom,dev-name: the bridge device name +-interrupt: IPC interrupt line from remote subsystem to QSEE +-label : The name of this subsystem. + +Required properties if interrupt type is IRQ_TYPE_LEVEL_HIGH[4]: +-qcom,rx-irq-clr : the register to clear the level triggered rx interrupt +-qcom,rx-irq-clr-mask : the bitmask to clear the rx interrupt + +Example: + + qcom,qsee_ipc_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,rx-irq-clr = <0x1d08008 0x4>; + qcom,rx-irq-clr-mask = <0x2>; + qcom,dev-name = "qsee_ipc_irq_spss"; + interrupts = <0 349 4>; + label = "spss"; + }; + }; diff --git a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt new file mode 100644 index 0000000000000000000000000000000000000000..1114308f9436dc730357a86f76694a3077e68a73 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt @@ -0,0 +1,20 @@ +Qualcomm Technologies, Inc. Remote Debugger (RDBG) driver + +Required properties: +-compatible : Should be one of + To communicate with adsp + qcom,smp2pgpio_client_rdbg_2_in (inbound) + qcom,smp2pgpio_client_rdbg_2_out (outbound) + To communicate with modem + qcom,smp2pgpio_client_rdbg_1_in (inbound) + qcom,smp2pgpio_client_rdbg_1_out (outbound) + To communicate with cdsp + qcom,smp2pgpio_client_rdbg_5_in (inbound) + qcom,smp2pgpio_client_rdbg_5_out (outbound) +-gpios : the relevant gpio pins of the entry. + +Example: + qcom,smp2pgpio_client_rdbg_2_in { + compatible = "qcom,smp2pgpio_client_rdbg_2_in"; + gpios = <&smp2pgpio_rdbg_2_in 0 0>; + }; diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cba3ecaeb90bf244975b460dc1610dcf8b947fc --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt @@ -0,0 +1,41 @@ +Resource Power Manager(RPM) + +RPM is a dedicated hardware engine for managing shared SoC resources, +which includes buses, clocks, power rails, etc. The goal of RPM is +to achieve the maximum power savings while satisfying the SoC's +operational and performance requirements. RPM accepts resource +requests from multiple RPM masters. It arbitrates and aggregates the +requests, and configures the shared resources. The RPM masters are +the application processor, the modem processor, as well as hardware +accelerators. The RPM driver communicates with the hardware engine using +SMD. + +The devicetree representation of the SPM block should be: + +Required properties + +- compatible: "qcom,rpm-smd" or "qcom,rpm-glink" +- rpm-channel-name: The string corresponding to the channel name of the + peripheral subsystem. Required for both smd and + glink transports. +- rpm-channel-type: The interal SMD edge for this subsystem found in + +- qcom,glink-edge: Logical name of the remote subsystem. This is a required + property when rpm-smd driver using glink as trasport. + +Optional properties +- rpm-standalone: Allow RPM driver to run in standalone mode irrespective of RPM + channel presence. +- reg: Contains the memory address at which rpm messaging format version is + stored. If this field is not present, the target only supports v0 format. + +Example: + + qcom,rpm-smd@68150 { + compatible = "qcom,rpm-smd", "qcom,rpm-glink"; + reg = <0x68150 0x3200>; + qcom,rpm-channel-name = "rpm_requests"; + qcom,rpm-channel-type = 15; /* SMD_APPS_RPM */ + qcom,glink-edge = "rpm"; + } +} diff --git a/Documentation/devicetree/bindings/arm/msm/rpm_master_stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm_master_stats.txt new file mode 100644 index 0000000000000000000000000000000000000000..26a439654ff3b95740ff1caaa824f6464d8ff147 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/rpm_master_stats.txt @@ -0,0 +1,47 @@ +* RPM Stats + +RPM maintains a counter of the masters i.e APPS, MPPS etc +number of times the SoC entered a deeper sleep mode involving +lowering or powering down the backbone rails - Cx and Mx and +the oscillator clock, XO. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,rpm-master-stats". + +- reg: + Usage: required + Value type: + Definition: The address on the RPM RAM from where the stats are read + should be provided as "phys_addr_base". The offset from + which the stats are available should be provided as + "offset_addr". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. + +- qcom,masters: + Usage: required + Value tye: + Defination: Provides the masters list. + +qcom,master-offset: + Usage: required + Value tye: + Defination: Provides the masters list + +EXAMPLE: + +qcom,rpm-master-stats@60150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x60150 0x5000>; + qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt new file mode 100644 index 0000000000000000000000000000000000000000..36e1a69c564fe9bd999062978282ca54db4e0fed --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt @@ -0,0 +1,18 @@ +* RPMH Master Stats + +Differet Subsystems maintains master data in SMEM. +It tells about the individual masters information at any given +time like "system sleep counts", "system sleep last entered at" +and "system sleep accumulated duration" etc. These stats can be +show to the user using the debugfs interface of the kernel. +To achieve this, device tree node has been added. + +The required properties for rpmh-master-stats are: + +- compatible: "qcom,rpmh-master-stats". + +Example: + +qcom,rpmh-master-stats { + compatible = "qcom,rpmh-master-stats"; +}; diff --git a/Documentation/devicetree/bindings/arm/msm/smdpkt.txt b/Documentation/devicetree/bindings/arm/msm/smdpkt.txt new file mode 100644 index 0000000000000000000000000000000000000000..be9084b0e5a2338b13ef9b409de19ae48555c411 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/smdpkt.txt @@ -0,0 +1,43 @@ +Qualcomm Technologies, Inc Shared Memory Packet Driver (smdpkt) + +[Root level node] +Required properties: +-compatible : should be "qcom,smdpkt" + +[Second level nodes] +qcom,smdpkt-port-names +Required properties: +-qcom,smdpkt-remote : the remote subsystem name +-qcom,smdpkt-port-name : the smd channel name +-qcom,smdpkt-dev-name : the smdpkt device name + +Example: + + qcom,smdpkt { + compatible = "qcom,smdpkt"; + + qcom,smdpkt-data5-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA5_CNTL"; + qcom,smdpkt-dev-name = "smdcntl0"; + }; + + qcom,smdpkt-data6-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA6_CNTL"; + qcom,smdpkt-dev-name = "smdcntl1"; + }; + + qcom,smdpkt-cxm-qmi-port-8064 { + qcom,smdpkt-remote = "wcnss"; + qcom,smdpkt-port-name = "CXM_QMI_PORT_8064"; + qcom,smdpkt-dev-name = "smd_cxm_qmi"; + }; + + qcom,smdpkt-loopback { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "LOOPBACK"; + qcom,smdpkt-dev-name = "smd_pkt_loopback"; + }; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/smdtty.txt b/Documentation/devicetree/bindings/arm/msm/smdtty.txt new file mode 100644 index 0000000000000000000000000000000000000000..a445c60dcf68e8d0af69dd940958ea78f547ef63 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/smdtty.txt @@ -0,0 +1,40 @@ +Qualcomm Technologies, Inc Shared Memory TTY Driver (smdtty) + +[Root level node] +Required properties: +-compatible : should be "qcom,smdtty" + +[Second level nodes] +qcom,smdtty-port-names +Required properties: +-qcom,smdtty-remote: the remote subsystem name +-qcom,smdtty-port-name : the smd channel name + +Optional properties: +-qcom,smdtty-dev-name : the smdtty device name + +Required alias: +- The index into TTY subsystem is specified via an alias with the following format + 'smd{n}' where n is the tty device index. + +Example: + aliases { + smd1 = &smdtty_apps_fm; + smd36 = &smdtty_loopback; + }; + + qcom,smdtty { + compatible = "qcom,smdtty"; + + smdtty_apps_fm: qcom,smdtty-apps-fm { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_FM"; + }; + + smdtty_loopback: smdtty-loopback { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "LOOPBACK"; + qcom,smdtty-dev-name = "LOOPBACK_TTY"; + }; + }; + diff --git a/Documentation/devicetree/bindings/arm/msm/wil6210.txt b/Documentation/devicetree/bindings/arm/msm/wil6210.txt index b381bdebdfc981dd45376a9bac7cd38ea6c5acaa..0c75cf64e4d21030b8d01f7e85ed855ab71371e4 100644 --- a/Documentation/devicetree/bindings/arm/msm/wil6210.txt +++ b/Documentation/devicetree/bindings/arm/msm/wil6210.txt @@ -10,6 +10,10 @@ Required properties: - compatible: "qcom,wil6210" - qcom,smmu-support: Boolean flag indicating whether PCIe has SMMU support +- qcom,smmu-s1-en: Boolean flag indicating whether SMMU stage1 should be enabled +- qcom,smmu-fast-map: Boolean flag indicating whether SMMU fast mapping should be enabled +- qcom,smmu-coherent: Boolean flag indicating SMMU dma and page table coherency +- qcom,smmu-mapping: specifies the base address and size of SMMU space - qcom,pcie-parent: phandle for the PCIe root complex to which 11ad card is connected - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for the below optional properties: @@ -28,11 +32,17 @@ Optional properties: - clocks : List of phandle and clock specifier pairs - clock-names : List of clock input name strings sorted in the same order as the clocks property. +- qcom,keep-radio-on-during-sleep: Boolean flag to indicate if to suspend to d3hot + instead of turning off the device Example: wil6210: qcom,wil6210 { compatible = "qcom,wil6210"; qcom,smmu-support; + qcom,smmu-s1-en; + qcom,smmu-fast-map; + qcom,smmu-coherent; + qcom,smmu-mapping = <0x20000000 0xe0000000>; qcom,pcie-parent = <&pcie1>; qcom,wigig-en = <&tlmm 94 0>; qcom,msm-bus,name = "wil6210"; @@ -48,5 +58,6 @@ Example: clocks = <&clock_gcc clk_rf_clk3>, <&clock_gcc clk_rf_clk3_pin>; clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; + qcom,keep-radio-on-during-sleep; }; diff --git a/Documentation/devicetree/bindings/batterydata/batterydata.txt b/Documentation/devicetree/bindings/batterydata/batterydata.txt new file mode 100644 index 0000000000000000000000000000000000000000..884b19cf8cbad13a6fe3bbfb6a5be518343e5032 --- /dev/null +++ b/Documentation/devicetree/bindings/batterydata/batterydata.txt @@ -0,0 +1,268 @@ +Battery Profile Data + +Battery Data is a collection of battery profile data made available to +the QPNP Charger and BMS drivers via device tree. + +qcom,battery-data node required properties: +- qcom,rpull-up-kohm : The vadc pullup resistor's resistance value in kOhms. +- qcom,vref-batt-therm-uv : The vadc voltage used to make readings. + For Qualcomm Technologies, Inc. VADCs, this should be + 1800000uV. + +qcom,battery-data node optional properties: +- qcom,batt-id-range-pct : The area of variation between upper and lower bound + for which a given battery ID resistance is valid. This + value is expressed as a percentage of the specified kohm + resistance provided by qcom,batt-id-kohm. + +qcom,battery-data can also include any number of children nodes. These children +nodes will be treated as battery profile data nodes. + +Profile data node required properties: +- qcom,fcc-mah : Full charge count of the battery in milliamp-hours +- qcom,default-rbatt-mohm : The nominal battery resistance value +- qcom,rbatt-capacitive-mohm : The capacitive resistance of the battery. +- qcom,flat-ocv-threshold-uv : The threshold under which the battery can be + considered to be in the flat portion of the discharge + curve. +- qcom,max-voltage-uv : The maximum rated voltage of the battery +- qcom,v-cutoff-uv : The cutoff voltage of the battery at which the device + should shutdown gracefully. +- qcom,chg-term-ua : The termination charging current of the battery. +- qcom,batt-id-kohm : The battery id resistance of the battery. It can be + used as an array which could support multiple IDs for one battery + module when the ID resistance of some battery modules goes across + several ranges. +- qcom,battery-type : A string indicating the type of battery. +- qcom,fg-profile-data : An array of hexadecimal values used to configure more + complex fuel gauge peripherals which have a large amount + of coefficients used in hardware state machines and thus + influencing the final output of the state of charge read + by software. + +Profile data node optional properties: +- qcom,chg-rslow-comp-c1 : A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,chg-rslow-comp-c2 : A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,chg-rslow-comp-thr : A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,chg-rs-to-rslow: A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,fastchg-current-ma: Specifies the maximum fastcharge current. +- qcom,fg-cc-cv-threshold-mv: Voltage threshold in mV for transition from constant + charge (CC) to constant voltage (CV). This value should + be 10 mV less than the float voltage. + This property should only be specified if + "qcom,autoadjust-vfloat" property is specified in the + charger driver to ensure a proper operation. +- qcom,thermal-coefficients: Byte array of thermal coefficients for reading + battery thermistor. This should be exactly 6 bytes + in length. + Example: [01 02 03 04 05 06] +- qcom,soc-based-step-chg: A bool property to indicate if the battery will + perform SoC (State of Charge) based step charging. + If yes, the low and high thresholds defined in + "qcom,step-chg-ranges" tuples should be assigned as + SoC values in percentage. +- qcom,step-chg-ranges: Array of tuples in which a tuple describes a range + data of step charging setting. + A range contains following 3 integer elements: + [0]: the low threshold of battery votlage in uV + or SoC (State of Charge) in percentage when + SoC based step charge is used; + [1]: the high threshold of battery voltage in uV + or SoC in percentage when SoC based step charge + is used; + [2]: the FCC (full charging current) in uA when battery + voltage or SoC falls between the low and high + thresholds. + The threshold values in range should be in ascending + and shouldn't overlap. It support 8 ranges at max. +- qcom,jeita-fcc-ranges: Array of tuples in which a tuple describes a range + data of sw-jeita FCC (full charging current) setting. + A range contains following 3 integer elements: + [0]: the low threshold of battery temperature in deci-degree; + [1]: the high threshold of battery temperature in deci-degree; + [2]: the FCC in uA when battery temperature falls between + the low and high thresholds. + The threshold values in range should be in ascending + and shouldn't overlap. It support 8 ranges at max. +- qcom,jeita-fv-ranges: Array of tuples in which a tuple describes a range + data of sw-jeita FV (float voltage) setting. + A range contains following 3 integer elements: + [0]: the low threshold of battery temperature in deci-degree; + [1]: the high threshold of battery temperature in deci-degree; + [3]: the FV in uV when battery temperature falls between + the low and high thresholds. + The threshold values in range should be in ascending + and shouldn't overlap. It support 8 ranges at max. + +Profile data node required subnodes: +- qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes + temperature to fcc lookup. The units for this lookup + table should be degrees celsius to milliamp-hours. +- qcom,pc-temp-ocv-lut : A 2-dimensional lookup table node that encodes + temperature and percent charge to open circuit voltage + lookup. The units for this lookup table should be + degrees celsius and percent to millivolts. +- qcom,rbatt-sf-lut : A 2-dimentional lookup table node that encodes + temperature and percent charge to battery internal + resistance lookup. The units for this lookup table + should be degrees celsius and percent to milliohms. + +Profile data node optional subnodes: +- qcom,ibat-acc-luit: A 2-dimentional lookup table that encodes temperature + and battery current to battery ACC (apparent charge + capacity). The units for this lookup table should be + temperature in degrees celsius, ibat in milli-amps + and ACC in milli-ampere-hour. + +Lookup table required properties: +- qcom,lut-col-legend : An array that encodes the legend of the lookup table's + columns. The length of this array will determine the + lookup table's width. +- qcom,lut-data : An array that encodes the lookup table's data. The size of this + array should be equal to the size of qcom,lut-col-legend + multiplied by 1 if it's a 1-dimensional table, or + the size of qcom,lut-row-legend if it's a 2-dimensional + table. The data should be in a flattened row-major + representation. + +Lookup table optional properties: +- qcom,lut-row-legend : An array that encodes the legend of the lookup table's rows. + If this property exists, then it is assumed that the + lookup table is a 2-dimensional table. + +Example: + +In msm8974-mtp.dtsi: + +mtp_batterydata: qcom,battery-data { + qcom,rpull-up-kohm = <100>; + qcom,vref-batt-therm-uv = <1800000>; + + /include/ "batterydata-palladium.dtsi" + /include/ "batterydata-mtp-3000mah.dtsi" +}; + +&pm8941_bms { + qcom,battery-data = <&mtp_batterydata>; +}; + +In batterydata-palladium.dtsi: + +qcom,palladium-batterydata { + qcom,fcc-mah = <1500>; + qcom,default-rbatt-mohm = <236>; + qcom,rbatt-capacitive-mohm = <50>; + qcom,flat-ocv-threshold-uv = <3800000>; + qcom,max-voltage-uv = <4200000>; + qcom,v-cutoff-uv = <3400000>; + qcom,chg-term-ua = <100000>; + qcom,batt-id-kohm = <75>; + qcom,step-chg-ranges = <3600000 4000000 3000000 + 4001000 4200000 2800000 + 4201000 4400000 2000000>; + qcom,jeita-fcc-ranges = <0 100 600000 + 101 200 2000000 + 201 450 3000000 + 451 550 600000>; + qcom,jeita-fv-ranges = <0 100 4200000 + 101 450 4350000 + 451 550 4200000>; + qcom,battery-type = "palladium_1500mah"; + + qcom,fcc-temp-lut { + qcom,lut-col-legend = <(-20) 0 25 40 65>; + qcom,lut-data = <1492 1492 1493 1483 1502>; + }; + + qcom,pc-temp-ocv-lut { + qcom,lut-col-legend = <(-20) 0 25 40 65>; + qcom,lut-row-legend = <100 95 90 85 80 75 70>, + <65 60 55 50 45 40 35>, + <30 25 20 15 10 9 8>, + <7 6 5 4 3 2 1 0>; + qcom,lut-data = <4173 4167 4163 4156 4154>, + <4104 4107 4108 4102 4104>, + <4057 4072 4069 4061 4060>, + <3973 4009 4019 4016 4020>, + <3932 3959 3981 3982 3983>, + <3899 3928 3954 3950 3950>, + <3868 3895 3925 3921 3920>, + <3837 3866 3898 3894 3892>, + <3812 3841 3853 3856 3862>, + <3794 3818 3825 3823 3822>, + <3780 3799 3804 3804 3803>, + <3768 3787 3790 3788 3788>, + <3757 3779 3778 3775 3776>, + <3747 3772 3771 3766 3765>, + <3736 3763 3766 3760 3746>, + <3725 3749 3756 3747 3729>, + <3714 3718 3734 3724 3706>, + <3701 3703 3696 3689 3668>, + <3675 3695 3682 3675 3662>, + <3670 3691 3680 3673 3661>, + <3661 3686 3679 3672 3656>, + <3649 3680 3676 3669 3641>, + <3633 3669 3667 3655 3606>, + <3610 3647 3640 3620 3560>, + <3580 3607 3596 3572 3501>, + <3533 3548 3537 3512 3425>, + <3457 3468 3459 3429 3324>, + <3328 3348 3340 3297 3172>, + <3000 3000 3000 3000 3000>; + }; + + qcom,rbatt-sf-lut { + qcom,lut-col-legend = <(-20) 0 25 40 65>; + qcom,lut-row-legend = <100 95 90 85 80 75 70>, + <65 60 55 50 45 40 35>, + <30 25 20 15 10 9 8>, + <7 6 5 4 3 2 1 0>; + qcom,lut-data = <357 187 100 91 91>, + <400 208 105 94 94>, + <390 204 106 95 96>, + <391 201 108 98 98>, + <391 202 110 98 100>, + <390 200 110 99 102>, + <389 200 110 99 102>, + <393 202 101 93 100>, + <407 205 99 89 94>, + <428 208 100 91 96>, + <455 212 102 92 98>, + <495 220 104 93 101>, + <561 232 107 95 102>, + <634 245 112 98 98>, + <714 258 114 98 98>, + <791 266 114 97 100>, + <871 289 108 95 97>, + <973 340 124 108 105>, + <489 241 109 96 99>, + <511 246 110 96 99>, + <534 252 111 95 98>, + <579 263 112 96 96>, + <636 276 111 95 97>, + <730 294 109 96 99>, + <868 328 112 98 104>, + <1089 374 119 101 115>, + <1559 457 128 105 213>, + <12886 1026 637 422 3269>, + <170899 127211 98968 88907 77102>; + }; + + qcom,ibat-acc-lut { + qcom,lut-col-legend = <(-20) 0 25>; + qcom,lut-row-legend = <0 250 500 1000>; + qcom,lut-data = <1470 1470 1473>, + <1406 1406 1430>, + <1247 1247 1414>, + <764 764 1338>; + }; +}; + diff --git a/Documentation/devicetree/bindings/clock/qcom,a7-cpucc.txt b/Documentation/devicetree/bindings/clock/qcom,a7-cpucc.txt new file mode 100644 index 0000000000000000000000000000000000000000..2782b9c600b732fd44617931c686a244713370cf --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,a7-cpucc.txt @@ -0,0 +1,48 @@ +Qualcomm Application A7 CPU clock driver +------------------------------------- + +It is the clock controller driver which provides higher frequency +clocks and allows A7 CPU frequency scaling on sdxpoorwills based platforms. + +Required properties: +- compatible : shall contain only one of the following: + "qcom,cpu-sdxpoorwills", +- clocks : Phandle to the clock device. +- clock-names: Names of the used clocks. +- qcom,a7cc-init-rate = Initial rate which needs to be set from cpu driver. +- reg : shall contain base register offset and size. +- reg-names : Names of the bases for the above registers. +- vdd_dig_ao-supply : The regulator powering the APSS PLL. +- cpu-vdd-supply : The regulator powering the APSS RCG. +- qcom,rcg-reg-offset : Register offset for APSS RCG. +- qcom,speedX-bin-vZ : A table of CPU frequency (Hz) to regulator voltage (uV) mapping. + Format: + This represents the max frequency possible for each possible + power configuration for a CPU that's binned as speed bin X, + speed bin revision Z. Speed bin values can be between [0-7] + and the version can be between [0-3]. +- #clock-cells : shall contain 1. + +Optional properties : +- reg-names: "efuse", + +Example: + clock_cpu: qcom,clock-a7@17808100 { + compatible = "qcom,cpu-sdxpoorwills"; + clocks = <&clock_rpmh RPMH_CXO_CLK_A>; + clock-names = "xo_ao"; + qcom,a7cc-init-rate = <1497600000>; + reg = <0x17808100 0x7F10>; + reg-names = "apcs_pll"; + + vdd_dig_ao-supply = <&pmxpoorwills_s5_level_ao>; + cpu-vdd-supply = <&pmxpoorwills_s5_level_ao>; + qcom,rcg-reg-offset = <0x7F08>; + qcom,speed0-bin-v0 = + < 0 RPMH_REGULATOR_LEVEL_OFF>, + < 345600000 RPMH_REGULATOR_LEVEL_LOW_SVS>, + < 576000000 RPMH_REGULATOR_LEVEL_SVS>, + < 1094400000 RPMH_REGULATOR_LEVEL_NOM>, + < 1497600000 RPMH_REGULATOR_LEVEL_TURBO>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt index 231b8a36420ba90c06016ff4547c4f156540ab6c..37c48ad8743da4eb3ae007a6ffd34b5c5b3756e8 100644 --- a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt +++ b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt @@ -2,7 +2,7 @@ Qualcomm Technologies, Inc. Always On Processor Clock controller Binding ------------------------------------------------------------------------ Required properties : -- compatible : must be "qcom,aop-qmp-clk" +- compatible : must be "qcom,aop-qmp-clk-v1" or "qcom,aop-qmp-clk-v2". - #clock-cells : must contain 1 - mboxes : list of QMP mailbox phandle and channel identifier tuples. - mbox-names: List of identifier strings for each mailbox channel. @@ -10,7 +10,7 @@ Required properties : Example : clock_qdss: qcom,aopclk { - compatible = "qcom,aop-qmp-clk"; + compatible = "qcom,aop-qmp-clk-v1"; #clock-cells = <1>; mboxes = <&qmp_aop 0>; mbox-names = "qdss_clk"; diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc.txt b/Documentation/devicetree/bindings/clock/qcom,camcc.txt index dc93b35dddadcdf01069f8e25ff10b0eed6eaa6f..daf8a5394afda2de84b419b90bc236fb3ee1d5ef 100644 --- a/Documentation/devicetree/bindings/clock/qcom,camcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,camcc.txt @@ -2,7 +2,8 @@ Qualcomm Technologies Camera Clock & Reset Controller Binding ---------------------------------------------------- Required properties : -- compatible : shall contain "qcom,cam_cc-sdm845" +- compatible : shall contain "qcom,cam_cc-sdm845", "qcom,cam_cc-sdm845-v2" or + "qcom,cam_cc-sdm670" - reg : shall contain base register location and length - reg-names: names of registers listed in the same order as in the reg property. diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt index 92828e0daa8a19172402ed25dc344f40caa599ad..d169c31c13b8596faa69fa14b6f39555284bd316 100644 --- a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt @@ -2,7 +2,8 @@ Qualcomm Technologies, Inc. Display Clock & Reset Controller Binding ---------------------------------------------------- Required properties : -- compatible : shall contain "qcom,dispcc-sdm845". +- compatible : shall contain "qcom,dispcc-sdm845", "qcom,dispcc-sdm845-v2" or + "qcom,dispcc-sdm670". - reg : shall contain base register location and length. - reg-names: names of registers listed in the same order as in the reg property. diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index d95aa591c0bec5d4e040bd6c0114f70c32ff6b7b..7330db470e95a0410c5c980e5038453eaaf8bc4a 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -17,7 +17,11 @@ Required properties : "qcom,gcc-msm8996" "qcom,gcc-mdm9615" "qcom,gcc-sdm845" + "qcom,gcc-sdm845-v2" + "qcom,gcc-sdm845-v2.1" + "qcom,gcc-sdm670" "qcom,debugcc-sdm845" + "qcom,gcc-sdxpoorwills" - reg : shall contain base register location and length - #clock-cells : shall contain 1 diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt index f214c58c0a1cd04fbcc991f2facf988e009aa325..aa90bc413cb86f044aaa68dc7bcdb019fcff9ece 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt @@ -4,7 +4,11 @@ Qualcomm Technologies, Inc. Graphics Clock & Reset Controller Binding Required properties : - compatible : shall contain only one of the following: "qcom,gpucc-sdm845", - "qcom,gfxcc-sdm845" + "qcom,gpucc-sdm845-v2", + "qcom,gfxcc-sdm845", + "qcom,gfxcc-sdm845-v2" + "qcom,gpucc-sdm670", + "qcom,gfxcc-sdm670" - reg : shall contain base register offset and size. - #clock-cells : shall contain 1. diff --git a/Documentation/devicetree/bindings/clock/qcom,msm-clock-controller.txt b/Documentation/devicetree/bindings/clock/qcom,msm-clock-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef7d9c637ea1c601d4f60bd8038fa025ab1f3520 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,msm-clock-controller.txt @@ -0,0 +1,22 @@ +Qualcomm Technologies MSM Clock Controller + +Required properties : +- compatible : shall contain "qcom,msm-clock-controller" +- reg : shall contain base register location and length +- reg-names: names of registers listed in the same order as in + the reg property. +- #clock-cells : shall contain 1 +- #reset-cells : shall contain 1 + +Optional properties : +- vdd_-supply: The logic rail supply. + +Example: + clock_gcc: qcom,gcc@1800000 { + compatible = "qcom,msm-clock-controller"; + reg = <0x1800000 0x80000>; + reg-names = "cc-base"; + #clock-cells = <1>; + clock-names = "a7_debug_clk"; + clocks = <&clock_a7pll clk_a7_debug_mux>; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt index c81a4542dd283c2693c5d0d94597c28695eaf377..d57f61afa039523e7496fae82cc5b60d8533b4ba 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt @@ -2,7 +2,9 @@ Qualcomm Technologies, Inc. RPMh Clocks ------------------------------------------------------- Required properties : -- compatible : must be "qcom,rpmh-clk-sdm845" +- compatible : shall contain "qcom,rpmh-clk-sdm845" or "qcom,rpmh-clk-sdm670" + or "qcom,rpmh-clk-sdxpoorwills" + - #clock-cells : must contain 1 - mboxes : list of RPMh mailbox phandle and channel identifier tuples. - mbox-names : list of names to identify the RPMh mailboxes used. diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.txt b/Documentation/devicetree/bindings/clock/qcom,videocc.txt index 5dc109dc5a0f18d5d5a1b255ff965e76d34c73eb..9b53c65b16f937599fe97cda8511299e3f7066ad 100644 --- a/Documentation/devicetree/bindings/clock/qcom,videocc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,videocc.txt @@ -2,12 +2,13 @@ Qualcomm Technologies Video Clock & Reset Controller Binding ---------------------------------------------------- Required properties : -- compatible : shall contain "qcom,video_cc-sdm845" -- reg : shall contain base register location and length +- compatible : shall contain "qcom,video_cc-sdm845", "qcom,video_cc-sdm845-v2" + or "qcom,video_cc-sdm670". +- reg : shall contain base register location and length. - reg-names: names of registers listed in the same order as in the reg property. -- #clock-cells : shall contain 1 -- #reset-cells : shall contain 1 +- #clock-cells : shall contain 1. +- #reset-cells : shall contain 1. Optional properties : - vdd_-supply: The logic rail supply. diff --git a/Documentation/devicetree/bindings/clock/qoriq-clock.txt b/Documentation/devicetree/bindings/clock/qoriq-clock.txt index 16a3ec4331199c7b47d7f63ff8c9c7bd32c158cd..1bd2c76396f49b0f27e6897ece2609f67cb06fd7 100644 --- a/Documentation/devicetree/bindings/clock/qoriq-clock.txt +++ b/Documentation/devicetree/bindings/clock/qoriq-clock.txt @@ -31,6 +31,7 @@ Required properties: * "fsl,t4240-clockgen" * "fsl,b4420-clockgen" * "fsl,b4860-clockgen" + * "fsl,ls1012a-clockgen" * "fsl,ls1021a-clockgen" Chassis-version clock strings include: * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks diff --git a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt new file mode 100644 index 0000000000000000000000000000000000000000..9dff08d02aeead69e677fd286ef19e229a1af158 --- /dev/null +++ b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt @@ -0,0 +1,75 @@ +* Qualcomm Technologies, Inc. ConNectivity SubSystem Platform Driver + +This platform driver adds support for the CNSS subsystem used for PCIe +based Wi-Fi devices. It also adds support to integrate PCIe WLAN module +to subsystem restart framework. Apart from that, it also manages the +3.3V voltage regulator, WLAN Enable GPIO signal and PCIe link dynamically +with support for suspend and resume by retaining the PCI config space +states when PCIe link is shutdown. The main purpose of this device tree +entry below is to invoke the CNSS platform driver and provide handle to +the WLAN enable GPIO, 3.3V fixed voltage regulator resources. It also +provides the reserved RAM dump memory location and size. + +Required properties: + - compatible: "qcom,cnss" for QCA6174 device + "qcom,cnss-qca6290" for QCA6290 device + - wlan-en-gpio: WLAN_EN GPIO signal specified by the chip specifications + - vdd-wlan-supply: phandle to the regulator device tree node + - pinctrl-names: Names corresponding to the numbered pinctrl states + - pinctrl-: Pinctrl states as described in + bindings/pinctrl/pinctrl-bindings.txt + - qcom,wlan-rc-num: PCIe root complex number which WLAN chip is attached to + +Optional properties: + - qcom,notify-modem-status: Boolean property to decide whether modem + notification should be enabled or not in this + platform + - wlan-soc-swreg-supply: phandle to the external 1.15V regulator for QCA6174 + - wlan-ant-switch-supply: phandle to the 2.7V regulator for the antenna + switch of QCA6174 + - qcom,wlan-uart-access: Boolean property to decide whether QCA6174 + has exclusive access to UART. + - vdd-wlan-io-supply: phandle to the 1.8V IO regulator for QCA6174 + - vdd-wlan-xtal-supply: phandle to the 1.8V XTAL regulator for QCA6174 + - vdd-wlan-xtal-aon-supply: phandle to the LDO-4 regulator. This is needed + on platforms where XTAL regulator depends on + always on regulator in VDDmin. + - vdd-wlan-core-supply: phandle to the 1.3V CORE regulator for QCA6174 + - vdd-wlan-sp2t-supply: phandle to the 2.7V SP2T regulator for QCA6174 + - qcom,wlan-smmu-iova-address: I/O virtual address range as + format to be used for allocations associated + between WLAN/PCIe and SMMU + - qcom,wlan-ramdump-dynamic: To enable CNSS RAMDUMP collection + by providing the size of CNSS DUMP + - reg: Memory regions defined as starting address and size + - reg-names: Names of the memory regions defined in reg entry + - wlan-bootstrap-gpio: WLAN_BOOTSTRAP GPIO signal specified by QCA6174 + which should be drived depending on platforms + - qcom,is-dual-wifi-enabled: Boolean property to control wlan enable(wlan-en) + gpio on dual-wifi platforms. + - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174 + specifications. + - qcom,wlan-en-vreg-support: Boolean property to decide the whether the + WLAN_EN pin is a gpio or fixed regulator. + - qcom,mhi: phandle to indicate the device which needs MHI support. + - qcom,cap-tsf-gpio: WLAN_TSF_CAPTURED GPIO signal specified by the chip + specifications, should be drived depending on products + +Example: + + qcom,cnss@0d400000 { + compatible = "qcom,cnss"; + reg = <0x0d400000 0x200000>; + reg-names = "ramdump"; + qcom,wlan-ramdump-dynamic = <0x200000>; + wlan-en-gpio = <&msmgpio 82 0>; + vdd-wlan-supply = <&wlan_vreg>; + qcom,notify-modem-status; + wlan-soc-swreg-supply = <&pma8084_l27>; + pinctrl-names = "default"; + pinctrl-0 = <&cnss_default>; + qcom,wlan-rc-num = <0>; + qcom,wlan-smmu-iova-address = <0 0x10000000>; + qcom,mhi = <&mhi_wlan>; + qcom,cap-tsf-gpio = <&tlmm 126 1>; + }; diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt index c801e8486f872031936b7d4eab0345c475572e92..ad9d190255a0ebd8c1349d955921fd1cae4bb256 100644 --- a/Documentation/devicetree/bindings/cnss/icnss.txt +++ b/Documentation/devicetree/bindings/cnss/icnss.txt @@ -28,6 +28,8 @@ Optional properties: - qcom,icnss-vadc: VADC handle for vph_pwr read APIs. - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs. - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass + - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory + - qcom,gpio-force-fatal-error: SMP2P bit triggered by WLAN FW to force error fatal. Example: @@ -54,7 +56,9 @@ Example: <0 140 0 /* CE10 */ >, <0 141 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x200000>; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; qcom,smmu-s1-bypass; vdd-0.8-cx-mx-supply = <&pm8998_l5>; qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>; + qcom,gpio-forced-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; }; diff --git a/Documentation/devicetree/bindings/crypto/msm/ice.txt b/Documentation/devicetree/bindings/crypto/msm/ice.txt index 2d0e58059da3c6607ea14f99b27550c4570cc058..fe8671f1165c62c81a1341dfce4e92be4cd4a983 100644 --- a/Documentation/devicetree/bindings/crypto/msm/ice.txt +++ b/Documentation/devicetree/bindings/crypto/msm/ice.txt @@ -5,16 +5,22 @@ Required properties: - reg : Optional properties: - - interrupt-names : name describing the interrupts for ICE IRQ - - interrupts : - - qcom,enable-ice-clk : should enable clocks for ICE HW - - clocks : List of phandle and clock specifier pairs - - clock-names : List of clock input name strings sorted in the same - order as the clocks property. - - qocm,op-freq-hz : max clock speed sorted in the same order as the clocks - property. - - qcom,instance-type : describe the storage type for which ICE node is defined - currently, only "ufs" and "sdcc" are supported storage type + - interrupt-names : name describing the interrupts for ICE IRQ + - interrupts : + - qcom,enable-ice-clk : should enable clocks for ICE HW + - clocks : List of phandle and clock specifier pairs + - clock-names : List of clock input name strings sorted in the same + order as the clocks property. + - qocm,op-freq-hz : max clock speed sorted in the same order as the clocks + property. + - qcom,instance-type : describe the storage type for which ICE node is defined + currently, only "ufs" and "sdcc" are supported storage type + - vdd-hba-supply : regulated supply to be used by ICE HW + - qcom,msm-bus,name : bus for ICE transactions + - qcom,msm-bus,num-cases : bus case mapping for ICE HW + - qcom,msm-bus,num-paths : bus path mapping for iCE HW + - qcom,msm-bus,vectors-KBps : bus bandwidth to be voted + - qcom,bus-vector-names : bus vectors mapping Example: ufs_ice: ufsice@630000 { @@ -30,3 +36,26 @@ Example: qcom,instance-type = "ufs"; status = "disabled"; }; + + ufs_card_ice: ufscardice@1db0000 { + compatible = "qcom,ice_card"; + reg = <0x1db0000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_CARD_AXI_CLK>, + <&clock_gcc GCC_UFS_CARD_CLKREF_CLK>, + <&clock_gcc GCC_UFS_CARD_AHB_CLK>, + <&clock_gcc GCC_UFS_CARD_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_card_gdsc>; + qcom,msm-bus,name = "ufs_card_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs_card"; + }; diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt index c8077cb155235c403ae31c2f8f546a25a42e8f54..6f1d8e35978eec6244f2aab5c9a01a86f49c7735 100644 --- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt +++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt @@ -20,6 +20,8 @@ Optional properties: - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY. - qcom,support-core-clk-only : optional, indicates if the HW supports single crypto core clk. - qcom,bsm-ee : optional, indicate the BAM EE value, changes from target to target. Default value is 1 if not specified. + - qcom,smmu-s1-enable : Boolean flag to enable SMMU stage 1 translation. + - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. Example: diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt index 06b219ace82243f495058a4e6971f2132773b0b3..231f31aae18f3dd0e7644f301c3dc174b87fbfa2 100644 --- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt +++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt @@ -28,6 +28,7 @@ Optional properties: - qcom,use-sw-aes-ccm-algo : optional, indicates if use SW aes-ccm algorithm. - qcom,clk-mgmt-sus-res : optional, indicate if the ce clocks need to be disabled/enabled in suspend/resume function. - qcom,support-core-clk-only : optional, indicates if the HW supports single crypto core clk. + - qcom,request-bw-before-clk : optional, indicates if the HW supports bandwidth requests prior to clock controls. - qcom,bsm-ee : optional, indicate the BAM EE value, changes from target to target.Default value is 1 if not specified. - qcom,ce-opp-freq: optional, indicates the CE operating frequency in Hz, @@ -39,6 +40,9 @@ Optional properties: required. For other targets such as fsm, they do not perform bus scaling. It is not required for those targets. + - qcom,smmu-s1-enable : Boolean flag to bypass SMMU stage 1 translation. + - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + Example: qcom,qcrypto@fd444000 { diff --git a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt index 67dc991b3e75665e488c462bd78f34e1b14c202a..378641257b3cfbc44faf6933179e0aca53cc1fce 100644 --- a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt +++ b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt @@ -4,7 +4,7 @@ arm-memlat-mon is a device that represents the use of the PMU in ARM cores to measure the parameters for latency driven memory access patterns. Required properties: -- compatible: Must be "qcom,arm-memlat-mon" +- compatible: Must be "qcom,arm-memlat-mon" or "qcom,arm-cpu-mon" - qcom,cpulist: List of CPU phandles to be monitored in a cluster - qcom,target-dev: The DT device that corresponds to this master port - qcom,core-dev-table: A mapping table of core frequency to a required bandwidth vote at the @@ -15,6 +15,8 @@ Optional properties: Defaults to 0x17 if not specified. - qcom,inst-ev: The instruction count event that this monitor is supposed to measure. Defaults to 0x08 if not specified. +- qcom,stall-cycle-ev: The stall cycle count that this monitor is supposed to measure. + Assumes 100% stall if not specified. Example: @@ -24,6 +26,7 @@ Example: qcom,target-dev = <&memlat0>; qcom,cachemiss-ev = <0x2A>; qcom,inst-ev = <0x08>; + qcom,stall-cycle-ev = <0xE7>; qcom,core-dev-table = < 300000 1525>, < 499200 3143>, diff --git a/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt b/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt index c77f84b61eaf8a94d37e73fa4af220747b9a553b..29b733463af9d3a1628e8b3df38f9691239d50d0 100644 --- a/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt +++ b/Documentation/devicetree/bindings/devfreq/bimc-bwmon.txt @@ -6,17 +6,25 @@ master ports. For example, the CPU subsystem sits on one BIMC master port. Required properties: - compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2", - "qcom,bimc-bwmon3" or "qcom,bimc-bwmon4" + "qcom,bimc-bwmon3" or "qcom,bimc-bwmon4" or + "qcom,bimc-bwmon5" - reg: Pairs of physical base addresses and region sizes of memory mapped registers. - reg-names: Names of the bases for the above registers. Expected bases are: "base", "global_base" + "global_base" should not be specified for + "qcom,bimc-bwmon5" compatibles. - interrupts: Lists the threshold IRQ. - qcom,mport: The hardware master port that this device can monitor - qcom,target-dev: The DT device that corresponds to this master port - qcom,hw-timer-hz: Hardware sampling rate in Hz. This field must be specified for "qcom,bimc-bwmon4" +Optional properties: +- qcom,byte-mid-match: Byte count MID match value +- qcom,byte-mid-mask: Byte count MID mask value +- qcom,count-unit: Number of bytes monitor counts in + Example: qcom,cpu-bwmon { compatible = "qcom,bimc-bwmon"; @@ -26,4 +34,7 @@ Example: qcom,mport = <0>; qcom,target-dev = <&cpubw>; qcom,hw-timer-hz = <19200000>; + qcom,byte-mid-match = <0x1e00>; + qcom,byte-mid-mask = <0x1e00>; + qcom,count-unit = <0x100000>; }; diff --git a/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt b/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt index d00ebd84a52028156b4d200b233d303e30a7665c..5f66bbffc06eb963b20448ce5ef058130c2d33f3 100644 --- a/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt +++ b/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt @@ -9,12 +9,12 @@ Required properties: - compatible: Must be "devfreq-simple-dev" - clock-names: Must be "devfreq_clk" - clocks: Must refer to the clock that's fed to the device. -- freq-tbl-khz: A list of usable frequencies (in KHz) for the device - clock. Optional properties: - polling-ms: Polling interval for the device in milliseconds. Default: 50 - governor: Initial governor to user for the device. Default: "performance" - qcom,prepare-clk: Prepare the device clock during initialization. +- freq-tbl-khz: A list of usable frequencies (in kHz) for the device + clock. Example: diff --git a/Documentation/devicetree/bindings/devfreq/devfreq-spdm.txt b/Documentation/devicetree/bindings/devfreq/devfreq-spdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..16303f769d42222e3e15609fefc06fbaa7c6bf3d --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/devfreq-spdm.txt @@ -0,0 +1,84 @@ +MSM SPDM bandwidth monitor device + +devfreq-spdm is a device that represents a device that is monitored by the SPDM +hardware to measure the traffic status of configured master ports on the bus. + + +Required properties: +-compatible: Must be "qcom,devfreq_spdm" +-clock-names: Clocks used to measure current bus frequency. + Expected names are "cci_clk" +-clocks: References to named clocks +-qcom,spdm-client: Client id of the port being monitored +-qcom,bw-upstep: Initial up vote size in MB/s +-qcom,bw-dwnstep: Initial down vote size in MB/s +-qcom,max-vote: Vote ceiling in MB/s +-qcom,ports: SPDM ports used by this device +-qcom,alpha-up: SPDM filter up alpha value +-qcom,alpha-down: SPDM filter down alpha value +-qcom,bucket-size: SPDM filter bucket size +-qcom,pl-freqs: The driver supports different filter values at + three different performance levels. This value + defines the cut-over frequenices +-qcom,reject-rate: Desired rejection rate used to calculate + SPDM threshold +-qcom,response-time-us: Desired response time used to calculate + SPDM threshold +-qcom,cci-response-time-us: Desired response time used to calculate + SPDM threshold when CCI is under heavy load +-qcom,max-cci-freq: CCI frequency at which cci_response_time_us + is used +-qcom,up-step-multp: used to increase rate of growth on up votes +-qcom,spdm-interval: down-vote polling interval + +Example: +devfreq_spdm_cpu { + compatible = "qcom,devfreq_spdm"; + qcom,msm-bus,name = "devfreq_spdm"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 512 0 0>, + <1 512 0 0>; + qcom,spdm-client = <0>; + + clock-names = "cci_clk"; + clocks = <&clock_cpu clk_cci_clk>; + + qcom,bw-upstep = <100>; + qcom,bw-dwnstep = <100>; + qcom,max-vote = <10000>; + qcom,up-step-multp = <2>; + qcom,spdm-interval = <100>; + + qcom,ports = <16>; + qcom,alpha-up = <7>; + qcom,alpha-down = <15>; + qcom,bucket-size = <8>; + + /*max pl1 freq, max pl2 freq*/ + qcom,pl-freqs = <149999999 150000000>; + + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,reject-rate = <5000 5000 5000 5000 5000 5000>; + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,response-time-us = <220 220 2000 2000 900 900>; + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,cci-response-time-us = <50 50 30 30 20 20>; + qcom,max-cci-freq = <600000000>; +}; + +This device is always used with the SPDM governor which requires a device tree +entry to know what IRQ to respond to. + +Required properties: +-compatible Must be "qcom,gov_spdm_hyp" +-interrupt-names SPDM irq to handle. Name should be "spdm-irq" +-interrupts The interrupt number the SPDM hw is assigned + +Example: +devfreq_spdm_gov { + compatible = "qcom,gov_spdm_hyp"; + interrupt-names = "spdm-irq"; + interrupts = <0 192 0>; +}; diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ec1a880ac18bbe90a309e8f53aed410cda7e5a8 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt @@ -0,0 +1,46 @@ +THS8135 Video DAC +----------------- + +This is the binding for Texas Instruments THS8135 Video DAC bridge. + +Required properties: + +- compatible: Must be "ti,ths8135" + +Required nodes: + +This device has two video ports. Their connections are modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for RGB input +- Video port 1 for VGA output + +Example +------- + +vga-bridge { + compatible = "ti,ths8135"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + vga_bridge_in: endpoint { + remote-endpoint = <&lcdc_out_vga>; + }; + }; + + port@1 { + reg = <1>; + + vga_bridge_out: endpoint { + remote-endpoint = <&vga_con_in>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index 3534f0419870dd87bf8a164dbdd3e150ace852f6..fc95288a36884e625babce2f70669079e34bbcc3 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -121,6 +121,12 @@ Optional properties: If ping pong split is enabled, this time should not be higher than two times the dsi link rate time. If the property is not specified, then the default value is 14000 us. +- qcom,panel-allow-phy-poweroff: A boolean property indicates that panel allows to turn off the phy power + supply during idle screen. A panel should be able to handle the dsi lanes + in floating state(not LP00 or LP11) to turn on this property. Software + turns off PHY pmic power supply, phy ldo and DSI Lane ldo during + idle screen (footswitch control off) when this property is enabled. +- qcom,dsi-phy-regulator-min-datarate-bps: Minimum per lane data rate (bps) to turn on PHY regulator. [1] Documentation/devicetree/bindings/clocks/clock-bindings.txt [2] Documentation/devicetree/bindings/graph.txt @@ -229,4 +235,6 @@ Example: vddio-supply = <&pma8084_l12>; qcom,dsi-phy-regulator-ldo-mode; + qcom,panel-allow-phy-poweroff; + qcom,dsi-phy-regulator-min-datarate-bps = <1200000000>; }; diff --git a/Documentation/devicetree/bindings/display/msm/sde-rsc.txt b/Documentation/devicetree/bindings/display/msm/sde-rsc.txt index 7e54fdd91a1c2368b6de6f7d3d1ab923a8e7957a..55d18cf6fe328040b9fde461ef53bceca3998b35 100644 --- a/Documentation/devicetree/bindings/display/msm/sde-rsc.txt +++ b/Documentation/devicetree/bindings/display/msm/sde-rsc.txt @@ -29,6 +29,10 @@ Optional properties: Bus Scaling Subnodes: - qcom,sde-data-bus: Property to provide Bus scaling for data bus access for sde blocks. +- qcom,sde-llcc-bus: Property to provide Bus scaling for data bus access for + mnoc to llcc. +- qcom,sde-ebi-bus: Property to provide Bus scaling for data bus access for + llcc to ebi. Bus Scaling Data: - qcom,msm-bus,name: String property describing client name. @@ -69,4 +73,24 @@ Example: <22 512 0 6400000>, <23 512 0 6400000>, <22 512 0 6400000>, <23 512 0 6400000>; }; + qcom,sde-llcc-bus { + qcom,msm-bus,name = "sde_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + qcom,sde-ebi-bus { + qcom,msm-bus,name = "sde_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; }; diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt index bc226a7fa77004450c2ffba21ffefbb1bbc7b9f9..4b4c274bf4ed6632aa837771f4e4ae7d5652ec08 100644 --- a/Documentation/devicetree/bindings/display/msm/sde.txt +++ b/Documentation/devicetree/bindings/display/msm/sde.txt @@ -52,6 +52,9 @@ Required properties The number of offsets defined should reflect the amount of mixers that can drive data to a panel interface. +- qcom,sde-dspp-top-off: Offset address for the dspp top block. + The offset is calculated from register "mdp_phys" + defined in reg property. - qcom,sde-dspp-off: Array of offset addresses for the available dspp blocks. These offsets are calculated from register "mdp_phys" defined in reg property. @@ -122,16 +125,33 @@ Optional properties: configuration value. - qcom,sde-ubwc-swizzle: Property to specify the default UBWC swizzle configuration value. +- qcom,sde-smart-panel-align-mode: A u32 property to specify the align mode for + split display on smart panel. Possible values: + 0x0 - no alignment + 0xc - align at start of frame + 0xd - align at start of line - qcom,sde-panic-per-pipe: Boolean property to indicate if panic signal control feature is available on each source pipe. - qcom,sde-has-src-split: Boolean property to indicate if source split feature is available or not. - qcom,sde-has-dim-layer: Boolean property to indicate if mixer has dim layer feature is available or not. +- qcom,sde-has-idle-pc: Boolean property to indicate if target has idle + power collapse feature available or not. - qcom,sde-has-mixer-gc: Boolean property to indicate if mixer has gamma correction feature available or not. -- qcom,sde-has-cdp: Boolean property to indicate if cdp feature is - available or not. +- qcom,sde-has-dest-scaler: Boolean property to indicate if destination scaler + feature is available or not. +- qcom,sde-max-dest-scaler-input-linewidth: A u32 value indicates the + maximum input line width to destination scaler. +- qcom,sde-max-dest-scaler-output-linewidth: A u32 value indicates the + maximum output line width of destination scaler. +- qcom,sde-dest-scaler-top-off: A u32 value provides the + offset from mdp base to destination scaler block. +- qcom,sde-dest-scaler-top-size: A u32 value indicates the address range for ds top +- qcom,sde-dest-scaler-off: Array of u32 offsets indicate the qseed3 scaler blocks + offset from destination scaler top offset. +- qcom,sde-dest-scaler-size: A u32 value indicates the address range for each scaler block - qcom,sde-sspp-clk-ctrl: Array of offsets describing clk control offsets for dynamic clock gating. 1st value in the array represents offset of the control @@ -146,10 +166,6 @@ Optional properties: control register. Number of offsets defined should match the number of offsets defined in property: qcom,sde-sspp-off. -- qcom,sde-sspp-danger-lut: A 3 cell property, with a format of , - indicating the danger luts on sspp. -- qcom,sde-sspp-safe-lut: A 3 cell property, with a format of , - indicating the safe luts on sspp. - qcom,sde-sspp-excl-rect: Array of u32 values indicating exclusion rectangle support on each sspp. - qcom,sde-sspp-smart-dma-priority: Array of u32 values indicating hw pipe @@ -182,6 +198,9 @@ Optional properties: - qcom,sde-te-size: A u32 value indicates the te block address range. - qcom,sde-te2-size: A u32 value indicates the te2 block address range. - qcom,sde-dsc-off: A u32 offset indicates the dsc block offset on pingpong. +- qcom,sde-dither-off: A u32 offset indicates the dither block offset on pingpong. +- qcom,sde-dither-version: A u32 value indicates the dither block version. +- qcom,sde-dither-size: A u32 value indicates the dither block address range. - qcom,sde-sspp-vig-blocks: A node that lists the blocks inside the VIG hardware. The block entries will contain the offset and version (if needed) of each feature block. The presence of a block entry @@ -208,6 +227,7 @@ Optional properties: e.g. qcom,sde-dspp-blocks -- qcom,sde-dspp-pcc: offset and version of PCC hardware -- qcom,sde-dspp-gc: offset and version of GC hardware + -- qcom,sde-dspp-igc: offset and version of IGC hardware -- qcom,sde-dspp-hsic: offset and version of global PA adjustment -- qcom,sde-dspp-memcolor: offset and version of PA memcolor hardware -- qcom,sde-dspp-sixzone: offset and version of PA sixzone hardware @@ -238,6 +258,8 @@ Optional properties: of (pps, OT limit), where pps is pixel per second and OT limit is the write limit to apply if the given pps is not exceeded. +- qcom,sde-vbif-memtype-0: Array of u32 vbif memory type settings, group 0 +- qcom,sde-vbif-memtype-1: Array of u32 vbif memory type settings, group 1 - qcom,sde-wb-id: Array of writeback ids corresponding to the offsets defined in property: qcom,sde-wb-off. - qcom,sde-wb-clk-ctrl: Array of 2 cell property describing clk control @@ -272,12 +294,117 @@ Optional properties: applied in scenarios where panel interface can be more tolerant to memory latency such as command mode panels. +- qcom,sde-core-ib-ff: A string entry indicating the fudge factor for + core ib calculation. +- qcom,sde-core-clk-ff: A string entry indicating the fudge factor for + core clock calculation. +- qcom,sde-min-core-ib-kbps: This u32 value indicates the minimum mnoc ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-min-llcc-ib-kbps: This u32 value indicates the minimum llcc ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-min-dram-ib-kbps: This u32 value indicates the minimum dram ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-comp-ratio-rt: A string entry indicating the compression ratio + for each supported compressed format on realtime interface. + The string is composed of one or more of + /// + separated with spaces. +- qcom,sde-comp-ratio-nrt: A string entry indicating the compression ratio + for each supported compressed format on non-realtime interface. + The string is composed of one or more of + /// + separated with spaces. +- qcom,sde-undersized-prefill-lines: A u32 value indicates the size of undersized prefill in lines. +- qcom,sde-xtra-prefill-lines: A u32 value indicates the extra prefill in lines. +- qcom,sde-dest-scale-prefill-lines: A u32 value indicates the latency of destination scaler in lines. +- qcom,sde-macrotile-prefill-lines: A u32 value indicates the latency of macrotile in lines. +- qcom,sde-yuv-nv12-prefill-lines: A u32 value indicates the latency of yuv/nv12 in lines. +- qcom,sde-linear-prefill-lines: A u32 value indicates the latency of linear in lines. +- qcom,sde-downscaling-prefill-lines: A u32 value indicates the latency of downscaling in lines. +- qcom,sde-max-per-pipe-bw-kbps: Array of u32 value indicates the max per pipe bandwidth in Kbps. +- qcom,sde-amortizable-threshold: This value indicates the min for traffic shaping in lines. +- qcom,sde-vbif-qos-rt-remap: This array is used to program vbif qos remapper register + priority for realtime clients. +- qcom,sde-vbif-qos-nrt-remap: This array is used to program vbif qos remapper register + priority for non-realtime clients. +- qcom,sde-danger-lut: A 4 cell property, with a format of , + indicating the danger luts on sspp. +- qcom,sde-safe-lut-linear: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for linear format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-macrotile: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for macrotile format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-nrt: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for nrt (e.g wfd) on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-cwb: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for cwb on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-linear: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for linear format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-macrotile: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for macrotile format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-nrt: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for nrt (e.g wfd) on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-cwb: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for cwb on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-cdp-setting: Array of 2 cell property, with a format of + for cdp use cases in + order of , and . +- qcom,sde-qos-cpu-mask: A u32 value indicating desired PM QoS CPU affine mask. +- qcom,sde-qos-cpu-dma-latency: A u32 value indicating desired PM QoS CPU DMA latency in usec. +- qcom,sde-inline-rot-xin: An integer array of xin-ids related to inline + rotation. +- qcom,sde-inline-rot-xin-type: A string array indicating the type of xin, + namely sspp or wb. Number of entries should match + the number of xin-ids defined in + property: qcom,sde-inline-rot-xin +- qcom,sde-inline-rot-clk-ctrl: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of xin-ids defined in + property: qcom,sde-inline-rot-xin +- #power-domain-cells: Number of cells in a power-domain specifier and should contain 0. +- qcom,sde-mixer-display-pref: A string array indicating the preferred display type + for the mixer block. Possible values: + "primary" - preferred for primary display + "none" - no preference on display +- qcom,sde-ctl-display-pref: A string array indicating the preferred display type + for the ctl block. Possible values: + "primary" - preferred for primary display + "none" - no preference on display Bus Scaling Subnodes: - qcom,sde-reg-bus: Property to provide Bus scaling for register access for mdss blocks. - qcom,sde-data-bus: Property to provide Bus scaling for data bus access for mdss blocks. +- qcom,sde-llcc-bus: Property to provide Bus scaling for data bus access for + mnoc to llcc. +- qcom,sde-ebi-bus: Property to provide Bus scaling for data bus access for + llcc to ebi. - qcom,sde-inline-rotator: A 2 cell property, with format of (rotator phandle, instance id), of inline rotator device. @@ -294,17 +421,23 @@ Bus Scaling Data: * Current values of src & dst are defined at include/linux/msm-bus-board.h +SMMU Subnodes: +- smmu_sde_****: Child nodes representing sde smmu virtual + devices + Subnode properties: -- compatible : Compatible name used in smmu v2. - smmu_v2 names should be: - "qcom,smmu-mdp-unsec" - smmu context bank device for - unsecure mdp domain. - "qcom,smmu-rot-unsec" - smmu context bank device for - unsecure rotation domain. - "qcom,smmu-mdp-sec" - smmu context bank device for - secure mdp domain. - "qcom,smmu-rot-sec" - smmu context bank device for - secure rotation domain. +- compatible: Compatible names used for smmu devices. + names should be: + "qcom,smmu_sde_unsec": smmu context bank device + for unsecure sde real time domain. + "qcom,smmu_sde_sec": smmu context bank device + for secure sde real time domain. + "qcom,smmu_sde_nrt_unsec": smmu context bank device + for unsecure sde non-real time domain. + "qcom,smmu_sde_nrt_sec": smmu context bank device + for secure sde non-real time domain. + + Please refer to ../../interrupt-controller/interrupts.txt for a general description of interrupt bindings. @@ -342,15 +475,23 @@ Example: interrupt-controller; #interrupt-cells = <1>; iommus = <&mdp_smmu 0>; + #power-domain-cells = <0>; qcom,sde-off = <0x1000>; qcom,sde-ctl-off = <0x00002000 0x00002200 0x00002400 0x00002600 0x00002800>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; qcom,sde-mixer-off = <0x00045000 0x00046000 0x00047000 0x0004a000>; + qcom,sde-mixer-display-pref = "primary", "none", + "none", "none"; + qcom,sde-dspp-top-off = <0x1300>; qcom,sde-dspp-off = <0x00055000 0x00057000>; qcom,sde-dspp-ad-off = <0x24000 0x22800>; qcom,sde-dspp-ad-version = <0x00030000>; + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; qcom,sde-wb-off = <0x00066000>; qcom,sde-wb-xin-id = <6>; qcom,sde-intf-off = <0x0006b000 0x0006b800 @@ -399,19 +540,22 @@ Example: qcom,sde-ubwc-version = <0x100>; qcom,sde-ubwc-static = <0x100>; qcom,sde-ubwc-swizzle = <0>; + qcom,sde-smart-panel-align-mode = <0xd>; qcom,sde-panic-per-pipe; - qcom,sde-has-cdp; qcom,sde-has-src-split; qcom,sde-has-dim-layer; qcom,sde-sspp-src-size = <0x100>; qcom,sde-mixer-size = <0x100>; qcom,sde-ctl-size = <0x100>; + qcom,sde-dspp-top-size = <0xc>; qcom,sde-dspp-size = <0x100>; qcom,sde-intf-size = <0x100>; qcom,sde-dsc-size = <0x100>; qcom,sde-cdm-size = <0x100>; qcom,sde-pp-size = <0x100>; qcom,sde-wb-size = <0x100>; + qcom,sde-dest-scaler-top-size = <0xc>; + qcom,sde-dest-scaler-size = <0x800>; qcom,sde-len = <0x100>; qcom,sde-wb-linewidth = <2560>; qcom,sde-sspp-scale-size = <0x100>; @@ -420,6 +564,10 @@ Example: qcom,sde-csc-type = "csc-10bit"; qcom,sde-highest-bank-bit = <15>; qcom,sde-has-mixer-gc; + qcom,sde-has-idle-pc; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; qcom,sde-sspp-max-rects = <1 1 1 1 1 1 1 1 1 1 @@ -441,8 +589,38 @@ Example: qcom,sde-wb-id = <2>; qcom,sde-wb-clk-ctrl = <0x2bc 16>; - qcom,sde-sspp-danger-lut = <0x000f 0xffff 0x0000>; - qcom,sde-sspp-safe-lut = <0xfffc 0xff00 0xffff>; + qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 + 0x00000000>; + qcom,sde-safe-lut = <0xfffc 0xff00 0xffff 0xffff>; + qcom,sde-qos-lut-linear = + <4 0x00000000 0x00000357>, + <5 0x00000000 0x00003357>, + <6 0x00000000 0x00023357>, + <7 0x00000000 0x00223357>, + <8 0x00000000 0x02223357>, + <9 0x00000000 0x22223357>, + <10 0x00000002 0x22223357>, + <11 0x00000022 0x22223357>, + <12 0x00000222 0x22223357>, + <13 0x00002222 0x22223357>, + <14 0x00012222 0x22223357>, + <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = + <10 0x00000003 0x44556677>, + <11 0x00000033 0x44556677>, + <12 0x00000233 0x44556677>, + <13 0x00002233 0x44556677>, + <14 0x00012233 0x44556677>, + <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-nrt = + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = + <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; qcom,sde-vbif-off = <0 0>; qcom,sde-vbif-id = <0 1>; @@ -452,6 +630,8 @@ Example: <124416000 4>, <248832000 16>; qcom,sde-vbif-dynamic-ot-wr-limit = <62208000 2>, <124416000 4>, <248832000 16>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; qcom,sde-dram-channels = <2>; qcom,sde-num-nrt-paths = <1>; @@ -459,6 +639,27 @@ Example: qcom,sde-max-bw-high-kbps = <9000000>; qcom,sde-max-bw-low-kbps = <9000000>; + qcom,sde-core-ib-ff = "1.1"; + qcom,sde-core-clk-ff = "1.0"; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-comp-ratio-rt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3"; + qcom,sde-comp-ratio-nrt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3"; + qcom,sde-undersized-prefill-lines = <4>; + qcom,sde-xtra-prefill-lines = <5>; + qcom,sde-dest-scale-prefill-lines = <6>; + qcom,sde-macrotile-prefill-lines = <7>; + qcom,sde-yuv-nv12-prefill-lines = <8>; + qcom,sde-linear-prefill-lines = <9>; + qcom,sde-downscaling-prefill-lines = <10>; + qcom,sde-max-per-pipe-bw-kbps = <2400000 2400000 2400000 2400000 + 2400000 2400000 2400000 2400000>; + qcom,sde-amortizable-threshold = <11>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-sspp-vig-blocks { qcom,sde-vig-csc-off = <0x320>; qcom,sde-vig-qseed-off = <0x200>; @@ -476,6 +677,7 @@ Example: }; qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00010000>; qcom,sde-dspp-pcc = <0x1700 0x00010000>; qcom,sde-dspp-gc = <0x17c0 0x00010000>; qcom,sde-dspp-hsic = <0x0 0x00010000>; @@ -496,6 +698,9 @@ Example: }; qcom,sde-inline-rotator = <&mdss_rotator 0>; + qcom,sde-inline-rot-xin = <10 11>; + qcom,sde-inline-rot-xin-type = "sspp", "wb"; + qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>; qcom,platform-supply-entries { #address-cells = <1>; @@ -525,6 +730,24 @@ Example: <22 512 0 6400000>, <23 512 0 6400000>, <25 512 0 6400000>; }; + qcom,sde-llcc-bus { + qcom,msm-bus,name = "mdss_sde_llcc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <132 770 0 0>, + <132 770 0 6400000>, + <132 770 0 6400000>; + }; + qcom,sde-ebi-bus { + qcom,msm-bus,name = "mdss_sde_ebi"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 6400000>, + <129 512 0 6400000>; + }; qcom,sde-reg-bus { /* Reg Bus Scale Settings */ @@ -538,4 +761,14 @@ Example: <1 590 0 160000>, <1 590 0 320000>; }; + + smmu_kms_unsec: qcom,smmu_kms_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&mmss_smmu 0>; + }; + + smmu_kms_sec: qcom,smmu_kms_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&mmss_smmu 1>; + }; }; diff --git a/Documentation/devicetree/bindings/dma/qcom-sps-dma.txt b/Documentation/devicetree/bindings/dma/qcom-sps-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6c8726dac263f294127c73c11d2754afc27171e --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qcom-sps-dma.txt @@ -0,0 +1,42 @@ +* Qualcomm technologies inc, DMA engine driver for BAM (Bus Access Manager). + +Required properties: +- compatible: Should be "qcom,sps-dma". +- reg: Should contain DMA registers location and length. This should include + all of the per-channel registers. +- interrupts: Should contain the BAM interrupt number. +- qcom,summing-threshold: Should contain the BAM event threshold of + the sum of descriptors' sizes in bytes. + +Optional properties: +- qcom,managed-locally : Use when BAM global device control is managed locally + by the application processor. + +Example: + + dma_blsp1: qcom,sps-dma@f9904000 { /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0xf9904000 0x19000>; + interrupts = <0 238 0>; + qcom,summing-threshold = <10>; + }; + +DMA clients connected to the qcom-sps-dma DMA controller must use the format +described in the dma.txt file, using a five-cell specifier for each channel, +a phandle plus four integer cells, as shown below: + +dmas = <[phandle of the dma controller] [pipe index] [number of descriptors] + [sps_connect flags] [sps_register_event flags]>; + +Example: + +i2c_2: i2c@f9924000 { /* BLSP1 QUP2 */ + . + . + . + /* <&phandle pipe-idx n-descs connect-flags event-flags> */ + dmas = <&dma_blsp1 14 32 0x20000020 0x20>, + <&dma_blsp1 15 64 0x20000020 0x20>; + dma-names = "tx", "rx"; +}; diff --git a/Documentation/devicetree/bindings/dma/qcom_gpi.txt b/Documentation/devicetree/bindings/dma/qcom_gpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1b4a429ed391fe01ba18240efa5a4581a9362f9 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qcom_gpi.txt @@ -0,0 +1,101 @@ +Qualcomm Technologies Inc GPI DMA controller + +QCOM GPI DMA controller provides DMA capabilities for +peripheral buses such as I2C, UART, and SPI. + +============== +Node Structure +============== + +Main node properties: + +- #dma-cells + Usage: required + Value type: + Definition: Number of parameters client will provide. Must be set to 5. + 1st parameter: channel index, 0 for TX, 1 for RX + 2nd parameter: serial engine index + 3rd parameter: bus protocol, 1 for SPI, 2 for UART, 3 for I2C + 4th parameter: channel ring length in transfer ring elements + 5th parameter: event processing priority, set to 0 for lowest latency + +- compatible + Usage: required + Value type: + Definition: "qcom,gpi-dma" + +- reg + Usage: required + Value type: Array of + Definition: register address space location and size + +- reg-name + Usage: required + Value type: + Definition: register space name, must be "gpi-top" + +- interrupts + Usage: required + Value type: Array of + Definition: Array of tuples which describe interrupt line for each GPII + instance. + +- qcom,max-num-gpii + Usage: required + Value type: + Definition: Total number of GPII instances available for this controller. + +- qcom,gpii-mask + Usage: required + Value type: + Definition: Bitmap of supported GPII instances in hlos. + +- qcom,ev-factor + Usage: required + Value type: + Definition: Event ring transfer size compare to channel transfer ring. Event + ring length = ev-factor * transfer ring size + +- iommus + Usage: required + Value type: + Definition: phandle for apps smmu controller and SID, and mask + for the controller. For more detail please check binding + documentation arm,smmu.txt + +- qcom,smmu-cfg + Usage: required + Value type: + Definition: Determine whether GPI driver require to configure SMMU that + sits behind GPI controller. + Bit mask: + BIT(0) : Attach address mapping to endpoint device + BIT(1) : Set SMMU attribute S1_BYPASS + BIT(2) : Set SMMU attribute FAST + BIT(3) : Set SMMU attribute ATOMIC + +- qcom,iova-range + Usage: required if SMMU S1 translation is enabled + Value type: Array of + Definition: Pair of values describing iova base and size to allocate. + +======== +Example: +======== +gpi_dma0: qcom,gpi-dma@0x800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, + <0 252 0>, <0 253 0>, <0 254 0>, <0 255 0>, + <0 256 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x0016 0x0>; + qcom,smmu-cfg = <0x1> + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; +}; diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 3e7fcb7924d3fcfd11325a861140950240147ed8..806c45823205d9e5ec9b75995bb8d8d4ea281f51 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -35,7 +35,7 @@ Required properties: - qcom,mdss-dsi-panel-destination: A string that specifies the destination display for the panel. "display_1" = DISPLAY_1 "display_2" = DISPLAY_2 -- qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY +- qcom,mdss-dsi-panel-phy-timings: An array of length 12 that specifies the PHY timing settings for the panel. - qcom,mdss-dsi-panel-timings-8996: An array of length 40 char that specifies the 8996 PHY lane timing settings for the panel. @@ -144,10 +144,11 @@ Optional properties: 0xff = default value. - qcom,mdss-dsi-border-color: Defines the border color value if border is present. 0 = default value. -- qcom,mdss-dsi-panel-jitter: An integer value defines the panel jitter timing for rsc - backoff time. The jitter configurition causes the early - wakeup if panel needs to adjust before vsync. - Default jitter value is 5%. Max allowed value is 25%. +- qcom,mdss-dsi-panel-jitter: Panel jitter value is expressed in terms of numerator + and denominator. It contains two u32 values - numerator + followed by denominator. The jitter configurition causes + the early wakeup if panel needs to adjust before vsync. + Default jitter value is 2.0%. Max allowed value is 10%. - qcom,mdss-dsi-panel-prefill-lines: An integer value defines the panel prefill lines required to calculate the backoff time of rsc. Default value is 16 lines. Max allowed value is vtotal. @@ -193,6 +194,8 @@ Optional properties: "dsi_cmd_mode" = enable command mode. - qcom,5v-boost-gpio: Specifies the panel gpio for display 5v boost. - qcom,mdss-dsi-te-check-enable: Boolean to enable Tear Check configuration. +- qcom,mdss-dsi-te-using-wd: Boolean entry enables the watchdog timer support to generate the vsync signal + for command mode panel. By default, panel TE will be used to generate the vsync. - qcom,mdss-dsi-te-using-te-pin: Boolean to specify whether using hardware vsync. - qcom,mdss-dsi-te-pin-select: Specifies TE operating mode. 0 = TE through embedded dcs command @@ -331,14 +334,21 @@ Optional properties: as below: --> Reset GPIO value --> Sleep value (in ms) -- qcom,partial-update-enabled: Boolean used to enable partial +- qcom,partial-update-enabled: String used to enable partial panel update for command mode panels. + "none": partial update is disabled + "single_roi": default enable mode, only single roi is sent to panel + "dual_roi": two rois are merged into one big roi. Panel ddic should be able + to process two roi's along with the DCS command to send two rois. + disabled if property is not specified. This property is specified + per timing node to support resolution restrictions. - qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating additional idle time in dsi clock cycles that is needed to compensate for smaller line width. - qcom,partial-update-roi-merge: Boolean indicates roi combination is need and function has been provided for dcs - 2A/2B command. + 2A/2B command. This property is specified per timing node to support + resolution restrictions. - qcom,dcs-cmd-by-left: Boolean to indicate that dcs command are sent through the left DSI controller only in a dual-dsi configuration - qcom,mdss-dsi-panel-hdr-enabled: Boolean to indicate HDR support in panel. @@ -375,7 +385,8 @@ Optional properties: - qcom,suspend-ulps-enabled: Boolean to enable support for ULPS mode for panels during suspend state. - qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its left, top, width, height alignments and minimum width and - height values + height values. This property is specified per timing node to support + resolution's alignment restrictions. - qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. - qcom,mdss-dsi-panel-status-command: A byte stream formed by multiple dcs packets based on qcom dsi controller protocol, to read the panel status. @@ -393,6 +404,24 @@ Optional properties: String that specifies the ctrl state for reading the panel status. "dsi_lp_mode" = DSI low power mode "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-lp1-command: An optional byte stream to request low + power mode on a panel +- qcom,mdss-dsi-lp1-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-lp2-command: An optional byte stream to request ultra + low power mode on a panel +- qcom,mdss-dsi-lp2-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-nolp-command: An optional byte stream to disable low + power and ultra low power panel modes +- qcom,mdss-dsi-nolp-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode - qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. "bta_check" = Uses BTA to check the panel status "reg_read" = Reads panel status register to check the panel status @@ -456,28 +485,6 @@ Optional properties: with the supply entry index. For a detailed description of fields in the supply entry, refer to the qcom,ctrl-supply-entries binding above. -- qcom,config-select: Optional property to select default configuration. - -[[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel. - Default configuration can be chosen by specifying phandle of the - selected subnode in the qcom,config-select. -Required properties for sub-nodes: None -Optional properites: -- qcom,lm-split: An array of two values indicating MDP should use two layer - mixers to reduce power. - Ex: Normally 1080x1920 display uses single DSI and thus one layer - mixer. But if we use two layer mixers then mux the output of - those two mixers into single stream and route it to single DSI - then we can lower the clock requirements of MDP. To use this - configuration we need two fill this array with <540 540>. - Both values doesn't have to be same, but recommended, however sum of - both values has to be equal to the panel-width. - By default two mixer streams are merged using 2D mux, however if - 2 DSC encoders are used then merge is performed within compression - engine. -- qcom,split-mode: String property indicating which split mode MDP should use. Valid - entries are "pingpong-split" and "dualctl-split". - This property is mutually exclusive with qcom,lm-split. - qcom,mdss-dsc-version: An 8 bit value indicates the DSC version supported by panel. Bits[0.3] provides information about minor version while Bits[4.7] provides major version information. It supports only DSC rev 1(Major).1(Minor) @@ -500,6 +507,21 @@ Optional properites: - qcom,mdss-dsc-block-prediction-enable: A boolean value to enable/disable the block prediction at decoder. - qcom,mdss-dsc-config-by-manufacture-cmd: A boolean to indicates panel use manufacture command to setup pps instead of standard dcs type 0x0A. +- qcom,display-topology: Array of u32 values which specifies the list of topologies available + for the display. A display topology is defined by a + set of 3 values in the order: + - number of mixers + - number of compression encoders + - number of interfaces + Therefore, the array should always contain a tuple of 3 elements. +- qcom,default-topology-index: An u32 value which indexes the topology set + specified by the node "qcom,display-topology" + to identify the default topology for the + display. The first set is indexed by the + value 0. + +Required properties for sub-nodes: None +Optional properties: - qcom,dba-panel: Indicates whether the current panel is used as a display bridge to a non-DSI interface. - qcom,bridge-name: A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name @@ -575,6 +597,7 @@ Example: qcom,mdss-dsi-interleave-mode = <0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; qcom,mdss-dsi-te-using-te-pin; qcom,mdss-dsi-te-dcs-command = <1>; qcom,mdss-dsi-wr-mem-continue = <0x3c>; @@ -634,7 +657,6 @@ Example: qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; qcom,mdss-tear-check-frame-rate = <6000>; qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; - qcom,partial-update-enabled; qcom,dcs-cmd-by-left; qcom,mdss-dsi-lp11-init; qcom,mdss-dsi-init-delay-us = <100>; @@ -642,7 +664,6 @@ Example: mdss-dsi-tx-eot-append; qcom,ulps-enabled; qcom,suspend-ulps-enabled; - qcom,panel-roi-alignment = <4 4 2 2 20 20>; qcom,esd-check-enabled; qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; @@ -663,7 +684,7 @@ Example: <40 120 128>, <128 240 64>; qcom,mdss-dsi-panel-orientation = "180" - qcom,mdss-dsi-panel-jitter = <0x8>; + qcom,mdss-dsi-panel-jitter = <0x8 0x10>; qcom,mdss-dsi-panel-prefill-lines = <0x10>; qcom,mdss-dsi-force-clock-lane-hs; qcom,compression-mode = "dsc"; @@ -692,18 +713,17 @@ Example: 29 00 00 00 00 00 02 F1 00]; qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode"; - qcom,config-select = <&dsi_sim_vid_config0>; - dsi_sim_vid_config0: config0 { - qcom,lm-split = <360 360>; - qcom,mdss-dsc-encoders = <2>; - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <360>; - qcom,mdss-dsc-slice-per-pkt = <2>; - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - qcom,mdss-dsc-config-by-manufacture-cmd; - }; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <4 4 2 2 20 20>; }; }; qcom,panel-supply-entries { @@ -737,41 +757,19 @@ Example: }; }; - qcom,config-select = <&dsi_sim_vid_config0>; qcom,dba-panel; qcom,bridge-name = "adv7533"; qcom,mdss-dsc-version = <0x11>; qcom,mdss-dsc-scr-version = <0x1>; - - dsi_sim_vid_config0: config0 { - qcom,lm-split = <360 360>; - qcom,mdss-dsc-encoders = <2>; - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <360>; - qcom,mdss-dsc-slice-per-pkt = <2>; - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - qcom,mdss-dsc-config-by-manufacture-cmd; - }; - - dsi_sim_vid_config1: config1 { - qcom,mdss-dsc-encoders = <1>; - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <360>; - qcom,mdss-dsc-slice-per-pkt = <2>; - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - qcom,mdss-dsc-config-by-manufacture-cmd; - }; - - dsi_sim_vid_config2: config2 { - qcom,split-mode = "dualctl-split"; - }; - - dsi_sim_vid_config3: config3 { - qcom,split-mode = "pingpong-split"; - }; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <0>; }; }; diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt new file mode 100644 index 0000000000000000000000000000000000000000..ada2eab37e3ec57ba48868e8f450ac65b9bbba9a --- /dev/null +++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt @@ -0,0 +1,217 @@ +Qualcomm Technologies, Inc. +sde-dp is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification. +DP Controller: Required properties: +- compatible: Should be "qcom,dp-display". +- reg: Base address and length of DP hardware's memory mapped regions. +- reg-names: A list of strings that name the list of regs. "dp_ctrl" - DP controller memory region. + "dp_phy" - DP PHY memory region. + "dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region. + "dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region. + "dp_mmss_cc" - Display Clock Control memory region. + "qfprom_physical" - QFPROM Phys memory region. + "dp_pll" - USB3 DP combo PLL memory region. + "usb3_dp_com" - USB3 DP PHY combo memory region. + "hdcp_physical" - DP HDCP memory region. +- cell-index: Specifies the controller instance. +- clocks: Clocks required for Display Port operation. +- clock-names: Names of the clocks corresponding to handles. Following clocks are required: + "core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent". +- gdsc-supply: phandle to gdsc regulator node. +- vdda-1p2-supply: phandle to vdda 1.2V regulator node. +- vdda-0p9-supply: phandle to vdda 0.9V regulator node. +- interrupt-parent phandle to the interrupt parent device node. +- interrupts: The interrupt signal from the DSI block. +- qcom,aux-en-gpio: Specifies the aux-channel enable gpio. +- qcom,aux-sel-gpio: Specifies the aux-channel select gpio. +- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio. +- qcom,aux-cfg0-settings: Specifies the DP AUX configuration 0 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg1-settings: Specifies the DP AUX configuration 1 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg2-settings: Specifies the DP AUX configuration 2 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg3-settings: Specifies the DP AUX configuration 3 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg4-settings: Specifies the DP AUX configuration 4 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg5-settings: Specifies the DP AUX configuration 5 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg6-settings: Specifies the DP AUX configuration 6 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg7-settings: Specifies the DP AUX configuration 7 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg8-settings: Specifies the DP AUX configuration 8 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg9-settings: Specifies the DP AUX configuration 9 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port. +- qcom,dp-usbpd-detection: Phandle for the PMI regulator node for USB PHY PD detection. +- qcom,-supply-entries: A node that lists the elements of the supply used by the a particular "type" of DSI module. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt + +msm_ext_disp is a device which manages the interaction between external +display interfaces, e.g. Display Port, and the audio subsystem. + +Optional properties: +- qcom,ext-disp: phandle for msm-ext-display module +- compatible: Must be "qcom,msm-ext-disp" + +[Optional child nodes]: These nodes are for devices which are +dependent on msm_ext_disp. If msm_ext_disp is disabled then +these devices will be disabled as well. Ex. Audio Codec device. + +- ext_disp_audio_codec: Node for Audio Codec. +- compatible : "qcom,msm-ext-disp-audio-codec-rx"; + +Example: + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + gdsc-supply = <&mdss_core_gdsc>; + vdda-1p2-supply = <&pm8998_l26>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xae90000 0xa84>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea030 0x10>, + <0x88e8000 0x621c>, + <0x0aee1000 0x034>; + reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,dp-usbpd-detection = <&pmi8998_pdphy>; + qcom,ext-disp = <&ext_disp>; + + qcom,aux-cfg0-settings = [1c 00]; + qcom,aux-cfg1-settings = [20 13 23 1d]; + qcom,aux-cfg2-settings = [24 00]; + qcom,aux-cfg3-settings = [28 00]; + qcom,aux-cfg4-settings = [2c 0a]; + qcom,aux-cfg5-settings = [30 26]; + qcom,aux-cfg6-settings = [34 0a]; + qcom,aux-cfg7-settings = [38 03]; + qcom,aux-cfg8-settings = [3c bb]; + qcom,aux-cfg9-settings = [40 03]; + qcom,max-pclk-frequency-khz = <593470>; + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 43 0>; + qcom,aux-sel-gpio = <&tlmm 51 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt index 3ad0986cc8c1c522ee816c04a613d18a9f285c67..a89b83482883fec89286cd1415b5e3309afdf34d 100644 --- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt +++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt @@ -96,3 +96,8 @@ Optional properties: If ping pong split enabled, this time should not be higher than two times the dsi link rate time. If the property is not specified, then the default value is 14000 us. +- qcom,dsi-phy-isolation-enabled: A boolean property enables the phy isolation from dsi + controller. This must be enabled for debugging purpose + only with simulator panel. It should not be enabled for + normal DSI panels. +- - qcom,null-insertion-enabled: A boolean to enable NULL packet insertion feature for DSI controller. diff --git a/Documentation/devicetree/bindings/extcon/extcon-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b3a1d2d42d6021dd09ad33c9c45e600556e4745 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/extcon-gpio.txt @@ -0,0 +1,32 @@ +GPIO Extcon device + +This is a virtual device used to generate USB cable states from the USB ID pin +connected to a GPIO pin. + +Required properties: +- compatible: Should be "extcon-gpio" +- extcon-id: The unique id of specific external connector. + Valid range is 0 (EXTCON_NONE) to 63 (EXTCON_NUM). + Refer include/linux/extcon.h for details. +- gpio: Specify GPIO (see gpio binding) +- debounce-ms: Debounce time for GPIO IRQ in ms +- irq-flags: interrupt flags (edge/level). Refer to "include/dt-bindings/interrupt-controller/irq.h" +- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + for these optional properties + +Example: + extcon_storage_cd { + compatible = "extcon-gpio"; + extcon-id = <62>; /* EXTCON_MECHANICAL */ + gpio = <&tlmm 126 GPIO_ACTIVE_LOW>; + debounce-ms = <200>; + irq-flags = ; + } + + &ufshc_card { + extcon = <&extcon_storage_cd>; + }; + + &sd_card { + extcon = <&extcon_storage_cd>; + }; diff --git a/Documentation/devicetree/bindings/fb/adv7533.txt b/Documentation/devicetree/bindings/fb/adv7533.txt new file mode 100644 index 0000000000000000000000000000000000000000..b198f37f8fc610ad8bb77c7110fed95008e85cdc --- /dev/null +++ b/Documentation/devicetree/bindings/fb/adv7533.txt @@ -0,0 +1,54 @@ +ADV7533 DSI to HDMI bridge + + +Required properties: +- compatible: Must be "adv7533" +- reg: Main I2C slave ID (for I2C host driver) +- adi,video-mode: Excepted a number and possible inputs are 0 to 3, while: + 3 = 1080p + 2 = 720p + 1 = 480p + 0 = 1080p pattern +- adi,main-addr: Main I2C slave ID +- adi,cec-dsi-addr: CEC DSI I2C slave ID + +Optional properties: +- adi,enable-audio: +- adi,disable-gpios: +- adi,irq-gpio: Main IRQ gpio mapping +- adi,hpd-irq-gpio: HPD IRQ gpio mapping +- adi,switch-gpio: DSI switch gpio mapping +- qcom,supply-names: Regulator names that supply 5v to bridge chip +- qcom,min-voltage-level Minimum voltage level to be supplied to bridge chip +- qcom,max-voltage-level Maximum voltage level to be supplied to bridge chip +- qcom,enable-load Load current to bridge chip when enabled +- qcom,disable-load Load current to bridge chip when disabled +- qcom,post-on-sleep Sleep time (ms) to indicate the sleep + time after the vreg is enabled + +Example: +&soc { + i2c@78b8000 { + adv7533@39 { + compatible = "adv7533"; + reg = <0x39>; + adi,video-mode = <3>; /* 3 = 1080p */ + adi,main-addr = <0x39>; + adi,cec-dsi-addr = <0x3C>; + adi,enable-audio; + pinctrl-names = "pmx_adv7533_active","pmx_adv7533_suspend"; + pinctrl-0 = <&adv7533_int_active &adv7533_hpd_int_active &adv7533_switch_active>; + pinctrl-1 = <&adv7533_int_suspend &adv7533_hpd_int_suspend &adv7533_switch_suspend>; + adi,irq-gpio = <&msm_gpio 31 0x2002>; + adi,hpd-irq-gpio = <&msm_gpio 20 0x2003>; + adi,switch-gpio = <&msm_gpio 32 0x0>; + hpd-5v-en-supply = <&adv_vreg>; + qcom,supply-names = "hpd-5v-en"; + qcom,min-voltage-level = <0>; + qcom,max-voltage-level = <0>; + qcom,enable-load = <0>; + qcom,disable-load = <0>; + qcom,post-on-sleep = <10>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/lt8912.txt b/Documentation/devicetree/bindings/fb/lt8912.txt new file mode 100644 index 0000000000000000000000000000000000000000..daeb15fe3ab555c2de51d733487b84ce98957391 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/lt8912.txt @@ -0,0 +1,20 @@ +LT8912 DSI to HDMI bridge + + +Required properties: +- compatible: Must be "lontium,lt8912" +- reg: Main I2C slave ID (for I2C host driver) + +Optional properties: +- qcom,hdmi-reset: Main reset gpio mapping + +Example: +&soc { + i2c@78b8000 { + lt8912@48 { + compatible = "lontium,lt8912"; + reg = <0x48>; + qcom,hdmi-reset = <&tlmm 64 0x0>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 608b4260a0ab6182c568a3f2196c358ce9efef6d..493a1aa5efba18e290fd7d7a4be9d519dd2a6751 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -12,6 +12,7 @@ Required properties: This property specifies the version for DSI HW that this panel will work with "qcom,dsi-panel-v2" = DSI V2.0 + "qcom,msm-dsi-v2" = DSI V2.0 - status: This property applies to DSI V2 panels only. This property should not be added for panels that work based on version "V6.0" @@ -37,8 +38,8 @@ Required properties: "display_2" = DISPLAY_2 - qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY timing settings for the panel. -- qcom,mdss-dsi-panel-timings-8996: An array of length 40 char that specifies the 8996 PHY lane - timing settings for the panel. +- qcom,mdss-dsi-panel-timings-phy-v2: An array of length 40 char that specifies the PHY version 2 + lane timing settings for the panel. - qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on qcom dsi controller protocol. byte 0: dcs data type @@ -61,9 +62,39 @@ Required properties: transmitted byte 5, 6: 16 bits length in network byte order byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-on: This is used to enable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-off: This is used to disable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload - qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are sent after displaying an image. +- qcom,mdss-dsi-idle-on-command: same as "qcom,mdss-dsi-on-command". Set of DCS command + used for idle mode entry. + +- qcom,mdss-dsi-idle-off-command: same as "qcom,mdss-dsi-on-command". Set of DCS command + used for idle mode exit. + Note, if a short DCS packet(i.e packet with Byte 0:dcs data type as 05) mentioned in qcom,mdss-dsi-on-command/qcom,mdss-dsi-off-command stream fails to transmit, then 3 options can be tried. @@ -275,14 +306,10 @@ Optional properties: to the physical width in the framebuffer information. - qcom,mdss-pan-physical-height-dimension: Specifies panel physical height in mm which corresponds to the physical height in the framebuffer information. -- qcom,mdss-dsi-mode-sel-gpio-state: String that specifies the lcd mode for panel - (such as single-port/dual-port), if qcom,panel-mode-gpio - binding is defined in dsi controller. - "dual_port" = Set GPIO to LOW - "single_port" = Set GPIO to HIGH +- qcom,mdss-dsi-panel-mode-gpio-state: String that specifies the mode state for panel if it is defined + in dsi controller. "high" = Set GPIO to HIGH "low" = Set GPIO to LOW - The default value is "dual_port". - qcom,mdss-tear-check-disable: Boolean to disable mdp tear check. Tear check is enabled by default to avoid tearing. Other tear-check properties are ignored if this property is present. The below tear check configuration properties can be individually tuned if @@ -330,6 +357,28 @@ Optional properties: 2A/2B command. - qcom,dcs-cmd-by-left: Boolean to indicate that dcs command are sent through the left DSI controller only in a dual-dsi configuration +- qcom,mdss-dsi-panel-hdr-enabled: Boolean to indicate HDR support in panel. +- qcom,mdss-dsi-panel-hdr-color-primaries: + Array of 8 unsigned integers denoting chromaticity of panel.These + values are specified in nits units. The value range is 0 through 50000. + To obtain real chromacity, these values should be divided by factor of + 50000. The structure of array is defined in below order + value 1: x value of white chromaticity of display panel + value 2: y value of white chromaticity of display panel + value 3: x value of red chromaticity of display panel + value 4: y value of red chromaticity of display panel + value 5: x value of green chromaticity of display panel + value 6: y value of green chromaticity of display panel + value 7: x value of blue chromaticity of display panel + value 8: y value of blue chromaticity of display panel +- qcom,mdss-dsi-panel-peak-brightness: Maximum brightness supported by panel.In absence of maximum value + typical value becomes peak brightness. Value is specified in nits units. + To obtail real peak brightness, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-panel-blackness-level: Blackness level supported by panel. Blackness level is defined as + ratio of peak brightness to contrast. Value is specified in nits units. + To obtail real blackness level, this value should be divided by factor of + 10000. - qcom,mdss-dsi-lp11-init: Boolean used to enable the DSI clocks and data lanes (low power 11) before issuing hardware reset line. - qcom,mdss-dsi-init-delay-us: Delay in microseconds(us) before performing any DSI activity in lp11 @@ -424,7 +473,11 @@ Optional properties: fields in the supply entry, refer to the qcom,ctrl-supply-entries binding above. - qcom,config-select: Optional property to select default configuration. - +- qcom,panel-allow-phy-poweroff: A boolean property indicates that panel allows to turn off the phy power + supply during idle screen. A panel should able to handle the dsi lanes + in floating state(not LP00 or LP11) to turn on this property. Software + turns off PHY pmic power supply, phy ldo and DSI Lane ldo during + idle screen (footswitch control off) when this property is enabled. [[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel. Default configuration can be chosen by specifying phandle of the selected subnode in the qcom,config-select. @@ -471,6 +524,7 @@ Optional properites: to a non-DSI interface. - qcom,bridge-name: A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name is required if qcom,dba-panel is defined for the panel. +- qcom,hdmi-mode: Indicates where current panel is HDMI mode, otherwise, it will be DVI mode. - qcom,adjust-timer-wakeup-ms: An integer value to indicate the timer delay(in ms) to accommodate s/w delay while configuring the event timer wakeup logic. @@ -493,6 +547,8 @@ Additional properties added to the second level nodes that represent timings pro Note, if a given optional qcom,* binding is not present, then the driver will configure the default values specified. +Note, all the "qcom,supply-*" properties have their definitions in mdss-dsi-txt. + Example: &mdss_mdp { dsi_sim_vid: qcom,mdss_dsi_sim_video { @@ -538,7 +594,6 @@ Example: qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = < 15>; - qcom,mdss-brightness-max-level = <255>; qcom,mdss-dsi-interleave-mode = <0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-te-check-enable; @@ -571,7 +626,7 @@ Example: qcom,mdss-mdp-transfer-time-us = <12500>; qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 22 27 1e 03 04 00]; - qcom,mdss-dsi-panel-timings-8996 = [23 20 06 09 05 03 04 a0 + qcom,mdss-dsi-panel-timings-phy-v2 = [23 20 06 09 05 03 04 a0 23 20 06 09 05 03 04 a0 23 20 06 09 05 03 04 a0 23 20 06 09 05 03 04 a0 @@ -581,6 +636,9 @@ Example: qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp-mode-on = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-lp-mode-off = [22 01 00 00 00 00 00]; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; @@ -592,7 +650,7 @@ Example: qcom,5v-boost-gpio = <&pm8994_gpios 14 0>; qcom,mdss-pan-physical-width-dimension = <60>; qcom,mdss-pan-physical-height-dimension = <140>; - qcom,mdss-dsi-mode-sel-gpio-state = "dsc_mode"; + qcom,mdss-dsi-panel-mode-gpio-state = "low"; qcom,mdss-tear-check-sync-cfg-height = <0xfff0>; qcom,mdss-tear-check-sync-init-val = <1280>; qcom,mdss-tear-check-sync-threshold-start = <4>; @@ -611,6 +669,7 @@ Example: qcom,suspend-ulps-enabled; qcom,panel-roi-alignment = <4 4 2 2 20 20>; qcom,esd-check-enabled; + qcom,panel-allow-phy-poweroff; qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; @@ -682,6 +741,7 @@ Example: qcom,supply-max-voltage = <2800000>; qcom,supply-enable-load = <100000>; qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; qcom,supply-pre-on-sleep = <0>; qcom,supply-post-on-sleep = <0>; qcom,supply-pre-off-sleep = <0>; @@ -695,6 +755,7 @@ Example: qcom,supply-max-voltage = <1800000>; qcom,supply-enable-load = <100000>; qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; qcom,supply-pre-on-sleep = <0>; qcom,supply-post-on-sleep = <0>; qcom,supply-pre-off-sleep = <0>; diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f74f7feddcdd3b9e38c66a4796139247eea3dce --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt @@ -0,0 +1,261 @@ +Qualcomm mdss-dsi + +mdss-dsi is the master DSI device which supports multiple DSI host controllers that +are compatible with MIPI display serial interface specification. + +Required properties: +- compatible: Must be "qcom,mdss-dsi" +- hw-config: Specifies the DSI host setup configuration + "hw-config" = "single_dsi" + "hw-config" = "dual_dsi" + "hw-config" = "split_dsi" +- ranges: The standard property which specifies the child address + space, parent address space and the length. +- vdda-supply: Phandle for vreg regulator device node. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom, msm-bus,num-cases: This is the number of bus scaling use cases + defined in the vectors property. This must be + set to <2> for MDSS DSI driver where use-case 0 + is used to remove BW votes from the system. Use + case 1 is used to generate bandwidth requestes + when sending command packets. +- qcom,msm-bus,num-paths: This represents number of paths in each bus + scaling usecase. This value depends on number of + AXI master ports dedicated to MDSS for + particular chipset. +- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt. + DSI driver should always set average bandwidth + (ab) to 0 and always use instantaneous + bandwidth(ib) values. + +Optional properties: +- vcca-supply: Phandle for vcca regulator device node. +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI modulee. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- pll-src-config Specified the source PLL for the DSI + link clocks: + "PLL0" - Clocks sourced out of DSI PLL0 + "PLL1" - Clocks sourced out of DSI PLL1 + This property is only valid for + certain DSI hardware configurations + mentioned in the "hw-config" binding above. + For example, in split_dsi config, the clocks can + only be sourced out of PLL0. For + dual_dsi, both PLL would be active. + For single DSI, it is possible to + select either PLL. If no value is specified, + the default value for single DSI is set as PLL0. +- qcom,mmss-ulp-clamp-ctrl-offset: Specifies the offset for dsi ulps clamp control register. +- qcom,mmss-phyreset-ctrl-offset: Specifies the offset for dsi phy reset control register. +- qcom,dsi-clk-ln-recovery: Boolean which enables the clk lane recovery + +mdss-dsi-ctrl is a dsi controller device which is treated as a subnode of the mdss-dsi device. + +Required properties: +- compatible: Must be "qcom,mdss-dsi-ctrl" +- cell-index: Specifies the controller used among the two controllers. +- reg: Base address and length of the different register + regions(s) required for DSI device functionality. +- reg-names: A list of strings that map in order to the list of regs. + "dsi_ctrl" - MDSS DSI controller register region + "dsi_phy" - MDSS DSI PHY register region + "dsi_phy_regulator" - MDSS DSI PHY REGULATOR region + "mmss_misc_phys" - Register region for MMSS DSI clamps +- vdd-supply: Phandle for vdd regulator device node. +- vddio-supply: Phandle for vdd-io regulator device node. +- qcom,mdss-fb-map-prim: pHandle that specifies the framebuffer to which the + primary interface is mapped. +- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. +- qcom,platform-regulator-settings: An array of length 7 or 5 that specifies the PHY + regulator settings. It use 5 bytes for 8996 pll. +- qcom,platform-strength-ctrl: An array of length 2 or 10 that specifies the PHY + strengthCtrl settings. It use 10 bytes for 8996 pll. +- qcom,platform-lane-config: An array of length 45 or 20 that specifies the PHY + lane configuration settings. It use 20 bytes for 8996 pll. +- qcom,platform-bist-ctrl: An array of length 6 that specifies the PHY + BIST ctrl settings. +- qcom,dsi-pref-prim-pan: phandle that specifies the primary panel to be used + with the controller. + +Optional properties: +- label: A string used to describe the controller used. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- qcom,mdss-fb-map-sec: pHandle that specifies the framebuffer to which the + secondary interface is mapped. +- qcom,platform-enable-gpio: Specifies the panel lcd/display enable gpio. +- qcom,platform-reset-gpio: Specifies the panel reset gpio. +- qcom,platform-te-gpio: Specifies the gpio used for TE. +- qcom,platform-bklight-en-gpio: Specifies the gpio used to enable display back-light +- qcom,platform-mode-gpio: Select video/command mode of panel through gpio when it supports + both modes. +- qcom,platform-intf-mux-gpio: Select dsi/external(hdmi) interface through gpio when it supports + either dsi or external interface. +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt +- qcom,regulator-ldo-mode: Boolean to enable ldo mode for the dsi phy regulator +- qcom,null-insertion-enabled: Boolean to enable NULL packet insertion + feature for DSI controller. +- qcom,dsi-irq-line: Boolean specifies if DSI has a different irq line than mdp. +- qcom,lane-map: Specifies the data lane swap configuration. + "lane_map_0123" = <0 1 2 3> (default value) + "lane_map_3012" = <3 0 1 2> + "lane_map_2301" = <2 3 0 1> + "lane_map_1230" = <1 2 3 0> + "lane_map_0321" = <0 3 2 1> + "lane_map_1032" = <1 0 3 2> + "lane_map_2103" = <2 1 0 3> + "lane_map_3210" = <3 2 1 0> +- qcom,pluggable Boolean to enable hotplug feature. +- qcom,timing-db-mode: Boolean specifies dsi timing mode registers are supported or not. +- qcom,display-id A string indicates the display ID for the controller. + The possible values are: + - "primary" + - "secondary" + - "tertiary" +- qcom,bridge-index: Instance id of the bridge chip connected to DSI. qcom,bridge-index is + required if a bridge chip panel is used. + +Example: + mdss_dsi: qcom,mdss_dsi@0 { + compatible = "qcom,mdss-dsi"; + hw-config = "single_dsi"; + pll-src-config = "PLL0"; + #address-cells = <1>; + #size-cells = <1>; + vdda-supply = <&pm8226_l4>; + vcca-supply = <&pm8226_l28>; + reg = <0x1a98000 0x1a98000 0x25c + 0x1a98500 0x1a98500 0x280 + 0x1a98780 0x1a98780 0x30 + 0x193e000 0x193e000 0x30>; + + qcom,dsi-clk-ln-recovery; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + qcom,supply-ulp-load = <0>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <1000>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + mdss_dsi0: mdss_dsi_ctrl0@fd922800 { + compatible = "qcom,mdss-dsi-ctrl"; + label = "MDSS DSI CTRL->0"; + cell-index = <0>; + reg = <0xfd922800 0x1f8>, + <0xfd922b00 0x2b0>, + <0xfd998780 0x30>, + <0xfd828000 0x108>; + reg-names = "dsi_ctrl", "dsi_phy", + "dsi_phy_regulator", "mmss_misc_phys"; + + vdd-supply = <&pm8226_l15>; + vddio-supply = <&pm8226_l8>; + qcom,mdss-fb-map-prim = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + + qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>; + + qcom,platform-strength-ctrl = [ff 06]; + qcom,platform-bist-ctrl = [00 00 b1 ff 00 00]; + qcom,platform-regulator-settings = [07 09 03 00 20 00 01]; + qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97 + 00 00 00 00 05 00 00 01 97 + 00 00 00 00 0a 00 00 01 97 + 00 00 00 00 0f 00 00 01 97 + 00 c0 00 00 00 00 00 01 bb]; + + qcom,mmss-ulp-clamp-ctrl-offset = <0x20>; + qcom,mmss-phyreset-ctrl-offset = <0x24>; + qcom,regulator-ldo-mode; + qcom,null-insertion-enabled; + qcom,timing-db-mode; + + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active>; + pinctrl-1 = <&mdss_dsi_suspend>; + qcom,platform-reset-gpio = <&msmgpio 25 1>; + qcom,platform-te-gpio = <&msmgpio 24 0>; + qcom,platform-enable-gpio = <&msmgpio 58 1>; + qcom,platform-bklight-en-gpio = <&msmgpio 86 0>; + qcom,platform-mode-gpio = <&msmgpio 7 0>; + qcom,platform-intf-mux-gpio = <&tlmm 115 0>; + qcom,dsi-irq-line; + qcom,lane-map = "lane_map_3012"; + qcom,display-id = "primary"; + qcom,bridge-index = <00>; + }; + }; diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt new file mode 100644 index 0000000000000000000000000000000000000000..c474b88c97ea31dbdc3cdc637931c0db921c177d --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt @@ -0,0 +1,52 @@ +Qualcomm MDSS EDP + +MDSS EDP is a edp driver which supports panels that are compatible with +VESA EDP display interface specification. + +When configuring the optional properties for external backlight, one should also +configure the gpio that drives the pwm to it. + +Required properties +- compatible : Must be "qcom,mdss-edp". +- reg : Offset and length of the register set for the + device. +- reg-names : Names to refer to register sets related to this + device +- vdda-supply : Phandle for vdd regulator device node. +- gpio-panel-en : GPIO for supplying power to panel and backlight + driver. +- gpio-lvl-en : GPIO to enable HPD be received by host. +- status : A string that has to be set to "okay/ok" to enable + the driver. By default this property will be set to + "disable". Will be set to "ok/okay" status for + specific platforms. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- gpio-panel-hpd : gpio pin use for edp hpd + +Optional properties +- qcom,panel-lpg-channel : LPG channel for backlight. +- qcom,panel-pwm-period : PWM period in microseconds. + + +Optional properties: +- qcom,mdss-brightness-max-level: Specifies the max brightness level supported. + 255 = default value. + +Example: + mdss_edp: qcom,mdss_edp@fd923400 { + compatible = "qcom,mdss-edp"; + reg = <0xfd923400 0x700>, + <0xfd8c2000 0x1000>; + reg-names = "edp_base", "mmss_cc_base"; + vdda-supply = <&pm8941_l12>; + gpio-panel-en = <&msmgpio 58 0>; + gpio-lvl-en = <&msmgpio 91 0>; + qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */ + qcom,panel-pwm-period = <53>; + status = "disable"; + qcom,mdss-fb-map = <&mdss_fb0>; + gpio-panel-hpd = <&msmgpio 102 0>; + }; + + diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt new file mode 100644 index 0000000000000000000000000000000000000000..e33d358f7c821013f4367ba338050e3ecb6a5894 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt @@ -0,0 +1,898 @@ +Qualcomm MDSS MDP + +MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to +drive user interface to different panel interfaces. MDP driver is the core of +MDSS which manage all data paths to different panel interfaces. + +Required properties +- compatible : Must be "qcom,mdss_mdp" + - "qcom,mdss_mdp3" for mdp3 +- reg : offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- interrupts : Interrupt associated with MDSS. +- interrupt-controller: Mark the device node as an interrupt controller. + This is an empty, boolean property. +- #interrupt-cells: Should be one. The first cell is interrupt number. +- vdd-supply : Phandle for vdd regulator device node. +- qcom,max-clk-rate: Specify maximum MDP core clock rate in hz that this + device supports. +- qcom,mdss-pipe-vig-off: Array of offset for MDP source surface pipes of + type VIG, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of VIG pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-vig-fetch-id: Array of shared memory pool fetch ids + corresponding to the VIG pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective VIG pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-off: Array of offsets for MDP source surface pipes of + type RGB, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of RGB pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-rgb-fetch-id: Array of shared memory pool fetch ids + corresponding to the RGB pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective RGB pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-off: Array of offsets for MDP source surface pipes of + type DMA, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of DMA pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-dma-fetch-id: Array of shared memory pool fetch ids + corresponding to the DMA pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective DMA pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-cursor-off: Array of offsets for MDP source surface pipes of + type cursor, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of cursor pipes that can be + active in MDP for this configuration. Meant for + hardware that has hw cursors support as a + source pipe. +- qcom,mdss-pipe-cursor-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective cursor pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-cursor-off +- qcom,mdss-pipe-cursor-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-cursor-off +- qcom,mdss-ctl-off: Array of offset addresses for the available ctl + hw blocks within MDP, these offsets are + calculated from register "mdp_phys" defined in + reg property. The number of ctl offsets defined + here should reflect the number of control paths + that can be configured concurrently on MDP for + this configuration. +- qcom,mdss-wb-off: Array of offset addresses for the progammable + writeback blocks within MDP. The number of + offsets defined should match the number of ctl + blocks defined in property: qcom,mdss-ctl-off +- qcom,mdss-mixer-intf-off: Array of offset addresses for the available + mixer blocks that can drive data to panel + interfaces. + These offsets are be calculated from register + "mdp_phys" defined in reg property. + The number of offsets defined should reflect the + amount of mixers that can drive data to a panel + interface. +- qcom,mdss-dspp-off: Array of offset addresses for the available dspp + blocks. These offsets are calculated from + regsiter "mdp_phys" defined in reg property. + The number of dspp blocks should match the + number of mixers driving data to interface + defined in property: qcom,mdss-mixer-intf-off +- qcom,mdss-pingpong-off: Array of offset addresses for the available + pingpong blocks. These offsets are calculated + from regsiter "mdp_phys" defined in reg property. + The number of pingpong blocks should match the + number of mixers driving data to interface + defined in property: qcom,mdss-mixer-intf-off +- qcom,mdss-mixer-wb-off: Array of offset addresses for the available + mixer blocks that can be drive data to writeback + block. These offsets will be calculated from + register "mdp_phys" defined in reg property. + The number of writeback mixer offsets defined + should reflect the number of mixers that can + drive data to a writeback block. +- qcom,mdss-intf-off: Array of offset addresses for the available MDP + video interface blocks that can drive data to a + panel controller through timing engine. + The offsets are calculated from "mdp_phys" + defined in reg property. The number of offsets + defiend should reflect the number of progammable + interface blocks available in hardware. +- qcom,mdss-pref-prim-intf: A string which indicates the configured hardware + interface between MDP and the primary panel. + Individual panel controller drivers initialize + hardware based on this property. + Based on the interfaces supported at present, + possible values are: + - "dsi" + - "edp" + - "hdmi" + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for MDSS driver where use-case 0 is + used to take off MDSS BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,active-only: A boolean flag indicating if it is active only. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to MDSS for particular chipset. This + value represents the RT + NRT AXI master ports. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for MDSS are: + 22 = MSM_BUS_MASTER_MDP_PORT0 + 23 = MSM_BUS_MASTER_MDP_PORT1 + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for MDSS are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +- qcom,mdss-prefill-outstanding-buffer-bytes: The size of mdp outstanding buffer + in bytes. The buffer is filled during prefill + time and the buffer size shall be included in + prefill bandwidth calculation. +- qcom,mdss-prefill-y-buffer-bytes: The size of mdp y plane buffer in bytes. The + buffer is filled during prefill time when format + is YUV and the buffer size shall be included in + prefill bandwidth calculation. +- qcom,mdss-prefill-scaler-buffer-lines-bilinear: The value indicates how many lines + of scaler line buffer need to be filled during + prefill time. If bilinear scalar is enabled, then this + number of lines is used to determine how many bytes + of scaler buffer to be included in prefill bandwidth + calculation. +- qcom,mdss-prefill-scaler-buffer-lines-caf: The value indicates how many lines of + of scaler line buffer need to be filled during + prefill time. If CAF mode filter is enabled, then + this number of lines is used to determine how many + bytes of scaler buffer to be included in prefill + bandwidth calculation. +- qcom,mdss-prefill-post-scaler-buffer: The size of post scaler buffer in bytes. + The buffer is used to smooth the output of the + scaler. If the buffer is present in h/w, it is + filled during prefill time and the number of bytes + shall be included in prefill bandwidth calculation. +- qcom,mdss-prefill-pingpong-buffer-pixels: The size of pingpong buffer in pixels. + The buffer is used to keep pixels flowing to the + panel interface. If the vertical start position of a + layer is in the beginning of the active area, pingpong + buffer must be filled during prefill time to generate + starting lines. The number of bytes to be filled is + determined by the line width, starting position, + byte per pixel and scaling ratio, this number shall be + included in prefill bandwidth calculation. +- qcom,mdss-prefill-fbc-lines: The value indicates how many lines are required to fill + fbc buffer during prefill time if FBC (Frame Buffer + Compressor) is enabled. The number of bytes to be filled + is determined by the line width, bytes per pixel and + scaling ratio, this number shall be included in prefill bandwidth + calculation. +- qcom,max-mixer-width: Specify maximum MDP mixer width that the device supports. + This is a mandatory property, if not specified then + mdp probe will fail. + +Optional properties: +- batfet-supply : Phandle for battery FET regulator device node. +- vdd-cx-supply : Phandle for vdd CX regulator device node. +- qcom,vbif-settings : Array with key-value pairs of constant VBIF register + settings used to setup MDSS QoS for optimum performance. + The key used should be offset from "vbif_phys" register + defined in reg property. +- qcom,vbif-nrt-settings : The key used should be offset from "vbif_nrt_phys" + register defined in reg property. Refer qcom,vbif-settings + for a detailed description of this binding. +- qcom,mdp-settings : Array with key-value pairs of constant MDP register + settings used to setup MDSS QoS for best performance. + The key used should be offset from "mdp_phys" register + defined in reg property. +- qcom,mdss-smp-data: Array of shared memory pool data for dynamic SMP. There + should be only two values in this property. The first + value corresponds to the number of smp blocks and the + second is the size of each block present in the mdss + hardware. This property is optional for MDP hardware + with fix pixel latency ram. +- qcom,mdss-rot-block-size: The size of a memory block (in pixels) to be used + by the rotator. If this property is not specified, + then a default value of 128 pixels would be used. +- qcom,mdss-has-bwc: Boolean property to indicate the presence of bandwidth + compression feature in the rotator. +- qcom,mdss-has-non-scalar-rgb: Boolean property to indicate the presence of RGB + pipes which have no scaling support. +- qcom,mdss-has-decimation: Boolean property to indicate the presence of + decimation feature in fetch. +- qcom,mdss-has-fixed-qos-arbiter-enabled: Boolean property to indicate the + presence of rt/nrt feature. This feature enables + increased performance by prioritizing the real time + (rt) traffic over non real time (nrt) traffic to + access the memory. +- qcom,mdss-num-nrt-paths: Integer property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports are dedicated to non-realtime VBIF for + particular chipset. This property is mandatory when + "qcom,mdss-has-fixed-qos-arbiter-enabled" is enabled. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. +- qcom,mdss-has-source-split: Boolean property to indicate if source split + feature is available or not. +- qcom,mdss-has-rotator-downscale: Boolean property to indicate if rotator + downscale feature is available or not. +- qcom,mdss-rot-downscale-min: This integer value indicates the Minimum + downscale factor supported by rotator. +- qcom,mdss-rot-downscale-max: This integer value indicates the Maximum + downscale factor supported by rotator. +- qcom,mdss-ad-off: Array of offset addresses for the available + Assertive Display (AD) blocks. These offsets + are calculated from the register "mdp_phys" + defined in reg property. The number of AD + offsets should be less than or equal to the + number of mixers driving interfaces defined in + property: qcom,mdss-mixer-intf-off. Assumes + that AD blocks are aligned with the mixer + offsets as well (i.e. the first mixer offset + corresponds to the same pathway as the first + AD offset). +- qcom,mdss-has-wb-ad: Boolean property to indicate assertive display feature + support on write back framebuffer. +- qcom,mdss-no-lut-read: Boolean property to indicate reading of LUT is + not supported. +- qcom,mdss-no-hist-vote Boolean property to indicate histogram reads + and histogram LUT writes do not need additional + bandwidth voting. +- qcom,mdss-mdp-wfd-mode: A string that specifies what is the mode of + writeback wfd block. + "intf" = Writeback wfd block is + connected to the interface mixer. + "shared" = Writeback block shared + between wfd and rotator. + "dedicated" = Dedicated writeback + block for wfd using writeback mixer. +- qcom,mdss-smp-mb-per-pipe: Maximum number of shared memory pool blocks + restricted for a source surface pipe. If this + property is not specified, no such restriction + would be applied. +- qcom,mdss-highest-bank-bit: Property to indicate tile format as opposed to usual + linear format. The value tells the GPU highest memory + bank bit used. +- qcom,mdss-pipe-rgb-fixed-mmb: Array of indexes describing fixed Memory Macro + Blocks (MMBs) for rgb pipes. First value denotes + total numbers of MMBs per pipe while values, if + any, following first one denotes indexes of MMBs + to that RGB pipe. +- qcom,mdss-pipe-vig-fixed-mmb: Array of indexes describing fixed Memory Macro + Blocks (MMBs) for vig pipes. First value denotes + total numbers of MMBs per pipe while values, if + any, following first one denotes indexes of MMBs + to that VIG pipe. +- qcom,mdss-pipe-sw-reset-off: Property to indicate offset to the register which + holds sw_reset bitmap for different MDSS + components. +- qcom,mdss-pipe-vig-sw-reset-map: Array of bit offsets for vig pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-sw-reset-map: Array of bit offsets for rgb pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-sw-reset-map: Array of bit offsets for dma pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-default-ot-wr-limit: This integer value indicates maximum number of pending + writes that can be allowed on each WR xin. + This value can be used to reduce the pending writes + limit and can be tuned to match performance + requirements depending upon system state. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot write limit + will enable this dynamic limiting for the write + operations in the platforms that require these + limits. +- qcom,mdss-default-ot-rd-limit: This integer value indicates the default number of pending + reads that can be allowed on each RD xin. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot read limit + will enable this dynamic limiting for the read + operations in the platforms that require these + limits. +- qcom,mdss-clk-levels: This array indicates the mdp core clock level selection + array. Core clock is calculated for each frame and + hence depending upon calculated value, clock rate + will be rounded up to the next level according to + this table. Order of entries need to be ordered in + ascending order. +- qcom,mdss-vbif-qos-rt-setting: This array is used to program vbif qos remapper register + priority for real time clients. +- qcom,mdss-vbif-qos-nrt-setting: This array is used to program vbif qos remapper register + priority for non real time clients. +- qcom,mdss-traffic-shaper-enabled: This boolean property enables traffic shaper functionality + for MDSS rotator which spread out rotator bandwidth request + so that rotator don't compete with other real time read + clients. +- qcom,mdss-dram-channels: This represents the number of channels in the + Bus memory controller. +- qcom,regs-dump-mdp: This array represents the registers offsets that + will be dumped from the mdp when the debug logging + is enabled; each entry in the table is an start and + end offset from the MDP address "mdp_phys", the + format of each entry is as follows: + + Ex: + <0x01000 0x01404> + Will dump the MDP registers + from the address: "mdp_phys + 0x01000" + to the address: "mdp_phys + 0x01404" +- qcom,regs-dump-names-mdp: This array represents the tag that will be used + for each of the entries defined within regs-dump. + Note that each tag matches with one of the + regs-dump entries in the same order as they + are defined. +- qcom,regs-dump-xin-id-mdp: Array of VBIF clients ids (xins) corresponding + to mdp block. Xin id property is not valid for mdp + internal blocks like ctl, lm, dspp. It should set + to 0xff for such blocks. + +Fudge Factors: Fudge factors are used to boost demand for + resources like bus bandswidth, clk rate etc. to + overcome system inefficiencies and avoid any + glitches. These fudge factors are expressed in + terms of numerator and denominator. First value + is numerator followed by denominator. They all + are optional but highly recommended. + Ex: + x = value to be fudged + a = numerator, default value is 1 + b = denominator, default value is 1 + FUDGE(x, a, b) = ((x * a) / b) +- qcom,mdss-ib-factor: This fudge factor is applied to calculated ib + values in default conditions. +- qcom,mdss-ib-factor-overlap: This fudge factor is applied to calculated ib + values when the overlap bandwidth is the + predominant value compared to prefill bandwidth + value. +- qcom,mdss-clk-factor: This fudge factor is applied to calculated mdp + clk rate in default conditions. + +- qcom,max-bandwidth-low-kbps: This value indicates the max bandwidth in KB + that can be supported without underflow. + This is a low bandwidth threshold which should + be applied in most scenarios to be safe from + underflows when unable to satisfy bandwidth + requirements. +- qcom,max-bandwidth-high-kbps: This value indicates the max bandwidth in KB + that can be supported without underflow. + This is a high bandwidth threshold which can be + applied in scenarios where panel interface can + be more tolerant to memory latency such as + command mode panels. +- qcom,max-bandwidth-per-pipe-kbps: A two dimensional array indicating the max + bandwidth in KB that a single pipe can support + without underflow for various usecases. The + first parameter indicates the usecase and the + second parameter gives the max bw allowed for + the usecase. Following are the enum values for + modes in different cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. +- qcom,max-bw-settings: This two dimension array indicates the max bandwidth + in KB that has to be supported when particular + scenarios are involved such as camera, flip. + The first parameter indicate the + scenario/usecase and second parameter indicate + the maximum bandwidth for that usecase. + Following are the enum values for modes in different + cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. + +- qcom,mdss-has-panic-ctrl: Boolean property to indicate if panic/robust signal + control feature is available or not. +- qcom,mdss-en-svs-high: Boolean property to indicate if this target needs to + enable the svs high voltage level for CX rail. +- qcom,mdss-pipe-vig-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective VIG pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective RGB pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective DMA pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-dma-off +- qcom,mdss-per-pipe-panic-luts: Array to configure the panic/robust luts for + each rt and nrt clients. This property is + for the MDPv1.7 and above, which configures + the panic independently on each client. + Each element of the array corresponds to: + First element - panic for linear formats + Second element - panic for tile formats + Third element - robust for linear formats + Fourth element - robust for tile formats +- qcom,mdss-has-pingpong-split: Boolean property to indicate if destination + split feature is available or not in the target. +- qcom,mdss-slave-pingpong-off: Offset address for the extra TE block which needs + to be programmed when pingpong split feature is enabled. + Offset is calculated from the "mdp_phys" + register value. Mandatory when qcom,mdss-has-pingpong-split + is enabled. +- qcom,mdss-ppb-ctl-off: Array of offset addresses of ping pong buffer control registers. + The offsets are calculated from the "mdp_phys" base address + specified. The number of offsets should match the + number of ping pong buffers available in the hardware. + Mandatory when qcom,mdss-has-pingpong-split is enabled. +- qcom,mdss-ppb-cfg-off: Array of offset addresses of ping pong buffer config registers. + The offsets are calculated from the "mdp_phys" base address + specified. The number of offsets should match the + number of ping pong buffers available in the hardware. + Mandatory when qcom,mdss-has-pingpong-split is enabled. +- qcom,mdss-cdm-off: Array of offset addresses for the available + chroma down modules that can convert RGB data + to YUV before sending it to the interface + block. These offsets will be calculated from + register "mdp_phys" define in reg property. The + number of cdm offsets should reflect the number + of cdm blocks present in hardware. +- qcom,mdss-dsc-off: Array of offset addresses for the available + display stream compression module block. + These offsets will be calculated from + register "mdp_phys" define in reg property. The + number of dsc offsets should reflect the number + of dsc blocks present in hardware. +- qcom,max-pipe-width: This value specifies the maximum MDP SSPP width + the device supports. If not specified, a default value + of 2048 will be applied. +- qcom,mdss-reg-bus: Property to provide Bus scaling for register access for + MDP and DSI Blocks. + +- qcom,mdss-rot-reg-bus: Property to provide Bus scaling for register access for + Rotator Block. + +- qcom,mdss-hw-rt: Optional Property to request min vote on the bus. + Few Low tier targets expect min vote on the bus during SMMU + and TZ operations. use this handle to request the vote needed. + +Optional subnodes: +- mdss_fb: Child nodes representing the frame buffer virtual devices. + +Subnode properties: +- compatible : Must be "qcom,mdss-fb" +- cell-index : Index representing frame buffer +- qcom,mdss-mixer-swap: A boolean property that indicates if the mixer muxes + need to be swapped based on the target panel. + By default the property is not defined. +- qcom,memblock-reserve: Specifies the memory location and the size reserved + for the framebuffer used to display the splash screen. + This property is required whenever the continuous splash + screen feature is enabled for the corresponding + framebuffer device. It should be used for only 32bit + kernel. +- qcom,cont-splash-memory: Specifies the memory block region reserved for + continuous splash screen feature. This property should be + defined for corresponding framebuffer device if + "qcom,memblock-reserve" is not defined when continuous + splash screen feature is enabled. +- linux,contiguous-region: Phandle to the continuous memory region reserved for + frame-buffer or continuous splash screen. Size of this + region is dependent on the display panel resolution and + buffering scheme for frame-buffer node. Currently driver + uses double buffering. + + Example: Width = 1920, Height = 1080, BytesPerPixel = 4, + Number of frame-buffers reserved = 2. + Size = 1920*1080*4*2 = ROUND_1MB(15.8MB) = 16MB. +- qcom,mdss-fb-splash-logo-enabled: The boolean entry enables the framebuffer + driver to display the splash logo image. + It is independent of continuous splash + screen feature and has no relation with + qcom,cont-splash-enabled entry present in + panel configuration. +- qcom,mdss-idle-power-collapse-enabled: Boolean property that enables support + for mdss power collapse in idle + screen use cases with smart panels. +- qcom,boot-indication-enabled: Boolean property that enables turning on the blue + LED for notifying that the device is in boot + process. + +- qcom,mdss-pp-offets: A node that lists the offsets of post processing blocks + from base module. + -- qcom,mdss-mdss-sspp-igc-lut-off: This 32 bit value provides the + offset to the IGC lut rams from mdp_phys base. + -- qcom,mdss-sspp-vig-pcc-off: This 32 bit value provides the offset + to PCC block from the VIG pipe base address. + -- qcom,mdss-sspp-rgb-pcc-off: This 32 bit value provides the offset + to PCC block from the RGB pipe base address. + -- qcom,mdss-sspp-dma-pcc-off: This 32 bit value provides the offset + to PCC block from the DMA pipe base address. + -- qcom,mdss-dspp-pcc-off: This 32 bit value provides the offset + to PCC block from the DSPP pipe base address. + -- qcom,mdss-lm-pgc-off: This 32 bit value provides the offset + to PGC block from the layer mixer base address. + -- qcom,mdss-dspp-gamut-off: This 32 bit value provides the offset + to gamut block from DSPP base address. + -- qcom,mdss-dspp-pgc-off: This 32 bit value provides the offset to + PGC block from the DSPP base address. + +- qcom,mdss-scaler-offsets: A node that lists the offsets of scaler blocks + from base module. + -- qcom,mdss-vig-scaler-off: This 32 bit value provides the + offset to vig scaler from vig pipe base. + -- qcom,mdss-vig-scaler-lut-off: This 32 bit value provides the + offset to vig scaler lut from vig pipe base. + -- qcom,mdss-has-dest-scaler: Boolean property to indicate the + presence of destination scaler block. + -- qcom,mdss-dest-block-off: This 32 bit value provides the + offset from mdp base to destination scaler block. + -- qcom,mdss-dest-scaler-off: Array containing offsets of + destination scalar modules from the scaler block. + -- qcom,mdss-dest-scaler-lut-off: Array containing offsets of destination + scaler lut tables from scalar block. + +- qcom,mdss-has-separate-rotator: Boolean property to indicate support of + indpendent rotator. Indpendent rotator has + separate DMA pipe working in block mode only. + +- smmu_mdp_***: Child nodes representing the mdss smmu virtual devices. + Mandatory smmu v2 and not required for smmu v1. + +Subnode properties: +- compatible : Compatible name used in smmu v2. + smmu_v2 names should be: + "qcom,smmu_mdp_unsec" - smmu context bank device for + unsecure mdp domain. + "qcom,smmu_rot_unsec" - smmu context bank device for + unsecure rotation domain. + "qcom,smmu_mdp_sec" - smmu context bank device for + secure mdp domain. + "qcom,smmu_rot_sec" - smmu context bank device for + secure rotation domain. + "qcom,smmu_kms_unsec" - smmu context bank device for + unsecure mdp domain for KMS driver. + "qcom,smmu_nrt_unsec" - smmu context bank device for + unsecure rotation domain for KMS driver. + "qcom,smmu_kms_sec" - smmu context bank device for + secure mdp domain for KMS driver. + "qcom,smmu_nrt_sec" - smmu context bank device for + secure rotation domain for KMS driver. + "qcom,smmu_arm_mdp_unsec" - arm smmu context bank device for + unsecure mdp domain. + "qcom,smmu_arm_mdp_sec" - arm smmu context bank device for + secure mdp domain. +- gdsc-mmagic-mdss-supply: Phandle for mmagic mdss supply regulator device node. +- reg : offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. + +Subnode properties: +Required properties: +- compatible: Must be "qcom,mdss_wb" +- qcom,mdss_pan_res: Array containing two elements, width and height which + specifies size of writeback buffer. +- qcom,mdss_pan_bpp: Specifies bits per pixel for writeback buffer. +- qcom,mdss-fb-map: Specifies the handle for frame buffer. + +Example: + mdss_mdp: qcom,mdss_mdp@fd900000 { + compatible = "qcom,mdss_mdp"; + reg = <0xfd900000 0x22100>, + <0xfd924000 0x1000>, + <0xfd925000 0x1000>; + reg-names = "mdp_phys", "vbif_phys", "vbif_nrt_phys"; + interrupts = <0 72 0>; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + vdd-supply = <&gdsc_mdss>; + batfet-supply = <&pm8941_chg_batif>; + vdd-cx-supply = <&pm8841_s2_corner>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_mdp"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,mdss-dram-channels = <2>; + qcom,mdss-num-nrt-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + + /* Fudge factors */ + qcom,mdss-ab-factor = <2 1>; /* 2 times */ + qcom,mdss-ib-factor = <3 2>; /* 1.5 times */ + qcom,mdss-high-ib-factor = <2 1>; /* 2 times */ + qcom,mdss-clk-factor = <5 4>; /* 1.25 times */ + + /* Clock levels */ + qcom,mdss-clk-levels = <92310000, 177780000, 200000000>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-vbif-qos-rt-setting = <2 2 2 2>; + qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>; + + qcom,max-bandwidth-low-kbps = <2300000>; + qcom,max-bandwidth-high-kbps = <3000000>; + qcom,max-bandwidth-per-pipe-kbps = <4 2100000>, + <8 1800000>; + qcom,max-bw-settings = <1 2300000>, + <2 1700000>, + <4 2300000>, + <8 2000000>; + + qcom,max-mixer-width = <2048>; + qcom,max-pipe-width = <2048>; + qcom,max-clk-rate = <320000000>; + qcom,vbif-settings = <0x0004 0x00000001>, + <0x00D8 0x00000707>; + qcom,vbif-nrt-settings = <0x0004 0x00000001>, + <0x00D8 0x00000707>; + qcom,mdp-settings = <0x02E0 0x000000AA>, + <0x02E4 0x00000055>; + qcom,mdss-pipe-vig-off = <0x00001200 0x00001600 + 0x00001A00>; + qcom,mdss-pipe-rgb-off = <0x00001E00 0x00002200 + 0x00002600>; + qcom,mdss-pipe-dma-off = <0x00002A00 0x00002E00>; + qcom,mdss-pipe-cursor-off = <0x00035000 0x00037000>; + qcom,mdss-dsc-off = <0x00081000 0x00081400>; + qcom,mdss-pipe-vig-fetch-id = <1 4 7>; + qcom,mdss-pipe-rgb-fetch-id = <16 17 18>; + qcom,mdss-pipe-dma-fetch-id = <10 13>; + qcom,mdss-pipe-rgb-fixed-mmb = <2 0 1>, + <2 2 3>, + <2 4 5>, + <2 6 7>; + qcom,mdss-pipe-vig-fixed-mmb = <1 8>, + <1 9>, + <1 10>, + <1 11>; + qcom,mdss-smp-data = <22 4096>; + qcom,mdss-rot-block-size = <64>; + qcom,mdss-rotator-ot-limit = <2>; + qcom,mdss-smp-mb-per-pipe = <2>; + qcom,mdss-pref-prim-intf = "dsi"; + qcom,mdss-has-non-scalar-rgb; + qcom,mdss-has-bwc; + qcom,mdss-has-decimation; + qcom,mdss-has-fixed-qos-arbiter-enabled; + qcom,mdss-has-source-split; + qcom,mdss-wfd-mode = "intf"; + qcom,mdss-no-lut-read; + qcom,mdss-no-hist-vote; + qcom,mdss-traffic-shaper-enabled; + qcom,mdss-has-rotator-downscale; + qcom,mdss-rot-downscale-min = <2>; + qcom,mdss-rot-downscale-max = <16>; + + qcom,mdss-has-pingpong-split; + qcom,mdss-pipe-vig-xin-id = <0 4 8>; + qcom,mdss-pipe-rgb-xin-id = <1 5 9>; + qcom,mdss-pipe-dma-xin-id = <2 10>; + qcom,mdss-pipe-cursor-xin-id = <7 7>; + + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>, + <0x3C4 0 0>; + + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>, + <0x3BC 4 8>, + <0x3C4 4 8>; + + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>, + <0x3B4 8 12>; + + qcom,mdss-per-pipe-panic-luts = <0x000f>, + <0xffff>, + <0xfffc>, + <0xff00>; + + qcom,mdss-has-panic-ctrl; + qcom,mdss-pipe-vig-panic-ctrl-offsets = <0 1 2 3>; + qcom,mdss-pipe-rgb-panic-ctrl-offsets = <4 5 6 7>; + qcom,mdss-pipe-dma-panic-ctrl-offsets = <8 9>; + + qcom,mdss-pipe-sw-reset-off = <0x0128>; + qcom,mdss-pipe-vig-sw-reset-map = <5 6 7 8>; + qcom,mdss-pipe-rgb-sw-reset-map = <9 10 11 12>; + qcom,mdss-pipe-dma-sw-reset-map = <13 14>; + + qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800 + 0x00000900 0x0000A00>; + qcom,mdss-mixer-intf-off = <0x00003200 0x00003600 + 0x00003A00>; + qcom,mdss-mixer-wb-off = <0x00003E00 0x00004200>; + qcom,mdss-dspp-off = <0x00004600 0x00004A00 0x00004E00>; + qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>; + qcom,mdss-wb-off = <0x00011100 0x00013100 0x00015100 + 0x00017100 0x00019100>; + qcom,mdss-intf-off = <0x00021100 0x00021300 + 0x00021500 0x00021700>; + qcom,mdss-cdm-off = <0x0007A200>; + qcom,mdss-ppb-ctl-off = <0x0000420>; + qcom,mdss-ppb-cfg-off = <0x0000424>; + qcom,mdss-slave-pingpong-off = <0x00073000> + + /* buffer parameters to calculate prefill bandwidth */ + qcom,mdss-prefill-outstanding-buffer-bytes = <1024>; + qcom,mdss-prefill-y-buffer-bytes = <4096>; + qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>; + qcom,mdss-prefill-scaler-buffer-lines-caf = <4>; + qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>; + qcom,mdss-prefill-pingpong-buffer-pixels = <5120>; + qcom,mdss-prefill-fbc-lines = <2>; + qcom,mdss-idle-power-collapse-enabled; + + qcom,regs-dump-xin-id-mdp = <0xff 0xff 0xff 0xff 0x0 0x0>; + mdss_fb0: qcom,mdss_fb_primary { + cell-index = <0>; + compatible = "qcom,mdss-fb"; + qcom,mdss-mixer-swap; + linux,contiguous-region = <&fb_mem>; + qcom,mdss-fb-splash-logo-enabled: + qcom,cont-splash-memory { + linux,contiguous-region = <&cont_splash_mem>; + }; + }; + + qcom,mdss-pp-offsets { + qcom,mdss-sspp-mdss-igc-lut-off = <0x3000>; + qcom,mdss-sspp-vig-pcc-off = <0x1580>; + qcom,mdss-sspp-rgb-pcc-off = <0x180>; + qcom,mdss-sspp-dma-pcc-off = <0x180>; + qcom,mdss-lm-pgc-off = <0x3C0>; + qcom,mdss-dspp-gamut-off = <0x1600>; + qcom,mdss-dspp-pcc-off = <0x1700>; + qcom,mdss-dspp-pgc-off = <0x17C0>; + }; + + qcom,mdss-scaler-offsets { + qcom,mdss-vig-scaler-off = <0xA00>; + qcom,mdss-vig-scaler-lut-off = <0xB00>; + qcom,mdss-has-dest-scaler; + qcom,mdss-dest-block-off = <0x00061000>; + qcom,mdss-dest-scaler-off = <0x800 0x1000>; + qcom,mdss-dest-scaler-lut-off = <0x900 0x1100>; + }; + + qcom,mdss-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + + qcom,mdss-hw-rt-bus { + /* hw-rt Bus Scale Settings */ + qcom,msm-bus,name = "mdss_hw_rt"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 1000>; + }; + + smmu_mdp_sec: qcom,smmu_mdp_sec_cb { + compatible = "qcom,smmu_mdp_sec"; + iommus = <&mdp_smmu 1>; + reg = <0xd09000 0x000d00>, + reg-names = "mmu_cb"; + gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; + clocks = <&clock_mmss clk_smmu_mdp_ahb_clk>, + <&clock_mmss clk_smmu_mdp_axi_clk>; + clock-names = "dummy_clk", "dummy_clk"; + }; + + qcom,mdss_wb_panel { + compatible = "qcom,mdss_wb"; + qcom,mdss_pan_res = <1280 720>; + qcom,mdss_pan_bpp = <24>; + qcom,mdss-fb-map = <&mdss_fb1>; + }; + + qcom,mdss-rot-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + }; + diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt index d0d7fffda45fd06fccbfec499ab7734baeae8893..d746a520fcaada3dbb64c52fe50e566a76123043 100644 --- a/Documentation/devicetree/bindings/fb/mdss-pll.txt +++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt @@ -1,22 +1,21 @@ -Qualcomm Technologies MDSS pll for DSI/EDP/HDMI +Qualcomm MDSS pll for DSI/EDP/HDMI mdss-pll is a pll controller device which supports pll devices that -are compatible with MIPI display serial interface specification, +are compatiable with MIPI display serial interface specification, HDMI and edp. Required properties: -- compatible: Compatible name used in the driver - "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", - "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", - "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", - "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", - "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", - "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", - "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", - "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", - "qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8", - "qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998", - "qcom,mdss_hdmi_pll_8998" +- compatible: Compatible name used in the driver. Should be one of: + "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", + "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", + "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", + "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", + "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", + "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", + "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", + "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_dsi_pll_8952", + "qcom,mdss_dsi_pll_8937", "qcom,mdss_hdmi_pll_8996_v3_1p8", + "qcom,mdss_dsi_pll_8953" - cell-index: Specifies the controller used - reg: offset and length of the register set for the device. - reg-names : names to refer to register sets related to this device diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c11a438f5d8f569ec77f77484f0388dc436b8e6 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt @@ -0,0 +1,25 @@ +Qualcomm Technologies, Inc. mdss-qpic-panel + +mdss-qpic-panel is a panel device which can be driven by qpic. + +Required properties: +- compatible: Must be "qcom,mdss-qpic-panel" +- qcom,mdss-pan-res: A two dimensional array that specifies the panel + resolution. +- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. +- qcom,refresh_rate: Panel refresh rate + +Optional properties: +- label: A string used as a descriptive name of the panel + + +Example: +/ { + qcom,mdss_lcdc_ili9341_qvga { + compatible = "qcom,mdss-qpic-panel"; + label = "ili qvga lcdc panel"; + qcom,mdss-pan-res = <240 320>; + qcom,mdss-pan-bpp = <18>; + qcom,refresh_rate = <60>; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic.txt b/Documentation/devicetree/bindings/fb/mdss-qpic.txt new file mode 100644 index 0000000000000000000000000000000000000000..16d5b3547bdc28725ca1f04922f27a2a530c939c --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-qpic.txt @@ -0,0 +1,49 @@ +Qualcomm Technolgies, Inc. mdss-qpic + +mdss-qpic is a qpic controller device which supports dma transmission to MIPI +and LCDC panel. + +Required properties: +- compatible: must be "qcom,mdss_qpic" +- reg: offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- interrupts: IRQ line +- vdd-supply: Phandle for vdd regulator device node. +- avdd-supply: Phandle for avdd regulator device node. +- qcom,cs-gpio: Phandle for cs gpio device node. +- qcom,te-gpio: Phandle for te gpio device node. +- qcom,rst-gpio: Phandle for rst gpio device node. +- qcom,ad8-gpio: Phandle for ad8 gpio device node. +- qcom,bl-gpio: Phandle for backlight gpio device node. + +Optional properties: +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for +below Bus Scaling properties: + - qcom,msm-bus,name + - qcom,msm-bus,num-cases + - qcom,msm-bus,num-paths + - qcom,msm-bus,vectors-KBps + +Example: + qcom,msm_qpic@f9ac0000 { + compatible = "qcom,mdss_qpic"; + reg = <0xf9ac0000 0x24000>; + reg-names = "qpic_base"; + interrupts = <0 251 0>; + + qcom,msm-bus,name = "mdss_qpic"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + + qcom,msm-bus,vectors-KBps = + <91 512 0 0>, + <91 512 400000 800000>; + + vdd-supply = <&pm8019_l11>; + avdd-supply = <&pm8019_l14>; + qcom,cs-gpio = <&msmgpio 21 0>; + qcom,te-gpio = <&msmgpio 22 0>; + qcom,rst-gpio = <&msmgpio 23 0>; + qcom,ad8-gpio = <&msmgpio 20 0>; + qcom,bl-gpio = <&msmgpio 84 0>; + }; diff --git a/Documentation/devicetree/bindings/fb/mdss-rotator.txt b/Documentation/devicetree/bindings/fb/mdss-rotator.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e077ac23819adc6804913465beb5b17ee4ec53f --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-rotator.txt @@ -0,0 +1,78 @@ +QTI MDSS Rotator + +MDSS rotator is a rotator driver, which manages the rotator hw +block inside the Mobile Display Subsystem. + +Required properties +- compatible : Must be "qcom,mdss-rotator". +- qcom,mdss-wb-count: The number of writeback block + in the hardware +- -supply: Phandle for regulator device node. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for MDSS driver where use-case 0 is + used to take off MDSS BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to MDSS for particular chipset. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for MDSS are: + 22 = MSM_BUS_MASTER_MDP_PORT0 + 23 = MSM_BUS_MASTER_MDP_PORT1 + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for MDSS are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +Optional properties +- qcom,mdss-has-reg-bus: Boolean property to indicate + if rotator needs to vote for register bus. This + property is needed starting 8996 +- qcom,mdss-has-ubwc: Boolean property to indicate + if the hw supports universal + bandwidth compression (ubwc) +- qcom,mdss-has-downscale Boolean property to indicate + if the hw supports downscale + +Example: + mdss_rotator: qcom,mdss_rotator { + compatible = "qcom,mdss_rotator"; + qcom,mdss-has-downscale; + qcom,mdss-has-ubwc; + qcom,mdss-wb-count = <2>; + + qcom,mdss-has-reg-bus; + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,mdss-num-nrt-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + vdd-supply = <&gdsc_mdss>; + gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; + qcom,supply-names = "vdd", "gdsc-mmagic-mdss"; + }; diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f95ed4285efbd568f32f71257aa82951af33086 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt @@ -0,0 +1,116 @@ +* Qualcomm HDMI Tx + +Required properties: +- cell-index: hdmi tx controller index +- compatible: must be "qcom,hdmi-tx" +- reg: offset and length of the register regions(s) for the device. +- reg-names: a list of strings that map in order to the list of regs. + +- hpd-gdsc-supply: phandle to the mdss gdsc regulator device tree node. +- hpd-5v-supply: phandle to the 5V regulator device tree node. +- core-vdda-supply: phandle to the HDMI vdda regulator device tree node. +- core-vcc-supply: phandle to the HDMI vcc regulator device tree node. +- qcom,supply-names: a list of strings that map in order + to the list of supplies. +- qcom,min-voltage-level: specifies minimum voltage (uV) level + of supply(ies) mentioned above. +- qcom,max-voltage-level: specifies maximum voltage (uV) level + of supply(ies) mentioned above. +- qcom,enable-load: specifies the current (uA) that will be + drawn from the enabled supply(ies) mentioned above. +- qcom,disable-load: specifies the current (uA) that will be + drawn from the disabled supply(ies) mentioned above. + +- qcom,hdmi-tx-cec: gpio for Consumer Electronics Control (cec) line. +- qcom,hdmi-tx-ddc-clk: gpio for Display Data Channel (ddc) clock line. +- qcom,hdmi-tx-ddc-data: gpio for ddc data line. + +Optional properties: +- hpd-5v-en-supply: phandle to the 5V boost enable regulator device tree node. +- qcom,hdmi-tx-mux-sel: gpio required to toggle HDMI output between + docking station, type A, and liquid device, type D, ports. Required + property for liquid devices. +- qcom,hdmi-tx-ddc-mux-sel: gpio for ddc mux select. +- qcom,hdmi-tx-mux-en: gpio required to enable mux for HDMI output + on liquid devices. Required property for liquid devices. +- qcom,hdmi-tx-mux-lpm: gpio required for hdmi mux configuration + selection on liquid devices. Required property for liquid devices. +- qcom,conditional-power-on: Enables HPD conditionally on MTP targets. + Required property for MTP devices which are reworked to expose HDMI port. +- qcom,hdmi-tx-hpd: gpio required for HDMI hot-plug detect. Required on + platforms where companion chip is not used. +- pinctrl-names: a list of strings that map to the pinctrl states. +- pinctrl-0: list of phandles, each pointing at a pin configuration node. +... +- pinctrl-n: list of phandles, each pointing at a pin configuration node. +- qcom,conti-splash-enabled: Enables the hdmi continuous splash screen feature. + HDMI interface will remain powered on from LK to kernel with continuous + display of bootup logo. +- qcom,pluggable: boolean to enable hotplug feature. +- qcom,display-id: A string indicates the display ID for the controller. + The possible values are: + - "primary" + - "secondary" + - "tertiary" + +[Optional child nodes]: These nodes are for devices which are +dependent on HDMI Tx controller. If HDMI Tx controller is disabled then +these devices will be disabled as well. Ex. HDMI Audio Codec device. + +- qcom,msm-hdmi-audio-rx: Node for HDMI audio codec. +Required properties: +- compatible : "msm-hdmi-audio-codec-rx"; + +Example: + mdss_hdmi_tx: qcom,hdmi_tx@fd922100 { + cell-index = <0>; + compatible = "qcom,hdmi-tx"; + reg = <0xfd922100 0x35C>, + <0xfd922500 0x7C>, + <0xfc4b8000 0x60F0>, + <0xfe2a0000 0xFFF>; + reg-names = "core_physical", "phy_physical", "qfprom_physical", + "hdcp_physical"; + + hpd-gdsc-supply = <&gdsc_mdss>; + hpd-5v-supply = <&pm8941_mvs2>; + hpd-5v-en-supply = <&hdmi_vreg>; + core-vdda-supply = <&pm8941_l12>; + core-vcc-supply = <&pm8941_s3>; + qcom,supply-names = "hpd-gdsc", "hpd-5v", "hpd-5v-en", "core-vdda", "core-vcc"; + qcom,min-voltage-level = <0 0 0 1800000 1800000>; + qcom,max-voltage-level = <0 0 0 1800000 1800000>; + qcom,enable-load = <0 0 0 1800000 0>; + qcom,disable-load = <0 0 0 0 0>; + + qcom,hdmi-tx-ddc-mux-sel = <&pma8084_gpios 6 0>; + qcom,hdmi-tx-cec = <&msmgpio 31 0>; + qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>; + qcom,hdmi-tx-ddc-data = <&msmgpio 33 0>; + qcom,hdmi-tx-hpd = <&msmgpio 34 0>; + + qcom,hdmi-tx-mux-lpm = <&msmgpio 27 0>; + qcom,hdmi-tx-mux-en = <&msmgpio 83 0>; + qcom,hdmi-tx-mux-sel = <&msmgpio 85 0>; + + qcom,conditional-power-on; + qcom,pluggable; + qcom,display-id = "secondary"; + + qcom,msm-hdmi-audio-rx { + compatible = "qcom,msm-hdmi-audio-codec-rx"; + }; + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", + "hdmi_cec_active", "hdmi_active", + "hdmi_sleep"; + pinctrl-0 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_suspend + &mdss_hdmi_cec_suspend>; + pinctrl-1 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_active + &mdss_hdmi_cec_suspend>; + pinctrl-2 = <&mdss_hdmi_hpd_active &mdss_hdmi_cec_active + &mdss_hdmi_ddc_suspend>; + pinctrl-3 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_active + &mdss_hdmi_cec_active>; + pinctrl-4 = <&mdss_hdmi_hpd_suspend &mdss_hdmi_ddc_suspend + &mdss_hdmi_cec_suspend>; + }; diff --git a/Documentation/devicetree/bindings/fb/mxsfb.txt b/Documentation/devicetree/bindings/fb/mxsfb.txt new file mode 100644 index 0000000000000000000000000000000000000000..96ec5179c8a00199e2056ee574c3c55aef37bae3 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mxsfb.txt @@ -0,0 +1,49 @@ +* Freescale MXS LCD Interface (LCDIF) + +Required properties: +- compatible: Should be "fsl,-lcdif". Supported chips include + imx23 and imx28. +- reg: Address and length of the register set for lcdif +- interrupts: Should contain lcdif interrupts +- display : phandle to display node (see below for details) + +* display node + +Required properties: +- bits-per-pixel : <16> for RGB565, <32> for RGB888/666. +- bus-width : number of data lines. Could be <8>, <16>, <18> or <24>. + +Required sub-node: +- display-timings : Refer to binding doc display-timing.txt for details. + +Examples: + +lcdif@80030000 { + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 2000>; + interrupts = <38 86>; + + display: display { + bits-per-pixel = <32>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <164>; + hback-porch = <89>; + hsync-len = <10>; + vback-porch = <23>; + vfront-porch = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/sm501fb.txt b/Documentation/devicetree/bindings/fb/sm501fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d9f0098092b927b48dabbf198ee252e91d08a58 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/sm501fb.txt @@ -0,0 +1,34 @@ +* SM SM501 + +The SM SM501 is a LCD controller, with proper hardware, it can also +drive DVI monitors. + +Required properties: +- compatible : should be "smi,sm501". +- reg : contain two entries: + - First entry: System Configuration register + - Second entry: IO space (Display Controller register) +- interrupts : SMI interrupt to the cpu should be described here. +- interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + +Optional properties: +- mode : select a video mode: + x[-][@] +- edid : verbatim EDID data block describing attached display. + Data from the detailed timing descriptor will be used to + program the display controller. +- little-endian: available on big endian systems, to + set different foreign endian. +- big-endian: available on little endian systems, to + set different foreign endian. + +Example for MPC5200: + display@1,0 { + compatible = "smi,sm501"; + reg = <1 0x00000000 0x00800000 + 1 0x03e00000 0x00200000>; + interrupts = <1 1 3>; + mode = "640x480-32@60"; + edid = [edid-data]; + }; diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index 3b4436e568657dc7069c5bd79768ca1539c66888..7cfc44bf47478d7f0190811f4d8e7d82d38f55ce 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -11,6 +11,9 @@ Required properties: * "qcom,scm-msm8660" for MSM8660 platforms * "qcom,scm-msm8690" for MSM8690 platforms * "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc) + * "android,firmware" for firmware image + * "android,vbmeta" for setting system properties for verified boot. + * "android,system" for system partition properties. - clocks: One to three clocks may be required based on compatible. * Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960" * Core, iface, and bus clocks required for "qcom,scm" @@ -26,3 +29,26 @@ Example for MSM8916: clock-names = "core", "bus", "iface"; }; }; + +Example for SDM845: + + firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index f4b6013a3616c862e8ff1b8fe43cfec0e36ad0fc..55cd3835850dbbf735e8b54870dfd6d328110752 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -5,14 +5,17 @@ Qualcomm Technologies, Inc. Adreno GPU Required properties: - label: A string used as a descriptive name for the device. - compatible: Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d" -- reg: Specifies the register base address and size. The second interval - specifies the shader memory base address and size. +- reg: Specifies the register base address and size, the shader memory + base address and size (if it exists), and the base address and size + of the CX_DBGC block (if it exists). - reg-names: Resource names used for the physical address of device registers and shader memory. "kgsl_3d0_reg_memory" gives the physical address and length of device registers while "kgsl_3d0_shader_memory" gives physical address and length of device shader memory. If specified, "qfprom_memory" gives the range for the efuse - registers used for various configuration options. + registers used for various configuration options. If specified, + "kgsl_3d0_cx_dbgc_memory" gives the physical address and length + of the CX DBGC block. - interrupts: Interrupt mapping for GPU IRQ. - interrupt-names: String property to describe the name of the interrupt. - qcom,id: An integer used as an identification number for the device. @@ -93,6 +96,7 @@ Optional Properties: - qcom,chipid: If it exists this property is used to replace the chip identification read from the GPU hardware. This is used to override faulty hardware readings. +- qcom,disable-wake-on-touch: Boolean. Disables the GPU power up on a touch input event. - qcom,disable-busy-time-burst: Boolean. Disables the busy time burst to avoid switching of power level for large frames based on the busy time limit. @@ -120,6 +124,12 @@ Optional Properties: mask - mask for the relevant bits in the efuse register. shift - number of bits to right shift to get the speed bin value. +- qcom,gpu-disable-fuse: GPU disable fuse + + offset - offset of the efuse register from the base. + mask - mask for the relevant bits in the efuse register. + shift - number of bits to right shift to get the disable_gpu + fuse bit value. - qcom,highest-bank-bit: Specify the bit of the highest DDR bank. This is programmed into protected registers and also @@ -143,6 +153,9 @@ Optional Properties: rendering thread is running on masked CPUs. Bit 0 is for CPU-0, bit 1 is for CPU-1... +- qcom,l2pc-update-queue: + Disables L2PC on masked CPUs at queue time when it's true. + - qcom,snapshot-size: Specify the size of snapshot in bytes. This will override snapshot size defined in the driver code. @@ -184,6 +197,9 @@ GPU Quirks: - qcom,gpu-quirk-hfi-use-reg: Use registers to replace DCVS HFI message to avoid GMU failure to access system memory during IFPC +- qcom,gpu-quirk-limit-uche-gbif-rw: + Limit number of read and write transactions from UCHE block to + GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC. KGSL Memory Pools: - qcom,gpu-mempools: Container for sets of GPU mempools.Multiple sets @@ -202,24 +218,47 @@ Properties: - qcom,mempool-allocate: Allocate memory from the system memory when the reserved pool exhausted. +SOC Hardware revisions: +- qcom,soc-hw-revisions: + Container of sets of SOC hardware revisions specified by + qcom,soc-hw-revision. +Properties: +- compatible: + Must be qcom,soc-hw-revisions. + +- qcom,soc-hw-revision: + Defines a SOC hardware revision. + +Properties: +- reg: + Identifier for the hardware revision - must match the value read + from the hardware. +- qcom,chipid: + GPU Chip ID to be used for this hardware revision. +- qcom,gpu-quirk-*: + GPU quirks applicable for this hardware revision. + GPU LLC slice info: - cache-slice-names: List of LLC cache slices for GPU transactions and pagetable walk. - cache-slices: phandle to the system LLC driver, cache slice index. + +GPU coresight info: The following properties are optional as collecting data via coresight might not be supported for every chipset. The documentation for coresight properties can be found in: Documentation/devicetree/bindings/coresight/coresight.txt -- coresight-id Unique integer identifier for the bus. -- coresight-name Unique descriptive name of the bus. -- coresight-nr-inports Number of input ports on the bus. -- coresight-outports List of output port numbers on the bus. -- coresight-child-list List of phandles pointing to the children of this +- qcom,gpu-coresights: Container for sets of GPU coresight sources. +- coresight-id: Unique integer identifier for the bus. +- coresight-name: Unique descriptive name of the bus. +- coresight-nr-inports: Number of input ports on the bus. +- coresight-outports: List of output port numbers on the bus. +- coresight-child-list: List of phandles pointing to the children of this component. -- coresight-child-ports List of input port numbers of the children. -- coresight-atid The unique ATID value of the coresight device +- coresight-child-ports: List of input port numbers of the children. +- coresight-atid: The unique ATID value of the coresight device Example of A330 GPU in MSM8916: @@ -274,6 +313,28 @@ Example of A330 GPU in MSM8916: coresight-child-list = <&funnel_in0>; coresight-child-ports = <5>; + qcom,soc-hw-revisions { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,soc-hw-revisions"; + + qcom,soc-hw-revision@0 { + reg = <0>; + + qcom,chipid = <0x06010500>; + qcom,gpu-quirk-hfi-use-reg; + qcom,gpu-quirk-limit-uche-gbif-rw; + }; + + qcom,soc-hw-revision@1 { + reg = <1>; + + qcom,chipid = <0x06010501>; + qcom,gpu-quirk-hfi-use-reg; + }; + }; + /* GPU Mempools */ qcom,gpu-mempools { #address-cells= <1>; diff --git a/Documentation/devicetree/bindings/hwmon/jc42.txt b/Documentation/devicetree/bindings/hwmon/jc42.txt index 07a250498fbb4cccb3210a418c572907d8310c43..f569db58f64a100b6c72e1053ce443b77ae102c2 100644 --- a/Documentation/devicetree/bindings/hwmon/jc42.txt +++ b/Documentation/devicetree/bindings/hwmon/jc42.txt @@ -34,6 +34,10 @@ Required properties: - reg: I2C address +Optional properties: +- smbus-timeout-disable: When set, the smbus timeout function will be disabled. + This is not supported on all chips. + Example: temp-sensor@1a { diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt index 62ba54bac51204efe98ef146b91b749dba7f66e9..d9d3470ceff72af516e65767c32e48769596349b 100644 --- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt +++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt @@ -18,7 +18,6 @@ Required properties: "high-thr-en-set" for high threshold interrupts and "low-thr-en-set" for low threshold interrupts. High and low threshold interrupts are to be enabled if VADC_USR needs to support recurring measurement. -- qcom,adc-bit-resolution : Bit resolution of the ADC. - qcom,adc-vdd-reference : Voltage reference used by the ADC. Channel nodes @@ -46,6 +45,14 @@ Optional properties: 0 : The calibration values used for measurement are from a timer. 1 : Forces a fresh measurement for calibration values at the same time measurement is taken. +- qcom,adc-full-scale-code: Full scale code with offset removed. +- pinctrl-names: should be "default" (see pinctrl binding [0]). +- pinctrl-0: a phandle pointing to the pin settings for the + device (see pinctrl binding [0]). + +[0]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +- #thermal-sensor-cells : To register ADC sensors with of_thermal. Should be 1. + See ./thermal.txt for a description. Client required property: - qcom,-vadc : The phandle to the corresponding vadc device. diff --git a/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt b/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa3abb215773996c4871e16965ce9cd68066a0af --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt @@ -0,0 +1,55 @@ +Qualcomm I2C controller + +Required properties: + - reg : Offset and length of the register region for the device named in + reg-names and has the same index. + - reg-names : Register region name(s) referenced in reg above + "qup_phys_addr" : Physical address of QUP register space. + - compatible : should be "qcom,i2c-msm-v2" + - interrupts : Interrupt number which correspond to the entry with the same + index in interrupt-names. + - interrupt-names: QUP core interrupt name(s) referenced in interrupts above + "qup_irq" : QUP interrupt used by the controller. + - dmas : DMA engine API's parameters for blsp. + <[phandle of the dma controller] [pipe index] [number of descriptors] + [sps_connect flags] [sps_register_event flags]>; + - dma-names : dma channel names. + - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz + - qcom,clk-freq-in : Supplied core clock frequency in Hz. + +Required alias: + - The desired bus-number is specified by an alias with the following format: + 'i2c{n}' where n is the bus number. + +Optional property: + - qcom,noise-rjct-scl : number of low samples on clock line to consider it low. + When missing default to 0. + - qcom,noise-rjct-sda : number of low samples on data line to consider it low. + When missing default to 0. + - qcom,disable-dma : disables DMA transfer mode. + - qcom,master-id : Master-port value used on voting for the clock path. + - qcom,high-time-clk-div : high time divider value to configure clk-ctl + register. When missing, default to the value given in driver. + - qcom,fs-clk-div: fs divider value to configure clk-ctl register. When + missing, default to the value given in driver. + +Example: + aliases { + i2c10 = &i2c_10; + }; + + i2c_10: i2c@f9966000 { + compatible = "qcom,i2c-msm-v2"; + reg-names = "qup_phys_addr", "dma_phys_addr"; + reg = <0xf9966000 0x1000>; + interrupt-names = "qup_irq"; + interrupts = <0 104 0>; + dmas = <&dma_blsp1 14 32 0x20000020 0x20>, + <&dma_blsp1 15 64 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,clk-freq-out = <100000>; + qcom,clk-freq-in = <24000000>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + + }; diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt b/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt index a244d6c0db26ab85e567505862a90a44dcdca1f9..21edaa0cf621163eec4e8cae7118629ce2262f2e 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-qcom-geni.txt @@ -12,6 +12,11 @@ Required properties: or when entering sleep state. - #address-cells: Should be <1> Address cells for i2c device address - #size-cells: Should be <0> as i2c addresses have no size component + - qcom,wrapper-core: Wrapper QUPv3 core containing this I2C controller. + +Optional property: + - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz. + When missing default to 400000Hz. Child nodes should conform to i2c bus binding. @@ -30,4 +35,6 @@ i2c@a94000 { pinctrl-1 = <&qup_1_i2c_5_sleep>; #address-cells = <1>; #size-cells = <0>; + qcom,wrapper-core = <&qupv3_0>; + qcom,clk-freq-out = <400000>; }; diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt b/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3629405f5684ff82ce11a5b0691370030719dc3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt @@ -0,0 +1,18 @@ +* AVIA HX711 ADC chip for weight cells + Bit-banging driver + +Required properties: + - compatible: Should be "avia,hx711" + - sck-gpios: Definition of the GPIO for the clock + - dout-gpios: Definition of the GPIO for data-out + See Documentation/devicetree/bindings/gpio/gpio.txt + - avdd-supply: Definition of the regulator used as analog supply + +Example: +weight@0 { + compatible = "avia,hx711"; + sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; + dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + avdd-suppy = <&avdd>; +}; + diff --git a/Documentation/devicetree/bindings/input/qpnp-power-on.txt b/Documentation/devicetree/bindings/input/qpnp-power-on.txt index a596aa1c595d058ae4b62c6bca53217c71e289d3..33d0236d96fcd5fb7f6b21688da0284b64ad2deb 100644 --- a/Documentation/devicetree/bindings/input/qpnp-power-on.txt +++ b/Documentation/devicetree/bindings/input/qpnp-power-on.txt @@ -82,7 +82,36 @@ Optional properties: - qcom,shutdown-poweroff-type Same description as qcom,warm-reset-poweroff- type but this applies for the system shutdown case. - +- qcom,kpdpwr-sw-debounce Boolean property to enable the debounce logic + on the KPDPWR_N rising edge. +- qcom,resin-pon-reset Boolean property which indicates that resin + needs to be configured during reset in addition + to the primary PON device that is configured + for system reset through qcom,system-reset + property. +- qcom,resin-warm-reset-type Poweroff type required to be configured on + RESIN reset control register when the system + goes for warm reset. If this property is not + specified, then the default type, warm reset + will be configured to RESIN reset control + register. This property is effective only if + qcom,resin-pon-reset is defined. +- qcom,resin-hard-reset-type Same description as qcom,resin-warm-reset-type + but this applies for the system hard reset case. +- qcom,resin-shutdown-type Same description as qcom,resin-warm-reset-type + but this applies for the system shutdown case. +- qcom,resin-shutdown-disable Boolean property to disable RESIN POFF + trigger during system shutdown case. + This property is effective only if + qcom,resin-pon-reset is defined. +- qcom,resin-hard-reset-disable Boolean property to disable RESIN POFF + trigger during system hard reset case. + This property is effective only if + qcom,resin-pon-reset is defined. +- qcom,ps-hold-shutdown-disable Boolean property to disable PS_HOLD POFF + trigger during system shutdown case. +- qcom,ps-hold-hard-reset-disable Boolean property to disable PS_HOLD + POFF trigger during system hard reset case. All the below properties are in the sub-node section (properties of the child node). diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..131942dd0ae9b4a092ece9bd1a4f558c10bf0945 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt @@ -0,0 +1,62 @@ +Synaptics DSXV27 touch controller + +Please add this description here: The Synaptics Touch controller is connected to the +host processor via I2C. The controller generates interrupts when the user touches +the panel. The host controller is expected to read the touch coordinates over I2C and +pass the coordinates to the rest of the system. + +Required properties: + + - compatible : should be "synaptics,dsx-i2c". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - synaptics,irq-gpio : irq gpio. + - synaptics,reset-gpio : reset gpio. + - vdd_supply : digital voltage power supply needed to power device. + - avdd_supply : analog voltage power supply needed to power device. + - synaptics,pwr-reg-name : power reg name of digital voltage. + - synaptics,bus-reg-name : bus reg name of analog voltage. + +Optional property: + - synaptics,ub-i2c-addr : addr of ub-i2c. + - synaptics,irq-on-state : status of irq gpio. + - synaptics,cap-button-codes : virtual key code mappings to be used. + - synaptics,vir-button-codes : virtual key code and the response region on panel. + - synaptics,x-flip : modify orientation of the x axis. + - synaptics,y-flip : modify orientation of the y axis. + - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. + - synaptics,power-delay-ms : power delay for controller (ms), default 100. + - synaptics,reset-active-ms : reset active time for controller (ms), default 20. + - synaptics,max-y-for-2d : maximal y value of the panel. + - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" + - clocks : Defined if 'clock-names' DT property is defined. These clocks + are associated with the underlying I2C bus. + +Example: + i2c@78b7000 { + status = "ok"; + synaptics@4b { + compatible = "synaptics,dsx-i2c"; + reg = <0x4b>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + vdd_supply = <&pmtitanium_l17>; + avdd_supply = <&pmtitanium_l6>; + synaptics,pwr-reg-name = "vdd"; + synaptics,bus-reg-name = "avdd"; + synaptics,ub-i2c-addr = <0x2c>; + synaptics,irq-gpio = <&tlmm 65 0x2008>; + synaptics,reset-gpio = <&tlmm 99 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-active-ms = <20>; + synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */ + synaptics,cap-button-codes = <139 172 158>; + synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>; + /* Underlying clocks used by secure touch */ + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..7dece8e062406553fd7af7299f5a768bf69accc4 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt @@ -0,0 +1,50 @@ +Synaptics DSXV26 touch controller + +Please add this description here: The Synaptics Touch controller is connected to the +host processor via I2C. The controller generates interrupts when the user touches +the panel. The host controller is expected to read the touch coordinates over I2C and +pass the coordinates to the rest of the system. + +Required properties: + + - compatible : should be "synaptics,dsx-i2c". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - synaptics,irq-gpio : irq gpio. + - synaptics,irq-flags : irq flags. + +Optional property: + - vdd_ana-supply : digital voltage power supply needed to power device. + - vcc_i2c-supply : analog voltage power supply needed to power device. + - synaptics,pwr-reg-name : power reg name of digital voltage. + - synaptics,bus-reg-name : bus reg name of analog voltage. + - synaptics,irq-on-state : status of irq gpio. + - synaptics,cap-button-codes : virtual key code mappings to be used. + - synaptics,vir-button-codes : virtual key code and the response region on panel. + - synaptics,x-flip : modify orientation of the x axis. + - synaptics,y-flip : modify orientation of the y axis. + - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. + - synaptics,max-y-for-2d : maximal y value of the panel. + +Example: + i2c@78b7000 { + status = "ok"; + synaptics@4b { + compatible = "synaptics,dsx-i2c"; + reg = <0x4b>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + vdd_ana-supply = <&pmtitanium_l17>; + vcc_i2c-supply = <&pmtitanium_l6>; + synaptics,pwr-reg-name = "vdd_ana"; + synaptics,bus-reg-name = "vcc_i2c"; + synaptics,irq-gpio = <&tlmm 65 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,irq-flags = <0x2008>; /* IRQF_ONESHOT | IRQF_TRIGGER_LOW */ + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */ + synaptics,cap-button-codes = <139 172 158>; + synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt index 3e5b9793341f4e10679f792c8e19e9fbb55027e1..8682ab6d4a50f86d0d352f6b5b4e8a337c5511c4 100644 --- a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt +++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt @@ -8,8 +8,9 @@ This driver provides a simple power button event via an Interrupt. Required properties: - compatible: should be "ti,tps65217-pwrbutton" or "ti,tps65218-pwrbutton" -Required properties for TPS65218: +Required properties: - interrupts: should be one of the following + - <2>: For controllers compatible with tps65217 - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218 Examples: @@ -17,6 +18,7 @@ Examples: &tps { tps65217-pwrbutton { compatible = "ti,tps65217-pwrbutton"; + interrupts = <2>; }; }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..07667a4d9e39341c0f3b0c7b9d2d0454ea866450 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt @@ -0,0 +1,67 @@ +QTI PDC interrupt controller + +PDC is QTI's platform parent interrupt controller that serves as wakeup source. + +Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power +Domain Controller) to manage subsystem wakeups and resources during sleep. +This driver marks the wakeup interrupts in APSS PDC such that it monitors the +interrupts when the system is asleep, wakes up the APSS when one of these +interrupts occur and replays it to the subsystem interrupt controller after it +becomes operational. + +Earlier MPM architecture used arch-extension of GIC interrupt +controller to mark enabled wake-up interrupts and monitor these when the +system goes to sleep. Since the arch-extensions are no-longer available +on newer kernel versions, this driver is implemented as hierarchical irq +domain. GIC is parent interrupt controller at the highest level. +Platform interrupt controller PDC is next in hierarchy, followed by others. +This driver only configures the interrupts, does not handle them. + +PDC interrupt configuration involves programming of 2 set of registers: +IRQ_ENABLE_BANK - Enable the irq +IRQ_i_CFG - Configure the interrupt i + +Properties: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,pdc-" + + * "qcom,pdc-sdm845": For sdm845 pin data + * "qcom,pdc-sdm845-v2": For sdm845 v2 pin data + * "qcom,pdc-sdm670": For sdm670 pin data + +- reg: + Usage: required + Value type: + Definition: Specifies the base physical address for PDC hardware + block for DRV2. + +- interrupt-cells: + Usage: required + Value type: + Definition: Specifies the number of cells needed to encode an interrupt source. + Value must be 3. + The encoding of these cells are same as described in + Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt + +- interrupt-parent: + Usage: required + Value type: + Definition: Specifies the interrupt parent necessary for hierarchical domain to operate. + +- interrupt-controller: + Usage: required + Value type: + Definition: Identifies the node as an interrupt controller. + +Example: + +pdcgic: interrupt-controller@0xb220000{ + compatible = "qcom,pdc-sdm845"; + reg = <0xb220000 0x30000>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; +}; diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 2d971b7a6981eb977e71d9a0f97c4e0c0acf3e3e..78aa1d78062c11155c8b7072108eff6698b8441c 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -74,6 +74,9 @@ conditions. address size faults are due to a fundamental programming error from which we don't care about recovering anyways. +- qcom,tz-device-id : A string indicating the device ID for this SMMU known + to TZ. See msm_tz_smmu.c for a full list of mappings. + - qcom,skip-init : Disable resetting configuration for all context banks during device reset. This is useful for targets where some context banks are dedicated to other execution @@ -86,6 +89,35 @@ conditions. useful if the upstream hardware is capable of switching between multiple domains within a single context bank. +- qcom,use-3-lvl-tables: + Some hardware configurations may not be optimized for using + a four level page table configuration. Set to use a three + level page table instead. + +- qcom,no-asid-retention: + Some hardware may lose internal state for asid after + retention. No cache invalidation operations involving asid + may be used. + +- qcom,disable-atos: + Some hardware may not have full support for atos debugging + in tandem with other features like power collapse. + +- qcom,mmu500-errata-1: + An array of . + Indicates the SIDs for which the workaround is required. + +- qcom,actlr: + An array of . + Any sid X for which X&~mask==sid will be programmed with the + given actlr-setting. + +- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator + disable in ms. In case of unmap call, regulator is + enabled/disabled. This may introduce additional delay. For + clients who do not detach, it's not possible to keep regulator + vote while smmu is attached. Type is . + - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index da54fb11ffd43f77cb52cbe844207b0daf711e60..176f9e115b4231328a72def913f72ca46b1d4e9c 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -169,8 +169,15 @@ Optional properties: sleep configuration defined for each pin or pin group. - qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no pinctrl support or PMIC GPIOs are used. -- qcom,hw-strobe-sel : Boolean property to enable hardware strobe. If not defined, software strobe - will be used. +- qcom,strobe-sel : Property to select strobe type. If not defined, + software strobe will be used. Allowed options are: + 0 - SW strobe + 1 - HW strobe + 2 - LPG strobe + LPG strobe is supported only for LED3. + If LPG strobe is specified, then strobe control is + configured for active high and level triggered. Also + qcom,hw-strobe-option should be set to 1 or 2. - qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to be edge triggered. Otherwise, it is level triggered. - qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt index ed1ddf5970163785f5b01781625f64b10b615947..a7a2eda6c5a7532161beec66efc89648c59d2155 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt @@ -1,10 +1,10 @@ -Qualcomm Technologies PNP Flash LED +Qualcomm Technologies Inc. PNP Flash LED -QPNP (Qualcomm Technologies Plug N Play) Flash LED (Light +QPNP (Qualcomm Technologies Inc. Plug N Play) Flash LED (Light Emitting Diode) driver is used to provide illumination to camera sensor when background light is dim to capture good picture. It can also be used for flashlight/torch application. -It is part of PMIC on Qualcomm Technologies reference platforms. +It is part of PMIC on Qualcomm Technologies Inc. reference platforms. The PMIC is connected to the host processor via SPMI bus. Required properties: diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7ce6627f3139d3e86753430166fb3bbead99131 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt @@ -0,0 +1,257 @@ +Qualcomm Technologies, Inc. Haptics driver + +QPNP (Qualcomm Technologies, Inc. Plug N Play) Haptics is a peripheral on some +QTI PMICs. It can be interfaced with the host processor via SPMI or I2C bus. + +Haptics peripheral can support different actuators or vibrators, +1. Eccentric Rotation Mass (ERM) +2. Linear Resonant Actuator (LRA) + +Also, it can support multiple modes of operation: Direct, Buffer, PWM or Audio. + +Haptics device is described under a single level of node. + +Properties: + +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-haptics". + +- reg + Usage: required + Value type: + Definition: Base address of haptics peripheral. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. Currently + supported interrupts are short-circuit and play. + +- qcom,pmic-revid + Usage: required + Value type: + Definition: Should specify the phandle of PMIC's revid module. This is used to + identify the PMIC subtype. + +- qcom,pmic-misc + Usage: optional + Value type: + Definition: Should specify the phandle of PMIC's misc module. This is used to + read the clock trim error register under MISC peripheral. + +- qcom,misc-clk-trim-error-reg + Usage: optional + Value type: + Definition: Register offset in MISC peripheral to read the clock trim error. + If this is specified, then qcom,pmic-misc should be specified. + +- qcom,actuator-type + Usage: optional + Value type: + Definition: Allowed values are 0 for LRA and 1 for ERM. If this is not + specified, then LRA type will be used by default. + +- qcom,play-mode + Usage: optional + Value type: + Definition: Allowed values are: "direct", "buffer", "pwm", "auto". If not + specified for LRA actuator, auto mode will be selected by + default. + +- qcom,wave-shape + Usage: optional + Value type: + Definition: Wave shape to be played. Allowed values: "sine" or "square". + Default value is "square". + +- qcom,wave-play-rate-us + Usage: optional + Value type: + Definition: Wave sample duration in microseconds. This should match with + the frequency the vibrator supports. + Allowed values are: 0 to 20475. Default value is 5715. + +- qcom,max-play-time-us + Usage: optional + Value type: + Definition: Maximum play time supported in microseconds. Default value is + 15000. + +- qcom,vmax-mv + Usage: optional + Value type: + Definition: Maximum output voltage in millivolts. Value specified here will + be rounded off to the closest multiple of 116 mV. + Allowed values: 0 to 3596. Default value is 3596. + +- qcom,ilim-ma + Usage: optional + Value type: + Definition: Output current limit in mA. Allowed values: 400 or 800. Default + value is 400. + +- qcom,en-brake + Usage: optional + Value type: + Definition: Enables internal reverse braking. + +- qcom,brake-pattern + Usage: optional + Value type: + Definition: Brake pattern to be applied. If specified, should be having + 4 elements. Allowed values for each element are: + 0, 1: Vmax/4, 2: Vmax/2, 3: Vmax. + +- qcom,sc-dbc-cycles + Usage: optional + Value type: + Definition: Short circuit debounce cycles for internal PWM. + Allowed values: 0, 8, 16 or 32. + +Following properties are specific only to LRA vibrators. + +- qcom,lra-auto-res-mode + Usage: optional + Value type: + Definition: Auto resonance method. Allowed values are: + For pmi8998 and chips earlier, + "none" : No auto resonance + "zxd" : Zero crossing detection method + "qwd" : Quarter wave drive method + "max-qwd" : Maximum QWD + "zxd-eop" : ZXD + End of Pattern + For pm660, + "zxd" : Zero crossing detection method + "qwd" : Quarter wave drive method + +- qcom,lra-high-z + Usage: optional + Value type: + Definition: High Z configuration for auto resonance. Allowed values are: + "none", "opt1", "opt2" and "opt3". + For pm660, "opt0" is valid value for 1 LRA period. + +- qcom,lra-res-cal-period + Usage: optional + Value type: + Definition: Auto resonance calibration period. Allowed values are: + For pmi8998 and chips earlier: 4, 8, 16, and 32. + For pm660: 4, 8, 16, 32, 64, 128 and 256. + +- qcom,lra-qwd-drive-duration + Usage: optional + Value type: + Definition: LRA drive duration in QWD mode. Applies only for pm660 currently. + Allowed values are: 0 and 1, for 1/4 and 3/8 LRA period. + respectively. + +- qcom,lra-calibrate-at-eop + Usage: optional + Value type: + Definition: Enables calibration at end of pattern. Applies only for pm660 + currently. Allowed values are: 0 and 1. + +- qcom,auto-res-err-recovery-hw + Usage: optional + Value type: + Definition: Enables Hardware auto resonance error recovery. Applies only for + pm660 currently. + +- qcom,drive-period-code-max-variation-pct + Usage: optional + Value type: + Definition: Maximum allowed variation of LRA drive period code in percentage + above which RATE_CFG registers will not be updated by SW when + auto resonance is enabled and auto resonance error correction + algorithm is running. If not specified, default value is 25%. + +- qcom,drive-period-code-min-variation-pct + Usage: optional + Value type: + Definition: Minimum allowed variation of LRA drive period code in percentage + below which RATE_CFG registers will not be updated by SW when + auto resonance is enabled and auto resonance error correction + algorithm is running. If not specified, default value is 25%. + +Following properties are applicable only when "qcom,play-mode" is set to +"buffer". + +- qcom,wave-rep-cnt + Usage: optional + Value type: + Definition: Repetition count for wave form. + Allowed values are: 1, 2, 4, 8, 16, 32, 64 and 128. Default + value is 1. + +- qcom,wave-samp-rep-cnt + Usage: optional + Value type: + Definition: Repetition count for each sample of wave form. Allowed values + are: 1, 2, 4 and 8. Default value is 1. + +- qcom,wave-samples + Usage: optional + Value type: + Definition: Wave samples in an array of 8 elements. Each element takes the + following representation, bit 0: unused, bits[5:1] : amplitude, + bit 6: overdrive, bit 7: sign. Default sample value is 0x3E. + +Following properties are applicable only when "qcom,play-mode" is set to +"pwm". + +- pwms + Usage: required, if "qcom,play-mode" is set to "pwm". + Value type: + Definition: PWM device that is feeding its output to Haptics. + +- qcom,period-us + Usage: required, if "qcom,play-mode" is set to "pwm". + Value type: + Definition: PWM period in us. + +- qcom,duty-us + Usage: required, if "qcom,play-mode" is set to "pwm". + Value type: + Definition: PWM duty cycle in us. + +- qcom,ext-pwm-freq-khz + Usage: optional + Value type: + Definition: Frequency for external PWM in KHz. + Allowed values are: 25, 50, 75 and 100. + +- qcom,ext-pwm-dtest-line + Usage: optional + Value type: + Definition: DTEST line which is used for external PWM. + +Example: + qcom,haptics@c000 { + compatible = "qcom,qpnp-haptics"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_RISING>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hap-sc-irq", "hap-play-irq"; + qcom,pmic-revid = <&pmi8998_revid>; + qcom,pmic-misc = <&pmi8998_misc>; + qcom,misc-clk-trim-error-reg = <0xf3>; + qcom,actuator-type = <0>; + qcom,play-mode = "direct"; + qcom,vmax-mv = <3200>; + qcom,ilim-ma = <800>; + qcom,sc-dbc-cycles = <8>; + qcom,wave-play-rate-us = <6667>; + qcom,en-brake; + qcom,brake-pattern = <0x3 0x0 0x0 0x0>; + qcom,lra-high-z = "opt1"; + qcom,lra-auto-res-mode = "qwd"; + qcom,lra-res-cal-period = <4>; + }; diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt new file mode 100644 index 0000000000000000000000000000000000000000..2865019b3fccf2187f44b30174fdc1bd3086101d --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt @@ -0,0 +1,50 @@ +Qualcomm Technologies, Inc. Vibrator-LDO + +QPNP (Qualcomm Technologies, Inc. Plug N Play) Vibrator-LDO is a peripheral +on some QTI PMICs. It can be interfaced with the host processor via SPMI. + +Vibrator-LDO peripheral supports Eccentric Rotation Mass (ERM) vibrator. + +Properties: + +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-vibrator-ldo". + +- reg + Usage: required + Value type: + Definition: Base address of vibrator-ldo peripheral. + +- qcom,vib-ldo-volt-uv + Usage: required + Value type: + Definition: The optimal voltage requirement of the vibrator motor for + a normal vibration. Value is specified in microvolts. + +- qcom,disable-overdrive + Usage: optional + Value type: + Definition: Do not apply overdrive voltage. + +- qcom,vib-overdrive-volt-uv + Usage: optional and not required if qcom,disable-overdrive present + Value type: + Definition: The voltage in microvolts used as overdrive factor for + improving motor reactivity at the start of vibration. + If this property not specified, a default value of + 2 times the value specified in qcom,vib-ldo-volt-uv + property is used. + +======= +Example +======= + +pmi632_vib: qcom,vibrator@5700 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5700 0x100>; + qcom,vib-ldo-volt-uv = <1504000>; + qcom,disable-overdrive; + qcom,vib-overdrive-volt-uv = <3544000>; +}; diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index 1e6aac56c44efaafb910194970966bab3520e79d..c7268ef07f592a58af2b10eb4c37e18383fea064 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -78,6 +78,15 @@ Optional properties for WLED: - qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be controlled dynamically when WLED module is enabled or disabled. +- qcom,auto-calibration-enable : A boolean property which enables auto-calibration + of the WLED sink configuration. +- qcom,wled-brightness-map : Array of brightness map codes of size 256. + These codes will be mapped to the brightness + level requested in the scale of 0-4095. Code + entry is of 16 bit size. +- qcom,wled-stepper-en : A boolean property to specify if stepper algorithm + needs to be enabled. This needs the brightness map + table to be specified. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. @@ -121,4 +130,5 @@ Example: qcom,en-phase-stag; qcom,led-strings-list = [00 01 02 03]; qcom,en-ext-pfet-sc-pro; + qcom,wled-brightness-map = /bits/ 16 <0 . . 4095>; }; diff --git a/Documentation/devicetree/bindings/leds/leds-qti-tri-led.txt b/Documentation/devicetree/bindings/leds/leds-qti-tri-led.txt new file mode 100644 index 0000000000000000000000000000000000000000..c088d429ef3d8eddafbc6e4540c79089b90e8a0a --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-qti-tri-led.txt @@ -0,0 +1,60 @@ +Qualcomm Technologies, Inc. TRI_LED driver specific bindings + +This binding document describes the properties of TRI_LED module in +Qualcomm Technologies, Inc. PMIC chips. + +- compatible: + Usage: required + Value type: + Definition: Must be "qcom,tri-led". + +- reg: + Usage: required + Value type: + Definition: Register base of the TRI_LED module and length. + +Properties for child nodes: +- pwms: + Usage: required + Value type: + Definition: The PWM device (phandle) used for controlling LED. + +- led-sources: + Usage: required + Value type: + Definition: see Documentation/devicetree/bindings/leds/common.txt; + Device current output identifiers are: 0 - LED1_EN, + 1 - LED2_EN, 2 - LED3_EN. + +- label: + Usage: optional + Value type: + Definition: see Documentation/devicetree/bindings/leds/common.txt; + +- linux,default-trigger: + Usage: optional + Value_type: + Definition: see Documentation/devicetree/bindings/leds/common.txt; + +Example: + + pmi8998_rgb: tri-led@d000{ + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + + red { + label = "red"; + pwms = <&pmi8998_lpg 4 1000000>; + led-sources = <0>; + }; + green { + label = "green"; + pwms = <&pmi8998_lpg 3 1000000>; + led-sources = <1>; + }; + blue { + label = "blue"; + pwms = <&pmi8998_lpg 2 1000000>; + led-sources = <2>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt index 8e2bdee210775170bc438ce0458d0a21c8c6cd7c..cd4d222021c497c2d0874a776ff2d08d83241368 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt @@ -13,16 +13,16 @@ Required properties: property defined. - gpios : should contain phandle to gpio controller node and array of #gpio-cells specifying specific gpio (controller specific) -- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor -- qcom,gpio-req-tbl-flags : should contain direction of gpios present in - qcom,gpio-req-tbl-num property (in the same order) -- qcom,gpio-req-tbl-label : should contain name of gpios present in - qcom,gpio-req-tbl-num property (in the same order) +- gpio-req-tbl-num : should contain index to gpios specific to this sensor +- gpio-req-tbl-flags : should contain direction of gpios present in + gpio-req-tbl-num property (in the same order) +- gpio-req-tbl-label : should contain name of gpios present in + gpio-req-tbl-num property (in the same order) - clock-names: name of the clocks required for the device - clock-rates: clock rate in Hz Optional properties: -- qcom,cam-vreg-name : name of the voltage regulators required for the device. +- regulator-names : name of the voltage regulators required for the device. - gdscr-supply : should contain gdsr regulator used for cci clocks. - mmagic-supply : should contain mmagic regulator used for mmagic clocks. @@ -43,18 +43,31 @@ like default * Qualcomm Technologies, Inc. CCI clock settings Optional properties: -- qcom,hw-thigh : should contain high period of the SCL clock in terms of CCI - clock cycle -- qcom,hw-tlow : should contain high period of the SCL clock in terms of CCI - clock cycle -- qcom,hw-tsu-sto : should contain setup time for STOP condition -- qcom,hw-tsu-sta : should contain setup time for Repeated START condition -- qcom,hw-thd-dat : should contain hold time for the data -- qcom,hw-thd-sta : should contain hold time for START condition -- qcom,hw-tbuf : should contain free time between a STOP and a START condition -- qcom,hw-scl-stretch-en : should contain enable or disable clock stretching -- qcom,hw-trdhld : should contain internal hold time for SDA -- qcom,hw-tsp : should contain filtering of glitches +- hw-thigh : should contain high period of the SCL clock in terms of CCI clock cycle +- hw-tlow : should contain high period of the SCL clock in terms of CCI clock cycle +- hw-tsu-sto : should contain setup time for STOP condition +- hw-tsu-sta : should contain setup time for Repeated START condition +- hw-thd-dat : should contain hold time for the data +- hw-thd-sta : should contain hold time for START condition +- hw-tbuf : should contain free time between a STOP and a START condition +- hw-scl-stretch-en : should contain enable or disable clock stretching +- hw-trdhld : should contain internal hold time for SDA +- hw-tsp : should contain filtering of glitches + +* Qualcomm Technologies, Inc. MSM Camera Sensor Resource Manager + +MSM camera sensor resource manager node contains properties of shared camera +sensor resource. + +Required properties: +- compatible : should be manufacturer name followed by sensor name + - "qcom,cam-res-mgr" +Optional properties: +- shared-gpios : should contain the gpios which are used by two or more + cameras, and these cameras may be opened together. +- pinctrl-names: List of names to assign the shared pin state defined in pinctrl device node +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl device node. * Qualcomm Technologies, Inc. MSM Sensor @@ -64,7 +77,7 @@ Required properties: - compatible : should be manufacturer name followed by sensor name - "qcom,camera" - reg : should contain i2c slave address of the device -- qcom,csiphy-sd-index : should contain csiphy instance that will used to +- csiphy-sd-index : should contain csiphy instance that will used to receive sensor data - 0, 1, 2 - cam_vdig-supply : should contain regulator from which digital voltage is @@ -72,67 +85,69 @@ Required properties: - cam_vana-supply : should contain regulator from which analog voltage is supplied - cam_vio-supply : should contain regulator from which IO voltage is supplied -- qcom,cam-vreg-name : should contain names of all regulators needed by this +- regulator-names : should contain names of all regulators needed by this sensor - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf" -- qcom,cam-vreg-min-voltage : should contain minimum voltage level for - regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-max-voltage : should contain maximum voltage level for - regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators - mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,sensor-position-roll : should contain sensor rotational angle with respect +- rgltr-cntrl-support : It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage +- rgltr-min-voltage : should contain minimum voltage level for + regulators mentioned in regulator-names property (in the same order) +- rgltr-max-voltage : should contain maximum voltage level for + regulators mentioned in regulator-names property (in the same order) +- rgltr-load-current : should contain optimum voltage level for regulators + mentioned in regulator-names property (in the same order) +- sensor-position-roll : should contain sensor rotational angle with respect to axis of reference - 0, 90, 180, 360 -- qcom,sensor-position-pitch : should contain sensor rotational angle with respect +- sensor-position-pitch : should contain sensor rotational angle with respect to axis of reference - 0, 90, 180, 360 -- qcom,sensor-position-yaw : should contain sensor rotational angle with respect +- sensor-position-yaw : should contain sensor rotational angle with respect to axis of reference - 0, 90, 180, 360 Optional properties: -- qcom,slave-id : should contain i2c slave address, device id address, expected +- slave-id : should contain i2c slave address, device id address, expected id read value and device id mask -- qcom,sensor-name : should contain unique sensor name to differentiate from +- sensor-name : should contain unique sensor name to differentiate from other sensor - "s5k3l1yx" -- qcom,sensor-mode : should contain sensor mode supported +- sensor-mode : should contain sensor mode supported - 0 -> back camera 2D - 1 -> front camera 2D - 2 -> back camera 3D - 3 -> back camera int 3D -- qcom,sensor-type : should contain format of data that sensor streams +- sensor-type : should contain format of data that sensor streams - 0 -> bayer format - 1 -> yuv format - qcom,secure : should be enabled to operate the camera in secure mode - 0, 1 -- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is +- gpio-no-mux : should contain field to indicate whether gpio mux table is available - 1 if gpio mux is not available, 0 otherwise - cam_vaf-supply : should contain regulator from which AF voltage is supplied - gpios : should contain phandle to gpio controller node and array of - #gpio-cells specifying specific gpio (controller specific) -- qcom,gpio-reset : should contain index to gpio used by sensors reset_n -- qcom,gpio-standby : should contain index to gpio used by sensors standby_n -- qcom,gpio-vio : should contain index to gpio used by sensors io vreg enable -- qcom,gpio-vana : should contain index to gpio used by sensors analog vreg enable -- qcom,gpio-vdig : should contain index to gpio used by sensors digital vreg enable -- qcom,gpio-vaf : should contain index to gpio used by sensors af vreg enable -- qcom,gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n -- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor -- qcom,gpio-req-tbl-flags : should contain direction of gpios present in - qcom,gpio-req-tbl-num property (in the same order) -- qcom,gpio-req-tbl-label : should contain name of gpios present in - qcom,gpio-req-tbl-num property (in the same order) -- qcom,gpio-set-tbl-num : should contain index of gpios that need to be + #gpio-cells specifying specific gpio (controller specific) +- gpio-reset : should contain index to gpio used by sensors reset_n +- gpio-standby : should contain index to gpio used by sensors standby_n +- gpio-vio : should contain index to gpio used by sensors io vreg enable +- gpio-vana : should contain index to gpio used by sensors analog vreg enable +- gpio-vdig : should contain index to gpio used by sensors digital vreg enable +- gpio-vaf : should contain index to gpio used by sensors af vreg enable +- gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n +- gpio-req-tbl-num : should contain index to gpios specific to this sensor +- gpio-req-tbl-flags : should contain direction of gpios present in + gpio-req-tbl-num property (in the same order) +- gpio-req-tbl-label : should contain name of gpios present in + gpio-req-tbl-num property (in the same order) +- gpio-set-tbl-num : should contain index of gpios that need to be configured by msm -- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios - present in qcom,gpio-set-tbl-num property (in the same order) -- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring +- gpio-set-tbl-flags : should contain value to be configured for the gpios + present in gpio-set-tbl-num property (in the same order) +- gpio-set-tbl-delay : should contain amount of delay after configuring gpios as specified in gpio_set_tbl_flags property (in the same order) -- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should +- csi-phy-sel : should contain CSIPHY core instance from which CSID should receive data -- qcom,actuator-cam-name : should contain actuator cam name associated with +- actuator-cam-name : should contain actuator cam name associated with this sensor - If actuator does not exist, this property should not be initialized - If actuator exist, this field should indicate the index of actuator to @@ -141,30 +156,43 @@ Optional properties: for actuator - qcom,actuator-vcm-enable : should contain value to be set for actuator vcm gpio -- qcom,sensor-position : should contain the mount angle of the camera sensor +- sensor-position : should contain the mount angle of the camera sensor - 0 -> back camera - 1 -> front camera -- qcom,cci-master : should contain i2c master id to be used for this camera +- cci-master : should contain i2c master id to be used for this camera sensor - 0 -> MASTER 0 - 1 -> MASTER 1 -- qcom,actuator-src : if auto focus is supported by this sensor, this +- actuator-src : if auto focus is supported by this sensor, this property should contain phandle of respective actuator node -- qcom,led-flash-src : if LED flash is supported by this sensor, this +- led-flash-src : if LED flash is supported by this sensor, this property should contain phandle of respective LED flash node - qcom,vdd-cx-supply : should contain regulator from which cx voltage is supplied - qcom,vdd-cx-name : should contain names of cx regulator -- qcom,eeprom-src : if eeprom memory is supported by this sensor, this +- eeprom-src : if eeprom memory is supported by this sensor, this property should contain phandle of respective eeprom nodes -- qcom,ois-src : if optical image stabilization is supported by this sensor, +- ois-src : if optical image stabilization is supported by this sensor, this property should contain phandle of respective ois node -- qcom,ir-led-src : if ir led is supported by this sensor, this property +- ir-led-src : if ir led is supported by this sensor, this property should contain phandle of respective ir-led node - qcom,ir-cut-src : if ir cut is supported by this sensor, this property should contain phandle of respective ir-cut node - qcom,special-support-sensors: if only some special sensors are supported on this board, add sensor name in this property. +- use-shared-clk : It is booloean property. This property is required + if the clk is shared clk between different sensor and ois, if this + device need to be opened together. +- clock-rates: clock rate in Hz. +- clock-cntl-level: says what all different cloc level node has. +- clock-cntl-support: Says whether clock control support is present or not +- clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property clock-rates. * Qualcomm Technologies, Inc. MSM ACTUATOR @@ -175,20 +203,22 @@ Required properties: data field which is 0x0 - compatible : - "qcom,actuator" -- qcom,cci-master : should contain i2c master id to be used for this camera +- cci-master : should contain i2c master id to be used for this camera sensor - 0 -> MASTER 0 - 1 -> MASTER 1 Optional properties: -- qcom,cam-vreg-name : should contain names of all regulators needed by this +- regulator-names : should contain names of all regulators needed by this actuator - "cam_vaf" -- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts - for regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts - for regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-op-mode : should contain the maximum current in microamps - required from the regulators mentioned in the qcom,cam-vreg-name property +- rgltr-cntrl-support : It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage +- rgltr-min-voltage : should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) +- rgltr-max-voltage : should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) +- rgltr-load-current : should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property (in the same order). - cam_vaf-supply : should contain regulator from which AF voltage is supplied @@ -201,32 +231,38 @@ Required properties: data field which is 0x0 - compatible : - "qcom,ois" -- qcom,cci-master : should contain i2c master id to be used for this camera +- cci-master : should contain i2c master id to be used for this camera sensor - 0 -> MASTER 0 - 1 -> MASTER 1 +- clock-rates: clock rate in Hz. Optional properties: -- qcom,cam-vreg-name : should contain names of all regulators needed by this +- regulator-names : should contain names of all regulators needed by this ois - "cam_vaf" -- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts - for regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts - for regulators mentioned in qcom,cam-vreg-name property (in the same order) -- qcom,cam-vreg-op-mode : should contain the maximum current in microamps - required from the regulators mentioned in the qcom,cam-vreg-name property +- rgltr-cntrl-support : It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage +- rgltr-min-voltage : should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) +- rgltr-max-voltage : should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) +- rgltr-load-current : should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property (in the same order). - cam_vaf-supply : should contain regulator from which ois voltage is supplied +- use-shared-clk : It is booloean property. This property is required + if the clk is shared clk between different sensor and ois, if this + device need to be opened together. Example: led_flash0: qcom,camera-flash@0 { cell-index = <0>; compatible = "qcom,camera-flash"; - qcom,flash-source = <&pmi8994_flash0 &pmi8994_flash1>; - qcom,torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - qcom,switch-source = <&pmi8998_switch>; + flash-source = <&pmi8994_flash0 &pmi8994_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch>; status = "ok"; } @@ -238,70 +274,71 @@ qcom,cci@0xfda0c000 { interrupts = <0 50 0>; interrupt-names = "cci"; clock-names = "camnoc_axi_clk", "soc_ahb_clk", - "slow_ahb_src_clk", "cpas_ahb_clk", - "cci_clk", "cci_clk_src"; - qcom,clock-rates = <0 0 80000000 0 0 37500000>; + "slow_ahb_src_clk", "cpas_ahb_clk", + "cci_clk", "cci_clk_src"; + clock-rates = <0 0 80000000 0 0 37500000>; + clock-cntl-level = "turbo"; gpios = <&tlmm 17 0>, <&tlmm 18 0>, <&tlmm 19 0>, <&tlmm 20 0>; - qcom,gpio-tbl-num = <0 1 2 3>; - qcom,gpio-tbl-flags = <1 1 1 1>; - qcom,gpio-tbl-label = "CCI_I2C_DATA0", + gpio-tbl-num = <0 1 2 3>; + gpio-tbl-flags = <1 1 1 1>; + gpio-tbl-label = "CCI_I2C_DATA0", "CCI_I2C_CLK0", "CCI_I2C_DATA1", "CCI_I2C_CLK1"; i2c_freq_100Khz: qcom,i2c_standard_mode { - qcom,hw-thigh = <78>; - qcom,hw-tlow = <114>; - qcom,hw-tsu-sto = <28>; - qcom,hw-tsu-sta = <28>; - qcom,hw-thd-dat = <10>; - qcom,hw-thd-sta = <77>; - qcom,hw-tbuf = <118>; - qcom,hw-scl-stretch-en = <0>; - qcom,hw-trdhld = <6>; - qcom,hw-tsp = <1>; + hw-thigh = <78>; + hw-tlow = <114>; + hw-tsu-sto = <28>; + hw-tsu-sta = <28>; + hw-thd-dat = <10>; + hw-thd-sta = <77>; + hw-tbuf = <118>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <1>; status = "ok"; }; i2c_freq_400Khz: qcom,i2c_fast_mode { - qcom,hw-thigh = <20>; - qcom,hw-tlow = <28>; - qcom,hw-tsu-sto = <21>; - qcom,hw-tsu-sta = <21>; - qcom,hw-thd-dat = <13>; - qcom,hw-thd-sta = <18>; - qcom,hw-tbuf = <25>; - qcom,hw-scl-stretch-en = <0>; - qcom,hw-trdhld = <6>; - qcom,hw-tsp = <3>; + hw-thigh = <20>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; status = "ok"; }; i2c_freq_custom: qcom,i2c_custom_mode { - qcom,hw-thigh = <15>; - qcom,hw-tlow = <28>; - qcom,hw-tsu-sto = <21>; - qcom,hw-tsu-sta = <21>; - qcom,hw-thd-dat = <13>; - qcom,hw-thd-sta = <18>; - qcom,hw-tbuf = <25>; - qcom,hw-scl-stretch-en = <1>; - qcom,hw-trdhld = <6>; - qcom,hw-tsp = <3>; + hw-thigh = <15>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; status = "ok"; }; i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { - qcom,hw-thigh = <16>; - qcom,hw-tlow = <22>; - qcom,hw-tsu-sto = <17>; - qcom,hw-tsu-sta = <18>; - qcom,hw-thd-dat = <16>; - qcom,hw-thd-sta = <15>; - qcom,hw-tbuf = <19>; - qcom,hw-scl-stretch-en = <1>; - qcom,hw-trdhld = <3>; - qcom,hw-tsp = <3>; - qcom,cci-clk-src = <37500000>; + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <19>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; status = "ok"; }; @@ -309,34 +346,45 @@ qcom,cci@0xfda0c000 { cell-index = <0>; reg = <0x0>; compatible = "qcom,actuator"; - qcom,cci-master = <0>; + cci-master = <0>; cam_vaf-supply = <&pmi8998_bob>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <100000>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <18 19>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_shared_clk_active &cam_res_mgr_active>; + pinctrl-1 = <&cam_shared_clk_suspend &cam_res_mgr_suspend>; }; qcom,cam-sensor@0 { cell-index = <0>; compatible = "qcom,camera"; reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <180>; - qcom,secure = <1>; - qcom,led-flash-src = <&led_flash0>; - qcom,actuator-src = <&actuator0>; - qcom,eeprom-src = <&eeprom0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + secure = <1>; + led-flash-src = <&led_flash0>; + actuator-src = <&actuator0>; + eeprom-src = <&eeprom0>; cam_vdig-supply = <&pm845_s3>; cam_vio-supply = <&pm845_lvs1>; cam_vana-supply = <&pmi8998_bob>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-min-voltage = <0 3312000 1352000>; - qcom,cam-vreg-max-voltage = <0 3312000 1352000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1352000>; + rgltr-max-voltage = <0 3312000 1352000>; + rgltr-load-current = <0 80000 105000>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>; @@ -345,19 +393,21 @@ qcom,cci@0xfda0c000 { gpios = <&tlmm 13 0>, <&tlmm 80 0>, <&tlmm 79 0>; - qcom,gpio-reset = <1>; - qcom,gpio-standby = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", "CAM_VANA"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; status = "ok"; + use-shared-clk; clocks = <&clock_mmss clk_mclk0_clk_src>, <&clock_mmss clk_camss_mclk0_clk>; clock-names = "cam_src_clk", "cam_clk"; + clock-cntl-level; }; }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cdm.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dc661f8213807b9469efe8d43740763aadc20e0 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-cdm.txt @@ -0,0 +1,154 @@ +* Qualcomm Technologies, Inc. MSM Camera CDM + +CDM (Camera Data Mover) is module intended to provide means for fast programming +camera registers and lookup tables. + +======================= +Required Node Structure +======================= +CDM Interface node takes care of the handling has HW nodes and provide interface +for camera clients. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-cdm-intf". + +- label + Usage: required + Value type: + Definition: Should be "cam-cdm-intf". + +- num-hw-cdm + Usage: required + Value type: + Definition: Number of supported HW blocks. + +- cdm-client-names + Usage: required + Value type: + Definition: List of Clients supported by CDM interface. + +Example: + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpeg-dma", + "jpeg", + "fd"; + }; + +======================= +Required Node Structure +======================= +CDM HW node provides interface for camera clients through +to CDM interface node. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-cdm-intf". + +- label + Usage: required + Value type: + Definition: Should be "cpas-cdm". + +- reg-names + Usage: required + Value type: + Definition: Name of the register resources. + +- reg + Usage: required + Value type: + Definition: Register values. + +- reg-cam-base + Usage: required + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with CDM HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for CDM HW. + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CDM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CDM HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- cdm-client-names + Usage: required + Value type: + Definition: List of Clients supported by CDM HW node. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Example: + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm0"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "soc_ahb_clk", + "titan_top_ahb_clk", + "cam_axi_clk", + "camcc_slow_ahb_clk_src", + "cpas_top_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + qcom,clock-rates = <0 80000000 80000000 80000000 80000000 80000000>; + cdm-client-names = "ife"; + clock-cntl-level = "turbo"; + status = "ok"; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b16103946167fe33518b7252f2bbd07268a708a --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt @@ -0,0 +1,306 @@ +* Qualcomm Technologies, Inc. MSM Camera CPAS + +The MSM camera CPAS device provides dependency definitions for +enabling Camera CPAS HW and provides the Client definitions +for all HW blocks that use CPAS driver for BW voting. These +definitions consist of various properties that define the list +of clients supported, AHB, AXI master-slave IDs used for BW +voting. + +======================= +Required Node Structure +======================= +The camera CPAS device must be described in four levels of device nodes. The +first level describes the overall CPAS device. Within it, second level nodes +describe the list of AXI ports that map different clients for AXI BW voting. +Third level nodes describe the details of each AXI port having name, mnoc, +camnoc AXI Bus information. Fourth level nodes describe the details of Bus +master-slave IDs, ab, ib values for mnoc, camnoc bus interface. + +================================== +First Level Node - CAM CPAS device +================================== +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-cpas". + +- label + Usage: required + Value type: + Definition: Should be "cpas". + +- arch-compat + Usage: required + Value type: + Definition: Should be "cpas_top" or "camss_top". + +- reg-names + Usage: required + Value type: + Definition: Name of the register resources. + +- reg + Usage: required + Value type: + Definition: Register values. + +- reg-cam-base + Usage: required + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with CAMNOC HW. + +- qcom,cpas-hw-ver + Usage: required + Value type: + Definition: CAM HW Version information. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for CPAS HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CPAS HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CPAS HW. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +- qcom,msm-bus,name +- qcom,msm-bus,num-cases +- qcom,msm-bus,num-paths +- qcom,msm-bus,vectors-KBps + Please refer Documentation/devicetree/bindings/arm/msm/msm_bus.txt + for the properties above. + +- vdd-corners + Usage: required + Value type: + Definition: List of vdd corners to map for ahb level. + +- vdd-corner-ahb-mapping + Usage: required + Value type: + Definition: List of ahb level strings corresponds to vdd-corners. + Supported strings: suspend, svs, nominal, turbo + +- client-id-based + Usage: required + Value type: + Definition: Bool property specifying whether CPAS clients are ID based. + +- client-names + Usage: required + Value type: + Definition: List of Clients supported by CPAS. + +- client-axi-port-names + Usage: required + Value type: + Definition: AXI Port name for each client. + +- client-bus-camnoc-based + Usage: required + Value type: + Definition: Bool property specifying whether Clients are connected + through CAMNOC for AXI access. + +=================================================================== +Third Level Node - CAM AXI Port properties +=================================================================== +- qcom,axi-port-name + Usage: required + Value type: + Definition: Name of the AXI Port. + +=================================================================== +Fourth Level Node - CAM AXI Bus properties +=================================================================== + +- qcom,msm-bus,name +- qcom,msm-bus,num-cases +- qcom,msm-bus,num-paths +- qcom,msm-bus,vectors-KBps + Please refer Documentation/devicetree/bindings/arm/msm/msm_bus.txt + for the properties above. + +- qcom,msm-bus-vector-dyn-vote + Usage: optional + Value type: + Definition: Bool property specifying whether this bus client + is dynamic vote based. + +Example: + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170100>; /* Titan v170 v1.0.0 */ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 80000000 0>; + clock-cntl-level = "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + client-id-based; + client-names = + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg0", "fd0"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt index e8a74b30da19f6cad2c81e5d16382be07b2170a4..8ee02bf35f7b067f6abdcd790d349c421403daff 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt @@ -6,13 +6,15 @@ Required properties: - "qcom,csiphy-v5.01" - reg : offset and length of the register set for the device for the csiphy operating in compatible mode. +reg-cam-base : offset of ceiphy in camera hw block - reg-names : should specify relevant names to each reg property defined. - interrupts : should contain the csiphy interrupt. - interrupt-names : should specify relevant names to each interrupts property defined. - clock-names: name of the clocks required for the device -- qcom,clock-rates: clock rate in Hz +- clock-rates: clock rate in Hz - 0 if appropriate clock is required but doesn't have to apply the rate +- clock-cntl-level: says what all different cloc level node has. Example: @@ -20,15 +22,20 @@ qcom,csiphy@ac65000 { cell-index = <0>; compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; reg = <0xac65000 0x200>; + reg-cam-base = <0x65000>; reg-names = "csiphy"; interrupts = <0 477 0>; interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; clock-names = "camnoc_axi_clk", "soc_ahb_clk", "slow_ahb_src_clk", "cpas_ahb_clk", "cphy_rx_clk_src", "csiphy0_clk", "csi0phytimer_clk_src", "csi0phytimer_clk", "ife_0_csid_clk", "ife_0_csid_clk_src"; - qcom,clock-rates = + clock-rates = <0 0 80000000 0 320000000 0 269333333 0 0 384000000>; + clock-cntl-level = "turbo"; status = "ok"; }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..83a58df5c9fc30770caaeb67022a6847b2095521 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt @@ -0,0 +1,489 @@ +* Qualcomm Technologies, Inc. MSM EEPROM + +EEPROM is an one time programmed(OTP) device that stores the calibration data +use for camera sensor. It may either be integrated in the sensor module or in +the sensor itself. As a result, the power, clock and GPIOs may be the same as +the camera sensor. The following describes the page block map, power supply, +clock, GPIO and power on sequence properties of the EEPROM device. + +======================================================= +Required Node Structure if probe happens from userspace +======================================================= +The EEPROM device is described in one level of the device node. + +====================================== +First Level Node - CAM EEPROM device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,eeprom". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for EEPROM HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property specifies if the regulator control is supported + e.g. rgltr-min-voltage. + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain the maximum current in microamps required for + the regulators mentioned in regulator-names property. + +- gpio-no-mux + Usage: required + Value type: + Definition: should specify the gpio mux type. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the eeprom. + +- gpio-reset + Usage: required + Value type: + Definition: should specify the reset gpio index. + +- gpio-standby + Usage: required + Value type: + Definition: should specify the standby gpio index. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels. + +- sensor-position + Usage: required + Value type: + Definition: should contain the mount angle of the camera sensor. + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor. + +- sensor-mode + Usage: required + Value type: + Definition: should contain sensor mode supported. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for EEPROM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for EEPROM HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: says what all different clock levels eeprom node has. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Example: + + eprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8998_l5>; + cam_vio-supply = <&pm8998_lvs1>; + regulator-names = "cam_vdig", "cam_vio"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 0>; + rgltr-max-voltage = <1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + +======================================================= +Required Node Structure if probe happens from kernel +======================================================= +The EEPROM device is described in one level of the device node. + +====================================== +First Level Node - CAM EEPROM device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,eeprom". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- qcom,eeprom-name + Usage: required + Value type: + Definition: Name of the EEPROM HW. + +- qcom,slave-addr + Usage: required + Value type: + Definition: Slave address of the EEPROM HW. + +- qcom,num-blocks + Usage: required + Value type: + Definition: Total block number that eeprom contains. + +- qcom,pageX + Usage: required + Value type: + Definition: List of values specifying page size, start address, + address type, data, data type, delay in ms. + size 0 stand for non-paged. + +- qcom,pollX + Usage: required + Value type: + Definition: List of values specifying poll size, poll reg address, + address type, data, data type, delay in ms. + size 0 stand for not used. + +- qcom,memX + Usage: required + Value type: + Definition: List of values specifying memory size, start address, + address type, data, data type, delay in ms. + size 0 stand for not used. + +- qcom,saddrX + Usage: required + Value type: + Definition: property should specify the slave address for block (%d). + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for EEPROM HW. + +- qcom,cmm-data-support + Usage: required + Value type: + Definition: Camera MultiModule data capability flag.. + +- qcom,cmm-data-compressed + Usage: required + Value type: + Definition: Camera MultiModule data compression flag. + +- qcom,cmm-data-offset + Usage: required + Value type: + Definition: Camera MultiModule data start offset. + +- qcom,cmm-data-size + Usage: required + Value type: + Definition: Camera MultiModule data size. + +- qcom,cam-power-seq-type + Usage: required + Value type: + Definition: should specify the power on sequence types. + +- qcom,cam-power-seq-val + Usage: required + Value type: + Definition: should specify the power on sequence values. + +- qcom,cam-power-seq-cfg-val + Usage: required + Value type: + Definition: should specify the power on sequence config values. + +- qcom,cam-power-seq-delay + Usage: required + Value type: + Definition: should specify the power on sequence delay time in ms. + +- spiop-read + Usage: required + Value type: + Definition: this array provides SPI read operation related data. + +- spiop-readseq + Usage: required + Value type: + Definition: this array provides SPI read sequence operation realted data. + +- spiop-queryid + Usage: required + Value type: + Definition: this array provides SPI query eeprom id operation related data. + +- spiop-pprog: + Usage: required + Value type: + Definition: this array provides SPI page program operation related data. + +- spiop-wenable + Usage: required + Value type: + Definition: this array provides SPI write enable operation related data. + +- spiop-readst + Usage: required + Value type: + Definition: this array provides SPI read destination operation related data. + +- spiop-erase + Usage: required + Value type: + Definition: this array provides SPI erase operation related data. + +- eeprom-idx + Usage: required + Value type: + Definition: this array provides eeprom id realted data. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property specifies if the regulator control is supported + e.g. rgltr-min-voltage. + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain the maximum current in microamps required for + the regulators mentioned in regulator-names property. + +- gpio-no-mux + Usage: required + Value type: + Definition: should specify the gpio mux type. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the eeprom. + +- gpio-reset + Usage: required + Value type: + Definition: should specify the reset gpio index. + +- gpio-standby + Usage: required + Value type: + Definition: should specify the standby gpio index. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels. + +- sensor-position + Usage: required + Value type: + Definition: should contain the mount angle of the camera sensor. + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor. + +- sensor-mode + Usage: required + Value type: + Definition: should contain sensor mode supported. + +- clock-cntl-level + Usage: required + Value type: + Definition: says what all different clock levels eeprom node has. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for EEPROM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for EEPROM HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Example: + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0x0>; + qcom,eeprom-name = "msm_eeprom"; + eeprom-id0 = <0xF8 0x15>; + eeprom-id1 = <0xEF 0x15>; + eeprom-id2 = <0xC2 0x36>; + eeprom-id3 = <0xC8 0x15>; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x60>; + qcom,num-blocks = <2>; + qcom,page0 = <1 0x100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0 1 1>; + qcom,mem0 = <0 0x0 2 0 1 0>; + qcom,page1 = <1 0x0200 2 0x8 1 1>; + qcom,pageen1 = <1 0x0202 2 0x01 1 10>; + qcom,poll1 = <0 0x0 2 0 1 1>; + qcom,mem1 = <32 0x3000 2 0 1 0>; + qcom,saddr1 = <0x62>; + qcom,cmm-data-support; + qcom,cmm-data-compressed; + qcom,cmm-data-offset = <0>; + qcom,cmm-data-size = <0>; + spiop-read = <0x03 3 0 0 0>; + spiop-readseq = <0x03 3 0 0 0>; + spiop-queryid = <0x90 3 0 0 0>; + spiop-pprog = <0x02 3 0 3 100>; + spiop-wenable = <0x06 0 0 0 0>; + spiop-readst = <0x05 0 0 0 0>; + spiop-erase = <0x20 3 0 10 100>; + qcom,cam-power-seq-type = "sensor_vreg", + "sensor_vreg", "sensor_clk", + "sensor_gpio", "sensor_gpio"; + qcom,cam-power-seq-val = "cam_vdig", + "cam_vio", "sensor_cam_mclk", + "sensor_gpio_reset", + "sensor_gpio_standby"; + qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>; + qcom,cam-power-seq-delay = <1 1 5 5 10>; + cam_vdig-supply = <&pm8998_l5>; + cam_vio-supply = <&pm8998_lvs1>; + regulator-names = "cam_vdig", "cam_vio"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 0>; + rgltr-max-voltage = <1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-cntl-level = "turbo"; + clock-names = "cam_clk"; + clock-rates = <24000000>; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf551f6bc8655e032daff840febd1ceae98ce781 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt @@ -0,0 +1,149 @@ +* Qualcomm Technologies, Inc. MSM Camera FD + +The MSM camera Face Detection device provides dependency definitions +for enabling Camera FD HW. MSM camera FD is implemented in multiple +device nodes. The root FD device node has properties defined to hint +the driver about the FD HW nodes available during the probe sequence. +Each node has multiple properties defined for interrupts, clocks and +regulators. + +======================= +Required Node Structure +======================= +FD root interface node takes care of the handling Face Detection high level +driver handling and controls underlying FD hardware present. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-fd". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,fd". + +- num-fd + Usage: required + Value type: + Definition: Number of supported FD HW blocks. + +Example: + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + }; + +======================= +Required Node Structure +======================= +FD Node provides interface for Face Detection hardware driver +about the device register map, interrupt map, clocks, regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,fd41". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt line associated with FD HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for FD HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for FD HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks required for FD HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Examples: + cam_fd: qcom,fd@ac5a000 { + cell-index = <0>; + compatible = "qcom,fd41"; + reg-names = "fd_core", "fd_wrapper"; + reg = <0xac5a000 0x1000>, + <0xac5b000 0x400>; + reg-cam-base = <0x5a000 0x5b000>; + interrupt-names = "fd"; + interrupts = <0 462 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "fd_core_clk_src", + "fd_core_clk", + "fd_core_uar_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_FD_CORE_CLK_SRC>, + <&clock_camcc CAM_CC_FD_CORE_CLK>, + <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; + src-clock-name = "fd_core_clk_src"; + clock-cntl-level = "svs"; + clock-rates = <0 0 0 0 0 400000000 0 0>; + }; + diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt new file mode 100644 index 0000000000000000000000000000000000000000..ffc0e96a459de868e7c3072284a11b99945d852c --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt @@ -0,0 +1,257 @@ +* Qualcomm Technologies, Inc. MSM Camera ICP + +The MSM camera ICP devices are implemented multiple device nodes. +The root icp device node has properties defined to hint the driver +about the number of A5,IPE and BPS nodes available during the +probe sequence. Each node has multiple properties defined +for interrupts, clocks and regulators. + +======================= +Required Node Structure +======================= +ICP root interface node takes care of the handling account for number +of A5, IPE and BPS devices present on the hardware. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-icp". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,a5" or "qcom,ipe0" or "qcom,ipe1" or "qcom,bps". + +- num-a5 + Usage: required + Value type: + Definition: Number of supported A5 processors. + +- num-ipe + Usage: required + Value type: + Definition: Number of supported IPE HW blocks. + +- num-bps + Usage: required + Value type: + Definition: Number of supported BPS HW blocks. + +Example: + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", "qcom,ipe0", "qcom,ipe1", "qcom,bps"; + num-a5 = <1>; + num-ipe = <2>; + num-bps = <1>; + status = "ok"; + }; + +======================= +Required Node Structure +======================= +A5/IPE/BPS Node's provides interface for Image Control Processor driver +about the A5 register map, interrupt map, clocks, regulators +and name of firmware image. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-a5" or "qcom,cam-ipe" or "qcom,cam-bps". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Register values. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with CDM HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for CDM HW. + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CDM HW. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CDM HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: lowsvs, svs, svs_l1, nominal, turbo. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- fw_name + Usage: optional + Value type: + Definition: Name of firmware image. + +- ubwc-cfg + Usage: required + Value type: + Definition: UBWC configuration. + +Examples: +a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_apb_clk", + "icp_atb_clk", + "icp_clk", + "icp_clk_src", + "icp_cti_clk", + "icp_ts_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_APB_CLK>, + <&clock_camcc CAM_CC_ICP_ATB_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>, + <&clock_camcc CAM_CC_ICP_CTI_CLK>, + <&clock_camcc CAM_CC_ICP_TS_CLK>; + + clock-rates = <0 0 0 80000000 0 0 0 0 600000000 0 0>; + clock-cntl-level = "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x7F 0x1FF>; +}; + +qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; +}; + +qcom,ipe1 { + cell-index = <1>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe1-vdd"; + ipe1-vdd-supply = <&ipe_1_gdsc>; + clock-names = "ipe_1_ahb_clk", + "ipe_1_areg_clk", + "ipe_1_axi_clk", + "ipe_1_clk", + "ipe_1_clk_src"; + src-clock-name = "ipe_1_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_1_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_1_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; +}; + +bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = <0 0 0 0 200000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 600000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; +}; + diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9a5e0fc1bf1e3571bec857378997c164d32ec4d --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt @@ -0,0 +1,111 @@ +* Qualcomm Technologies, Inc. MSM Camera IFE CSID + +Camera IFE CSID device provides the definitions for enabling +the IFE CSID hardware. It also provides the functions for the client +to control the IFE CSID hardware. + +======================= +Required Node Structure +======================= +The IFE CSID device is described in one level of the device node. + +====================================== +First Level Node - CAM IFE CSID device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,csid170" or "qcom,csid-lite170". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should be "csid". + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with IFE CSID HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for IFE CSID HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for IFE CSID HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for IFE CSID HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + + + +Example: + + qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg = <0xacb3000 0x1000>; + reg-names = "csid"; + interrupts = <0 464 0>; + interrupt-names = "csid"; + vdd-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src"; + clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>; + clock-rates = <0 0 80000000 0 320000000 0 384000000 0 384000000>; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-isp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-isp.txt new file mode 100644 index 0000000000000000000000000000000000000000..13aae64ded9f5701ad0ffed89bcfcc8988c81488 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-isp.txt @@ -0,0 +1,31 @@ +* Qualcomm Technologies, Inc. MSM Camera ISP + +The MSM camera ISP driver provides the definitions for enabling +the Camera ISP hadware. It provides the functions for the Client to +control the ISP hardware. + +======================= +Required Node Structure +======================= +The camera ISP device is described in one level of device node. + +================================== +First Level Node - CAM ISP device +================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-isp". + +- arch-compat + Usage: required + Value type: + Definition: Should be "vfe" or "ife". + +Example: + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-jpeg.txt b/Documentation/devicetree/bindings/media/video/msm-cam-jpeg.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2ed98ebac79f10bd5023eed96066cdb5d6ddb06 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-jpeg.txt @@ -0,0 +1,187 @@ +* Qualcomm Technologies, Inc. MSM Camera JPEG + +The MSM camera JPEG devices are implemented multiple device nodes. +The root JPEG device node has properties defined to hint the driver +about the number of Encoder and DMA nodes available during the +probe sequence. Each node has multiple properties defined +for interrupts, clocks and regulators. + +======================= +Required Node Structure +======================= +JPEG root interface node takes care of the handling account for number +of Encoder and DMA devices present on the hardware. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-jpeg". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,jpegenc" or "qcom,jpegdma". + +- num-jpeg-enc + Usage: required + Value type: + Definition: Number of supported Encoder HW blocks. + +- num-jpeg-dma + Usage: required + Value type: + Definition: Number of supported DMA HW blocks. + +Example: + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + +======================= +Required Node Structure +======================= +Encoder/DMA Nodes provide interface for JPEG driver about +the device register map, interrupt map, clocks and regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam_jpeg_enc". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with JPEG HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for JPEG HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for JPEG HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for JPEG HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Examples: + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt b/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a37922dd93a1254710b3397ac18503948b6d556 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt @@ -0,0 +1,149 @@ +* Qualcomm Technologies, Inc. MSM Camera LRME + +The MSM camera Low Resolution Motion Estimation device provides dependency +definitions for enabling Camera LRME HW. MSM camera LRME is implemented in +multiple device nodes. The root LRME device node has properties defined to +hint the driver about the LRME HW nodes available during the probe sequence. +Each node has multiple properties defined for interrupts, clocks and +regulators. + +======================= +Required Node Structure +======================= +LRME root interface node takes care of the handling LRME high level +driver handling and controls underlying LRME hardware present. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-lrme" + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,lrme" + +- num-lrme + Usage: required + Value type: + Definition: Number of supported LRME HW blocks + +Example: + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + compat-hw-name = "qcom,lrme"; + num-lrme = <1>; + }; + +======================= +Required Node Structure +======================= +LRME Node provides interface for Low Resolution Motion Estimation hardware +driver about the device register map, interrupt map, clocks, regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,lrme" + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources + +- reg + Usage: optional + Value type: + Definition: Register values + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt + +- interrupts + Usage: optional + Value type: + Definition: Interrupt line associated with LRME HW + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for LRME HW + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names" + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for LRME HW + +- clocks + Usage: required + Value type: + Definition: List of clocks required for LRME HW + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name + +Examples: + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 0 0>, + <0 0 0 0 0 19200000 19200000>, + <0 0 0 0 0 19200000 19200000>, + <0 0 0 0 0 19200000 19200000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "lrme_core_clk_src"; + }; + diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt index 2ed913c973d5d3ffa67fcec3d574f09e89255610..728c5f9c50fd5c7c6a96227c577c9e6c816c8e1a 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt @@ -56,6 +56,11 @@ Second Level Node - CAM SMMU context bank device or firmware device Value type: Definition: Should specify a string label to identify the context bank. +- qcom,secure-cb + Usage: optional + Value type: boolean + Definition: Specifies if the context bank is a secure context bank. + ============================================= Third Level Node - CAM SMMU memory map device ============================================= @@ -84,6 +89,11 @@ Third Level Node - CAM SMMU memory map device - Scratch region: 0x02 - IO region: 0x03 +- iova-granularity + Usage: optional + Value type: + Definition: Should specify IOVA granularity for shared memory region. + Example: qcom,cam_smmu@0 { compatible = "qcom,msm-cam-smmu"; @@ -114,7 +124,8 @@ Example: iova-region-start = <0x7400000>; iova-region-len = <0x6400000>; iova-region-id = <0x1>; - status = "ok"; + iova-granularity = <0x15>; + status = "ok"; }; iova-mem-region-io { diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt new file mode 100644 index 0000000000000000000000000000000000000000..99f2c7a0be350ab45804b0cd032749e061123f8d --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -0,0 +1,129 @@ +* Qualcomm Technologies, Inc. MSM Camera VFE + +Camera VFE device provides the definitions for enabling +the VFE hardware. It also provides the functions for the client +to control the VFE hardware. + +======================= +Required Node Structure +======================= +The VFE device is described in one level of the device node. + +====================================== +First Level Node - CAM VFE device +====================================== +Required properties: +- compatible + Usage: required + Value type: + Definition: Should specify the compatibility string for matching the + driver. e.g. "qcom,vfe170", "qcom,vfe-lite170". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should specify the name of the register block. + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with VFE HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for VFE HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for VFE HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for VFE HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +Optional properties: +- clock-names-option + Usage: optional + Value type: + Definition: Optional clock names. + +- clocks-option + Usage: required if clock-names-option defined + Value type: + Definition: List of optinal clocks used for VFE HW. + +- clock-rates-option + Usage: required if clock-names-option defined + Value type: + Definition: List of clocks rates for optional clocks. + +Example: + qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + interrupts = <0 465 0>; + interrupt-names = "ife"; + vdd-names = "camss-vdd", "ife0-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + ife0-vdd-supply = <&ife_0_gdsc>; + clock-names = "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "camnoc_axi_clk", + "ife_axi_clk", + clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>, + clock-rates = <0 0 80000000 0 320000000 0 384000000 0 0 0>; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt new file mode 100644 index 0000000000000000000000000000000000000000..d24314ae196dce13c24adfa572e8617447571ffb --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt @@ -0,0 +1,126 @@ +* Qualcomm Technologies, Inc. MSM FLASH + +The MSM camera Flash driver provides the definitions for +enabling and disabling LED Torch/Flash by requesting it to +PMIC/I2C/GPIO based hardware. It provides the functions for +the Client to control the Flash hardware. + +======================================================= +Required Node Structure +======================================================= +The Flash device is described in one level of the device node. + +====================================== +First Level Node - CAM FLASH device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,camera-flash". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- flash-source + Usage: required + Value type: + Definition: Should contain array of phandles to Flash source nodes. + +- torch-source + Usage: required + Value type: + Definition: Should contain array of phandles to torch source nodes. + +- switch-source + Usage: Optional + Value type: + Definition: Should contain phandle to switch source nodes. + +- slave-id + Usage: optional + Value type: + Definition: should contain i2c slave address, device id address + and expected id read value. + +- cci-master + Usage: optional + Value type: + Definition: should contain i2c master id to be used for this camera + flash. + +- max-current + Usage: optional + Value type: + Definition: Max current in mA supported by flash + +- max-duration + Usage: optional + Value type: + Definition: Max duration in ms flash can glow. + +- gpios + Usage: optional + Value type: + Definition: should specify the gpios to be used for the flash. + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should specify the gpio labels. + +- gpio-flash-reset + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash reset" pin. + +- gpio-flash-en + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash enable" pin. + +- gpio-flash-now + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash now" pin. + +Example: + +led_flash_rear: qcom,camera-flash@0 { + reg = <0x00 0x00>; + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + qcom,slave-id = <0x00 0x00 0x0011>; + qcom,cci-master = <0>; + gpios = <&msmgpio 23 0>, + <&msmgpio 24 0>; + <&msmgpio 25 0>; + qcom,gpio-flash-reset = <0>; + qcom,gpio-flash-en = <0>; + qcom,gpio-flash-now = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <0 0>; + qcom,gpio-req-tbl-label = "FLASH_EN", + "FLASH_NOW"; + qcom,max-current = <1500>; + qcom,max-duration = <1200>; + }; diff --git a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt index 0295e1b4eaca61e911705116df2381c4bb486a60..5a92bf6e1a4316509a592ae3619418a1260aeed0 100644 --- a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt +++ b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt @@ -81,6 +81,37 @@ Optional properties limits. - qcom,mdss-rot-vbif-qos-setting: This array is used to program vbif qos remapper register priority for rotator clients. +- qcom,mdss-rot-vbif-memtype: Array of u32 vbif memory type settings for each xin port. +- qcom,mdss-rot-cdp-setting: Integer array of size two, to indicate client driven + prefetch is available or not. Index 0 represents + if CDP is enabled for read and index 1, if CDP + is enabled for write operation. +- qcom,mdss-rot-qos-lut A 4 cell property with the format of indicating the qos + lut settings for the rotator sspp and writeback + client. +- qcom,mdss-rot-danger-lut A two cell property with the format of indicating the danger lut settings for + the rotator sspp and writeback client. +- qcom,mdss-rot-safe-lut A two cell property with the format of indicating the safe lut settings for the + rotator sspp and writeback client. +- qcom,mdss-inline-rot-qos-lut: A 4 cell property with the format of indicating the qos + lut settings for the inline rotator sspp and + writeback client. +- qcom,mdss-inline-rot-danger-lut: A two cell property with the format of + indicating the danger lut + settings for the inline rotator sspp and + writeback client. +- qcom,mdss-inline-rot-safe-lut: A two cell property with the format of + indicating the safe lut + settings for the inline rotator sspp and + writeback client. +- qcom,mdss-rot-qos-cpu-mask: A u32 value indicating desired PM QoS CPU + affine mask. +- qcom,mdss-rot-qos-cpu-dma-latency: A u32 value indicating desired PM QoS CPU DMA + latency in usec. - qcom,mdss-rot-mode: This is integer value indicates operation mode of the rotator device - qcom,mdss-sbuf-headroom: This integer value indicates stream buffer headroom in lines. @@ -94,6 +125,9 @@ Optional properties minimum allowable length configuration value. - qcom,sde-ubwc-swizzle: A u32 property to specify the default UBWC swizzle configuration value. +- qcom,rot-reg-bus: Property to provide Bus scaling for register + access for rotator blocks. +- power-domains: A phandle to respective power domain node. Subnode properties: - compatible: Compatible name used in smmu v2. @@ -121,6 +155,8 @@ Example: interrupt-parent = <&mdss_mdp>; interrupts = <2 0>; + power-domains = <&mdss_mdp>; + qcom,mdss-mdp-reg-offset = <0x00001000>; rot-vdd-supply = <&gdsc_mdss>; @@ -145,14 +181,38 @@ Example: /* VBIF QoS remapper settings*/ qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>; + qcom,mdss-rot-vbif-memtype = <3 3>; + + com,mdss-rot-cdp-setting = <1 1>; qcom,mdss-default-ot-rd-limit = <8>; qcom,mdss-default-ot-wr-limit = <16>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0>; + + qcom,mdss-rot-qos-cpu-mask = <0xf>; + qcom,mdss-rot-qos-cpu-dma-latency = <75>; + + qcom,mdss-inline-rot-qos-lut = <0x0 0x0 0x00112233 0x44556677>; + qcom,mdss-inline-rot-danger-lut = <0x0 0x0000ffff>; + qcom,mdss-inline-rot-safe-lut = <0x0 0x0000ff00>; + qcom,mdss-sbuf-headroom = <20>; cache-slice-names = "rotator"; cache-slices = <&llcc 4>; + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { compatible = "qcom,smmu_sde_rot_unsec"; iommus = <&mdp_smmu 0xe00>; diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt b/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt deleted file mode 100644 index 84a8765b4af3fb4b6b57b736cc69ca379adde733..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt +++ /dev/null @@ -1,42 +0,0 @@ -* Qualcomm Technologies Inc MSM VIDC VMEM - -Required properties: -- compatible : "qcom,msm-vmem". -- interrupts : Contains the interrupt that maps to the VMEM module. -- reg : A set of 2 start address and size pairs that describe the hardware -register address space and mappable memory address space. -- reg-names : Strings that describe the pairs in "reg". The register address -space should be called "reg-base" and the memory space should be called "mem-base". -- clocks : A set of clocks that correspond to the AHB and MAXI clocks that the -hardware uses. -- clock-names : A string that describes the "clocks" property. The AHB clock -should be named "ahb" and the MAXI clock should be named "maxi". -- qcom,bank-size : The size of each memory bank, in bytes. -- vdd-supply: phandle to a regulator that is considered to be the footswitch for vmem. -- qcom,msm-bus,(name|num-cases,num-paths,vectors-KBps) - Bus to be voted for prior to - issuing any IO transactions to vmem. Refer to Documentation/devicetree/bindings/arm/\ - msm/msm_bus_adhoc.txt for further details. - -Example: - -qcom,vmem@880000 { - compatible = "qcom,msm-vmem"; - interrupts = <0 429 0>; - reg = <0x880000 0x800>, - <0x6800000 0x100000>; - reg-names = "reg-base", "mem-base"; - - vdd-supply = <&gdsc_mmagic_video>; - clocks = <&clock_mmss clk_vmem_ahb_clk>, - <&clock_mmss clk_vmem_maxi_clk>; - clock-names = "ahb", "maxi"; - - qcom,bank-size = <131072>; - - qcom,msm-bus,name = "vmem"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; -}; diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt index bdc0eba719a0681ba2f4ae9852c079ac8320da21..f0549cb7ec5333c904d458526629fe19f28b6327 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt @@ -6,20 +6,13 @@ Venus Required properties: - compatible : one of: - "qcom,msm-vidc" -- qcom,max-hw-load: The maximum load the hardware can support expressed in units - of macroblocks per second. The load is a reflection of hardware capability - rather than a performance guarantee. Performance is guaranteed only up to - advertised capability of the chipset. -- qcom,max-hq-mbs-per-frame : Max no of mbs per frame beyond which - "High Quality" encoding is not supported. -- qcom,max-hq-frames-per-sec : Max no of frames per second beyond which - "High Quality" encoding is not supported. + - "qcom,sdm845-vidc" : Invokes driver specific data for SDM845. + - "qcom,sdm670-vidc" : Invokes driver specific data for SDM670. Optional properties: - reg : offset and length of the register set for the device. +- sku-index : sku version of the hardware. - interrupts : should contain the vidc interrupt. -- qcom,platform-version : mask and shift of the platform version bits - in efuse register. - qcom,reg-presets : list of offset-value pairs for registers to be written. The offsets are from the base offset specified in 'reg'. This is mainly used for QoS, VBIF, etc. presets for video. @@ -64,20 +57,9 @@ Optional properties: macro block in low power mode. the required frequency to get the final frequency, the factor is represented in Q16 format. -- qcom,sw-power-collapse = A bool indicating if video hardware core can be - power collapsed in idle state. -- qcom,never-unload-fw = A bool indicating if video firmware should be not be - unloaded after all active sessions have closed. Once a new session starts up - after this, the firmware will be ready to go. This should be set on platforms - that desire low-latency video startup and don't mind "leakage" of some memory. - qcom,use-non-secure-pil = A bool indicating which type of pil to use to load the fw. - qcom,fw-bias = The address at which venus fw is loaded (manually). -- qcom,enable-thermal-mitigation = A bool to enable thermal mitigation when - thermal run away occurs. -- qcom,hfi-version = The hfi packetization version supported by venus firmware. - If hfi version is not specified, then packetization type will default to - legacy. - qcom,vidc-iommu-domains = node containing individual domain nodes, each with: - a unique domain name for the domain node (e.g vidc,domain-ns) - qcom,vidc-domain-phandle: phandle for the domain as defined in @@ -97,13 +79,9 @@ Optional properties: internal persist = 0x200 internal persist1 = 0x400 internal cmd queue = 0x800 -- qcom,pm-qos-latency-us = The latency used to vote for QOS power manager. This -value is typically max(latencies of every cluster at all power levels) + 1 -- qcom,max-secure-instances = An int containing max number of concurrent secure - instances supported, accounting for venus and system wide limitations like - memory, performance etc. -- qcom,debug-timeout = A bool indicating that FW errors such as SYS_ERROR, - SESSION_ERROR and timeouts will be treated as Fatal. +- cache-slice-names = An array of supported cache slice names by llcc +- cache-slices = An array of supported cache slice ids corresponding + to cache-slice-names by llcc [Second level nodes] Context Banks @@ -149,7 +127,7 @@ Required properties: Optional properties: - qcom,bus-governor : governor to use when scaling bus, generally any commonly found devfreq governor might be used. In addition to those governors, the - custom Venus governors, "msm-vidc-ddr" or "msm-vidc-vmem" are also + custom Venus governors, "msm-vidc-ddr" or "msm-vidc-llcc" are also acceptable values. In the absence of this property the "performance" governor is used. - qcom,bus-rage-kbps : an array of two items () that indicate the @@ -168,25 +146,16 @@ Example: venus-supply = <&gdsc>; venus-core0-supply = <&gdsc1>; venus-core1-supply = <&gdsc2>; - qcom,hfi-version = "3xx"; qcom,reg-presets = <0x80004 0x1>, <0x80178 0x00001FFF>; qcom,qdss-presets = <0xFC307000 0x1000>, <0xFC322000 0x1000>; - qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/ - qcom,never-unload-fw; clock-names = "foo_clk", "bar_clk", "baz_clk"; qcom,clock-configs = <0x3 0x1 0x0>; - qcom,sw-power-collapse; qcom,buffer-type-tz-usage-table = <0x1 0x1>, <0x1fe 0x2>; - qcom,enable-thermal-mitigation; - qcom,use-non-secure-pil; - qcom,use_dynamic_bw_update; qcom,fw-bias = <0xe000000>; qcom,allowed-clock-rates = <200000000 300000000 400000000>; - qcom,max-hq-mbs-per-frame = <8160>; - qcom,max-hq-frames-per-sec = <60>; msm_vidc_cb1: msm_vidc_cb1 { compatible = "qcom,msm-vidc,context-bank"; label = "venus_ns"; diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt index 6ac06c1b9aec8908095c0b2fc22af1882334293c..5b6bd970c95e6abe0220d1a3d65594a9fde0b974 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt @@ -42,6 +42,8 @@ Optional properties for peripheral child nodes: see: Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt - interrupt-names: Corresponding interrupt name to the interrupts property +- qcom,can-sleep: Boolean flag indicating that processes waiting on SPMI + transactions may sleep Each child node of SPMI slave id represents a function of the PMIC. In the example below the rtc device node represents a peripheral of pm8941 diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index 8a377827695bd2d13d169adc162b4129a043a422..f978c5859a1155ea9ae88295e79c15f8a0783589 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -52,6 +52,7 @@ Optional properties: - no-sdio: controller is limited to send sdio cmd during initialization - no-sd: controller is limited to send sd cmd during initialization - no-mmc: controller is limited to send mmc cmd during initialization +- extcon: phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details). *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line polarity properties, we have to fix the meaning of the "normal" and "inverted" diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index da9a632c2e13455aab964ac5b9fe8f203d3a0529..6c61ada705e3a4666adb2ce7aaf665a8028069a1 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -16,6 +16,9 @@ Required properties: Required "interrupt-names" are "hc_irq" and "pwr_irq". - -supply: phandle to the regulator device tree node Required "supply-name" are "vdd" and "vdd-io". + - qcom,ice-clk-rates: this is an array that specifies supported Inline + Crypto Engine (ICE) clock frequencies, Units - Hz. + - sdhc-msm-crypto: phandle to SDHC ICE node Required alias: - The slot number is specified via an alias with the following format @@ -38,6 +41,11 @@ Optional Properties: "HS200_1p2v" - indicates that host can support HS200 at 1.2v. "DDR_1p8v" - indicates that host can support DDR mode at 1.8v. "DDR_1p2v" - indicates that host can support DDR mode at 1.2v. + - qcom,bus-aggr-clk-rates: this is an array that specifies the frequency for + the bus-aggr-clk which should be set corresponding to the + frequency used from clk-rate. The Frequency of this clock + should be decided based on the power mode in which the + apps clk would run with frequency in clk-rates. - qcom,devfreq,freq-table - specifies supported frequencies for clock scaling. Clock scaling logic shall toggle between these frequencies based on card load. In case the defined frequencies are over or below @@ -77,7 +85,17 @@ Optional Properties: register dumps on CRC errors and also downgrade bus speed mode to SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable this workaround. - + - qcom,restore-after-cx-collapse - specifies whether the SDCC registers contents need + to be saved and restored by software when the CX Power Collapse feature is enabled. + On certain chipsets, coming out of the CX Power Collapse event, the SDCC registers + contents will not be retained. It is software responsibility to restore the + SDCC registers before resuming to normal operation. + - qcom,force-sdhc1-probe: Force probing sdhc1 even if it is not the boot device. + - qcom,ddr-config: Certain chipsets and platforms require particular settings for + the RCLK delay DLL configuration register for HS400 mode to work. + This value can vary between platforms and msms. If a msm/platform + require a different DLL setting than the default/POR setting for + HS400 mode, it can be specified using this field. In the following, can be vdd (flash core voltage) or vdd-io (I/O voltage). - qcom,-always-on - specifies whether supply should be kept "on" always. - qcom,-lpm_sup - specifies whether supply can be kept in low power mode (lpm). @@ -103,6 +121,10 @@ In the following, can be vdd (flash core voltage) or vdd-io (I/O voltag - qcom,wakeup-on-idle: if configured, the mmcqd thread will call set_wake_up_idle(), thereby voting for it to be called on idle CPUs. + - nvmem-cells: specifies the handle to represent the SoC revision. + usually it is defined by qfprom device node. + - nvmem-cell-names: specifies the given nvmem cell name as defined in + qfprom node. Example: @@ -116,6 +138,7 @@ Example: reg-names = "hc_mem", "core_mem"; interrupts = <0 123 0>, <0 138 0>; interrupt-names = "hc_irq", "pwr_irq"; + sdhc-msm-crypto = <&sdcc1_ice>; vdd-supply = <&pm8941_l21>; vdd-io-supply = <&pm8941_l13>; @@ -138,6 +161,7 @@ Example: qcom,nonremovable; qcom,large-address-bus; qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; + qcom,ice-clk-rates = <300000000 150000000>; qcom,scaling-lower-bus-speed-mode = "DDR52"; diff --git a/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d5f55d7a8ca2428e822abb5a6efd7c59b3564dd --- /dev/null +++ b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt @@ -0,0 +1,14 @@ +MSM HDCP driver + +Standalone driver managing HDCP related communications +between TZ and HLOS for MSM chipset. + +Required properties: + +compatible = "qcom,msm-hdcp"; + +Example: + +qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; +}; diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..a98e4aef7add0a86f25549142ff56f3b28525b04 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt @@ -0,0 +1,77 @@ +Qualcomm Technologies, Inc. Parallel Interface controller (QPIC) for NAND devices + +Required properties: +- compatible : "qcom,msm-nand". +- reg : should specify QPIC NANDc and BAM physical address range. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should specify QPIC/BAM interrupt numbers. +- interrupt-names : should specify relevant names to each interrupts property + defined. +- qcom,reg-adjustment-offset : Specify the base adjustment offset value for the + version registers +- qcom,qpic-clk-rpmh: Indicates whether QPIC clock is RPMH controlled clock or + not. + +MTD flash partition layout for NAND devices - + +Each partition is represented as a sub-node of the qcom,mtd-partitions device. +Each node's name represents the name of the corresponding partition. + +This is now completely optional as the partition information is avaialble from +bootloader. + +Optional properties: +- reg : boot_cfg. This is needed only on the targets where both NAND and eMMC + devices are supported. On eMMC based builds, NAND cannot be enabled by + default due to the absence of some of its required resources. +- reg : The partition offset and size +- label : The label / name for this partition. +- read-only: This parameter, if present, indicates that this partition + should only be mounted read-only. +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for +below optional properties: + - qcom,msm-bus,name + - qcom,msm-bus,num-cases + - qcom,msm-bus,active-only + - qcom,msm-bus,num-paths + - qcom,msm-bus,vectors-KBps + +Examples: + + qcom,nand@f9af0000 { + compatible = "qcom,msm-nand"; + reg = <0xf9af0000 0x1000>, + <0xf9ac4000 0x8000>, + <0x5e02c 0x4>; + reg-names = "nand_phys", + "bam_phys", + "boot_cfg"; + qcom,reg-adjustment-offset = <0x4000>; + + interrupts = <0 279 0>; + interrupt-names = "bam_irq"; + + qcom,msm-bus,name = "qpic_nand"; + qcom,msm-bus,num-cases = <1>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <91 512 0 0>, + qcom,qpic-clk-rpmh; + }; + + qcom,mtd-partitions { + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "boot"; + reg = <0x0 0x1000>; + read-only; + }; + partition@20000 { + label = "userdata"; + reg = <0x20000 0x1000>; + }; + partition@40000 { + label = "system"; + reg = <0x40000 0x1000>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt index c010fafc66a8e4d6f0b1543104ac352f82ec992f..c7194e87d5f4b7d9b61927a430479e39f52ddca8 100644 --- a/Documentation/devicetree/bindings/net/mediatek-net.txt +++ b/Documentation/devicetree/bindings/net/mediatek-net.txt @@ -7,7 +7,7 @@ have dual GMAC each represented by a child node.. * Ethernet controller node Required properties: -- compatible: Should be "mediatek,mt7623-eth" +- compatible: Should be "mediatek,mt2701-eth" - reg: Address and length of the register set for the device - interrupts: Should contain the three frame engines interrupts in numeric order. These are fe_int0, fe_int1 and fe_int2. diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt index bc1c3c8bf8fa37fa7e08dcabc65f1752a8a79749..62bdc5f2bf163dd8d91384a51f51f66a0fe592c3 100644 --- a/Documentation/devicetree/bindings/net/phy.txt +++ b/Documentation/devicetree/bindings/net/phy.txt @@ -35,6 +35,15 @@ Optional Properties: - broken-turn-around: If set, indicates the PHY device does not correctly release the turn around line low at the end of a MDIO transaction. +- eee-broken-100tx: +- eee-broken-1000t: +- eee-broken-10gt: +- eee-broken-1000kx: +- eee-broken-10gkx4: +- eee-broken-10gkr: + Mark the corresponding energy efficient ethernet mode as broken and + request the ethernet to stop advertising it. + Example: ethernet-phy@0 { diff --git a/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt b/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt new file mode 100644 index 0000000000000000000000000000000000000000..eff3d82e212403e251e7e6656dae6da1448a14f9 --- /dev/null +++ b/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt @@ -0,0 +1,61 @@ +Qualcomm Technologies Inc. EMAC Gigabit Ethernet controller + +This network controller consists of the MAC and +RGMII IO Macro for interfacing with PHY. + +Required properties: + +emac_hw node: +- compatible: Should be "qcom,emac-dwc-eqos" +- reg: Offset and length of the register regions for the mac and io-macro +- interrupts: Interrupt number used by this controller +- io-macro-info: Internal io-macro-info + +Optional: +- qcom,msm-bus,name: String representing the client-name +- qcom,msm-bus,num-cases: Total number of usecases +- qcom,msm-bus,num-paths: Total number of master-slave pairs +- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing: + master-id, slave-id, arbitrated bandwidth + in KBps, instantaneous bandwidth in KBps +qcom,bus-vector-names: specifies string IDs for the corresponding bus vectors + in the same order as qcom,msm-bus,vectors-KBps property. + +Internal io-macro-info: +- io-macro-bypass-mode: <0 or 1> internal or external delay configuration +- io-interface: PHY interface used + +Example: + +soc { + emac_hw: qcom,emac@00020000 { + compatible = "qcom,emac-dwc-eqos"; + reg = <0x20000 0x10000>, + <0x36000 0x100>; + reg-names = "emac-base", "rgmii-base"; + interrupts = <0 62 4>, <0 60 4>, + <0 49 4>, <0 50 4>, + <0 51 4>, <0 52 4>, + <0 53 4>, <0 54 4>, + <0 55 4>, <0 56 4>, + <0 57 4>; + interrupt-names = "sbd-intr", "lpi-intr", + "tx-ch0-intr", "tx-ch1-intr", + "tx-ch2-intr", "tx-ch3-intr", + "tx-ch4-intr", "rx-ch0-intr", + "rx-ch1-intr", "rx-ch2-intr", + "rx-ch3-intr"; + qcom,msm-bus,name = "emac"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + qcom,bus-vector-names = "10", "100", "1000"; + io-macro-info { + io-macro-bypass-mode = <0>; + io-interface = "rgmii"; + }; + }; +} diff --git a/Documentation/devicetree/bindings/net/ti,dp83867.txt b/Documentation/devicetree/bindings/net/ti,dp83867.txt index 5d21141a68b547104d5f152da0214dc847f4a3e9..75bcaa3558802e6f53e8a0b9256bb5876a58a12d 100644 --- a/Documentation/devicetree/bindings/net/ti,dp83867.txt +++ b/Documentation/devicetree/bindings/net/ti,dp83867.txt @@ -3,9 +3,11 @@ Required properties: - reg - The ID number for the phy, usually a small integer - ti,rx-internal-delay - RGMII Receive Clock Delay - see dt-bindings/net/ti-dp83867.h - for applicable values + for applicable values. Required only if interface type is + PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_RXID - ti,tx-internal-delay - RGMII Transmit Clock Delay - see dt-bindings/net/ti-dp83867.h - for applicable values + for applicable values. Required only if interface type is + PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_TXID - ti,fifo-depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h for applicable values diff --git a/Documentation/devicetree/bindings/nfc/nq-nci.txt b/Documentation/devicetree/bindings/nfc/nq-nci.txt new file mode 100644 index 0000000000000000000000000000000000000000..b85e0701bbae553edd0b2f41327e2a5b59c9e59e --- /dev/null +++ b/Documentation/devicetree/bindings/nfc/nq-nci.txt @@ -0,0 +1,49 @@ +Qualcomm Technologies, Inc NQxxxx NFC NCI device + +Near Field Communication (NFC) device is based on NFC Controller Interface (NCI) + +Required properties: + +- compatible: "qcom,nq-nci" +- reg: NCI i2c slave address. +- qcom,nq-ven: specific gpio for hardware reset. +- qcom,nq-irq: specific gpio for read interrupt. +- qcom,nq-firm: gpio for firmware download +- qcom,nq-clkreq: gpio for clock +- interrupt-parent: Should be phandle for the interrupt controller + that services interrupts for this device. +- interrupts: Nfc read interrupt,gpio-clk-req interrupt + + +Recommended properties: + +- interrupt-names: names of interrupts, should include "nfc_irq", used for reference + + +Optional properties: + +- pinctrl-names, pinctrl-0, pincntrl-1: references to our pincntrl settings +- clocks, clock-names: must contain the NQxxxx's core clock. +- qcom,nq-esepwr: gpio to control power of secure element + +Example: + + nq-nci@2b { + compatible = "qcom,nq-nci"; + reg = <0x2b>; + qcom,nq-irq = <&tlmm 29 0x00>; + qcom,nq-ven = <&tlmm 30 0x00>; + qcom,nq-firm = <&tlmm 93 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + qcom,clk-src = "BBCLK2"; + interrupt-parent = <&tlmm>; + interrupts = <29 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + qcom,clk-gpio = <&pm8916_gpios 2 0>; + clocks = <&clock_rpm clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; diff --git a/Documentation/devicetree/bindings/nvmem/qcom-spmi-sdam.txt b/Documentation/devicetree/bindings/nvmem/qcom-spmi-sdam.txt new file mode 100644 index 0000000000000000000000000000000000000000..b849a22e2c20b1024bb41a5385f45dd777028a1c --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/qcom-spmi-sdam.txt @@ -0,0 +1,49 @@ +Qualcomm Technologies, Inc. Shared Direct Access Memory (SDAM) + +The SDAM provides scratch register space for the PMIC clients. +This memory can be used by software to store information or communicate +to/from the PBUS. + +Below are the DT bindings for this module + +Supported properties: + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,spmi-sdam" + +- reg + Usage: required + Value type: + Definition: The base address and size of the sdam peripheral. + +- Data cells + Usage: required + Value type: Subnodes with bindings described in bindings/nvmem/nvmem.txt. + Definition: Cells defining the shared memory usage and configuration. + +Example: + + sdam_1: sdam@b000 { + compatible = "qcom,spmi-sdam"; + reg = <0xb000 0x100>; + + .... + /* Data cells */ + restart_reason: restart@50 { + reg = <0x50 0x1>; + bits = <7 2>; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +Example: + + { + ... + nvmem-cells = <&restart_reason>; + nvmem-cell-names = "pmic_restart_reason"; + }; diff --git a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..faf56c2cdb3d57f585f3b2d32ae2b5e9aa580a16 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt @@ -0,0 +1,141 @@ +MSM PCI express endpoint + +Required properties: + - compatible: should be "qcom,pcie-ep". + - reg: should contain PCIe register maps. + - reg-names: indicates various resources passed to driver by name. + Should be "msi", "dm_core", "elbi", "parf", "phy", "mmio". + These correspond to different modules within the PCIe domain. + - #address-cells: Should provide a value of 0. + - interrupt-parent: Should be the PCIe device node itself here. + - interrupts: Should be in the format <0 1 2> and it is an index to the + interrupt-map that contains PCIe related interrupts. + - #interrupt-cells: Should provide a value of 1. + - #interrupt-map-mask: should provide a value of 0xffffffff. + - interrupt-map: Must create mapping for the number of interrupts + that are defined in above interrupts property. + For PCIe device node, it should define 6 mappings for + the corresponding PCIe interrupts supporting the + specification. + - interrupt-names: indicates interrupts passed to driver by name. + Should be "int_pm_turnoff", "int_dstate_change", + "int_l1sub_timeout", "int_link_up", + "int_link_down", "int_bridge_flush_n". + - perst-gpio: PERST GPIO specified by PCIe spec. + - wake-gpio: WAKE GPIO specified by PCIe spec. + - clkreq-gpio: CLKREQ GPIO specified by PCIe spec. + - -supply: phandle to the regulator device tree node. + Refer to the schematics for the corresponding voltage regulators. + vreg-1.8-supply: phandle to the analog supply for the PCIe controller. + vreg-0.9-supply: phandle to the analog supply for the PCIe controller. + +Optional Properties: + - qcom,-voltage-level: specifies voltage levels for supply. + Should be specified in pairs (max, min, optimal), units uV. + - clock-names: list of names of clock inputs. + Should be "pcie_0_pipe_clk", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo"; + - max-clock-frequency-hz: list of the maximum operating frequencies stored + in the same order of clock names; + - resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. + - reset-names: reset signal names sorted in the same order as the property + of resets. + - qcom,pcie-phy-ver: version of PCIe PHY. + - qcom,phy-init: The initialization sequence to bring up the PCIe PHY. + Should be specified in groups (offset, value, delay, direction). + - qcom,phy-status-reg: Register offset for PHY status. + - qcom,dbi-base-reg: Register offset for DBI base address. + - qcom,slv-space-reg: Register offset for slave address space size. + - qcom,pcie-link-speed: generation of PCIe link speed. The value could be + 1, 2 or 3. + - qcom,pcie-active-config: boolean type; active configuration of PCIe + addressing. + - qcom,pcie-aggregated-irq: boolean type; interrupts are aggregated. + - qcom,pcie-mhi-a7-irq: boolean type; MHI a7 has separate irq. + - qcom,pcie-perst-enum: Link enumeration will be triggered by PERST + deassertion. + - mdm2apstatus-gpio: GPIO used by PCIe endpoint side to notify the host side. + - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for + below optional properties: + - qcom,msm-bus,name + - qcom,msm-bus,num-cases + - qcom,msm-bus,num-paths + - qcom,msm-bus,vectors-KBps + +Example: + + pcie_ep: qcom,pcie@bfffd000 { + compatible = "qcom,pcie-ep"; + + reg = <0xbfffd000 0x1000>, + <0xbfffe000 0x1000>, + <0xbffff000 0x1000>, + <0xfc520000 0x2000>, + <0xfc526000 0x1000>, + <0xfc527000 0x1000>; + reg-names = "msi", "dm_core", "elbi", "parf", "phy", "mmio"; + + #address-cells = <0>; + interrupt-parent = <&pcie_ep>; + interrupts = <0 1 2 3 4 5>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 44 0 + 1 &intc 0 46 0 + 2 &intc 0 47 0 + 3 &intc 0 50 0 + 4 &intc 0 51 0 + 5 &intc 0 52 0>; + interrupt-names = "int_pm_turnoff", "int_dstate_change", + "int_l1sub_timeout", "int_link_up", + "int_link_down", "int_bridge_flush_n"; + + perst-gpio = <&msmgpio 65 0>; + wake-gpio = <&msmgpio 61 0>; + clkreq-gpio = <&msmgpio 64 0>; + mdm2apstatus-gpio = <&tlmm_pinmux 16 0>; + + gdsc-vdd-supply = <&gdsc_pcie_0>; + vreg-1.8-supply = <&pmd9635_l8>; + vreg-0.9-supply = <&pmd9635_l4>; + + qcom,vreg-1.8-voltage-level = <1800000 1800000 1000>; + qcom,vreg-0.9-voltage-level = <950000 950000 24000>; + + clock-names = "pcie_0_pipe_clk", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo"; + max-clock-frequency-hz = <62500000>, <1000000>, + <0>, <0>, <0>, <0>; + + resets = <&clock_gcc GCC_PCIE_BCR>, + <&clock_gcc GCC_PCIE_PHY_BCR>; + + reset-names = "pcie_0_core_reset", "pcie_0_phy_reset"; + + qcom,msm-bus,name = "pcie-ep"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + qcom,pcie-link-speed = <1>; + qcom,pcie-active-config; + qcom,pcie-aggregated-irq; + qcom,pcie-mhi-a7-irq; + qcom,pcie-perst-enum; + qcom,phy-status-reg = <0x728>; + qcom,dbi-base-reg = <0x168>; + qcom,slv-space-reg = <0x16c>; + + qcom,phy-init = <0x604 0x03 0x0 0x1 + 0x048 0x08 0x0 0x1 + 0x64c 0x4d 0x0 0x1 + 0x600 0x00 0x0 0x1 + 0x608 0x03 0x0 0x1>; + }; diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index fc019bda50a7796918bbc93617d63f7e3b473bfa..dfe5852df35226845325d61c91363ea344c8a48b 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -37,6 +37,7 @@ Required properties: MSIs, virtual IRQ's (INT#), link state notifications. - perst-gpio: PERST GPIO specified by PCIe spec. - wake-gpio: WAKE GPIO specified by PCIe spec. + - phy-status-offset: Offset from PCIe PHY base to check if PCIe PHY is up. - -supply: phandle to the regulator device tree node. Refer to the schematics for the corresponding voltage regulators. vreg-1.8-supply: phandle to the analog supply for the PCIe controller. @@ -70,13 +71,12 @@ Optional Properties: - qcom,common-clk-en: Enables the common clock configuration for the endpoint. - qcom,clk-power-manage-en: Enables the clock power management for the endpoint. + - qcom,max-link-speed: Max Gen speed Root complex supports. - qcom,n-fts: The number of fast training sequences sent when the link state is changed from L0s to L0. - qcom,pcie-phy-ver: version of PCIe PHY. - qcom,phy-sequence: The initialization sequence to bring up the PCIe PHY. Should be specified in groups (offset, value, delay). - - qcom,port-phy-sequence: The initialization sequence to bring up the - PCIe port PHY. Should be specified in groups (offset, value, delay). - qcom,use-19p2mhz-aux-clk: The frequency of PCIe AUX clock is 19.2MHz. - qcom,boot-option: Bits that alter PCIe bus driver boot sequence. @@ -91,14 +91,17 @@ Optional Properties: - iommus: the phandle and stream IDs for the SMMU used by this root complex. This should be used in separate nodes from the main root complex nodes, and is the only property needed in that case. - - qcom,common-phy: There is a common phy for all the Root Complexes. - qcom,smmu-exist: PCIe uses a SMMU. - qcom,smmu-sid-base: The base SMMU SID that PCIe bus driver will use to calculate and assign for each endpoint. - qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become stable after power on, before de-assert the PERST to the endpoint. + - qcom,switch-latency: The time (unit: ms) to wait for the PCIe endpoint's link + training with switch downstream port after the link between switch upstream + port and RC is up. - qcom,wr-halt-size: With base 2, this exponent determines the size of the data that PCIe core will halt on for each write transaction. + - qcom,slv-addr-space-size: The memory space size of PCIe Root Complex. - qcom,cpl-timeout: Completion timeout value. This value specifies the time range which the root complex will send out a completion packet if there is no response from the endpoint. @@ -214,13 +217,6 @@ Example: 0x15c 0x06 0x00 0x090 0x01 0x00 0x808 0x03 0x00>; - qcom,port-phy-sequence = <0x804 0x01 0x00 - 0x034 0x14 0x00 - 0x138 0x30 0x00 - 0x048 0x0f 0x00 - 0x15c 0x06 0x00 - 0x090 0x01 0x00 - 0x808 0x03 0x00>; perst-gpio = <&msmgpio 70 0>; wake-gpio = <&msmgpio 69 0>; clkreq-gpio = <&msmgpio 68 0>; @@ -265,6 +261,7 @@ Example: qcom,l1-supported; qcom,l1ss-supported; qcom,aux-clk-sync; + qcom,max-link-speed = <0x2>; qcom,n-fts = <0x50>; qcom,pcie-phy-ver = <1>; qcom,boot-option = <0x1>; @@ -272,11 +269,13 @@ Example: qcom,msi-gicm-base = <0x160>; qcom,ext-ref-clk; qcom,tlp-rd-size = <0x5>; - qcom,common-phy; qcom,smmu-exist; qcom,smmu-sid-base = <0x1480>; qcom,ep-latency = <100>; + qcom,switch-latency = <100>; qcom,wr-halt-size = <0xa>; /* 1KB */ + qcom,slv-addr-space-size = <0x1000000>; /* 16MB */ + qcom,phy-status-offset = <0x800>; qcom,cpl-timeout = <0x2>; iommus = <&anoc0_smmu>; diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt index ea828da2a1b68301cf9c9e5199b366d8c8bf90a0..793a9652ec33dffdb34a79e4c20e3a79182adeb5 100644 --- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt +++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt @@ -16,6 +16,10 @@ Required properties: If "halt_base" is in same 4K pages this register then this will be defined else "halt_q6", "halt_modem", "halt_nc" is required. + "pdc_sync" is the power domain register introduced in + sdm845 for power domain of subsystems. + If alternative reset is required, "alt_reset" maps to + mss_alt_ares. - interrupts: The modem watchdog interrupt - vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain. - vdd_cx-voltage: Voltage corner/level(max) for cx rail. @@ -28,6 +32,7 @@ Optional properties: This may be a shared regulator that is already voted on in the PIL proxy voting code (and also managed by the modem on its own), hence we mark it as as optional. +- vdd_mss-uV: Voltage to set for vdd_mss. - vdd_pll-supply: Reference to the regulator that supplies the PLL's rail. - qcom,vdd_pll: Voltage to be set for the PLL's rail. - reg-names: "cxrail_bhs_reg" - control register for modem power @@ -63,6 +68,9 @@ Optional properties: service. - qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem. - qcom,override-acc: Boolean- Present if we need to override the default ACC settings +- qcom,mss_pdc_offset: Integer- Mandatory if PDC register is specified. It is + used to specify which bit in the PDC register + corresponds to the modem. - qcom,ahb-clk-vote: Boolean- Present if we need to remove the vote for the mss_cfg_ahb clock after the modem boots up - qcom,pnoc-clk-vote: Boolean- Present if the modem needs the PNOC bus to be @@ -86,6 +94,8 @@ Optional properties: wordline clamp, and compiler memory clamp during MSS restart. - qcom,qdsp6v56-1-10: Boolean- Present if the qdsp version is v56 1.10 - qcom,override-acc-1: Override the default ACC settings with this value if present. +- qcom,minidump-id: Unique id for each subsystem +- qcom,reset-clk: Enable clock after MSS restart One child node to represent the MBA image may be specified, when the MBA image needs to be loaded in a specifically carved out memory region. diff --git a/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt b/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt index d7edafc9a46bbc482a38c5a1d42a42fc05b1123d..f8329a95b3e89863c377bd2ea855b6f294fd6a5f 100644 --- a/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt +++ b/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt @@ -67,6 +67,8 @@ Optional properties: - qcom,complete-ramdump: Boolean. If set, complete ramdump i.e. region between start address of first segment to end address of last segment will be collected without leaving any hole in between. +- qcom,ignore-ssr-failure: Boolean. If set, SSR failures are not considered fatal. +- qcom,mas-crypto: Reference to the bus master of crypto core. Example: qcom,venus@fdce0000 { diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index b73c96d24f59247da9d0ecbe51225e6f54271619..e15f71c8df53d06ae33c444d37d6efcb7ff10493 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -184,14 +184,20 @@ drive-push-pull - drive actively high and low drive-open-drain - drive with open drain drive-open-source - drive with open source drive-strength - sink or source at most X mA -input-enable - enable input on pin (no effect on output) -input-disable - disable input on pin (no effect on output) +input-enable - enable input on pin (no effect on output, such as + enabling an input buffer) +input-disable - disable input on pin (no effect on output, such as + disabling an input buffer) input-schmitt-enable - enable schmitt-trigger mode input-schmitt-disable - disable schmitt-trigger mode input-debounce - debounce mode with debound time X power-source - select between different power supplies low-power-enable - enable low power mode low-power-disable - disable low power mode +output-disable - disable output on a pin (such as disable an output + buffer) +output-enable - enable output on a pin without actively driving it + (such as enabling an output buffer) output-low - set the pin to output mode with low level output-high - set the pin to output mode with high level slew-rate - set the slew rate diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b483e5d05b1fa450924956bd88dbea27223f1f4 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.txt @@ -0,0 +1,210 @@ +Qualcomm Technologies, Inc. MSM8953 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8953 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8953-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + Valid pins are: + gpio0-gpio141, + sdc1_clk, + sdc1_cmd, + sdc1_data, + sdc1_rclk, + sdc2_clk, + sdc2_cmd, + sdc2_data, + qdsd_cmd, + qdsd_data0, + qdsd_data1, + qdsd_data2, + qdsd_data3 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + gpio, blsp_spi1, smb_int, adsp_ext, prng_rosc, blsp_i2c1, + qdss_cti_trig_out_b0, qdss_cti_trig_out_a1, blsp_spi2, blsp_uart2, + ldo_update, dac_calib0, ldo_en, blsp_i2c2, gcc_gp1_clk_b, + atest_gpsadc_dtest0_native, blsp_spi3, qdss_tracedata_b, + pwr_modem_enabled_b, blsp_i2c3, gcc_gp2_clk_b, gcc_gp3_clk_b, hall_int, + blsp_spi4, blsp_uart4, pwr_nav_enabled_b, dac_calib1, cap_int, + pwr_crypto_enabled_b, dac_calib2, blsp_i2c4, nfc_disable, blsp_spi5, + blsp_uart5, qdss_traceclk_a, atest_bbrx1, nfc_irq, m_voc, + qdss_cti_trig_in_a0, atest_bbrx0, blsp_i2c5, qdss_tracectl_a, + atest_gpsadc_dtest1_native, qdss_tracedata_a, blsp_spi6, blsp_uart6, + qdss_tracectl_b, dac_calib15, qdss_cti_trig_in_b0, dac_calib16, blsp_i2c6, + qdss_traceclk_b, atest_wlan0, atest_wlan1, mdp_vsync, pri_mi2s_mclk_a, + sec_mi2s_mclk_a, qdss_cti_trig_out_b1, cam_mclk, dac_calib3, cci_i2c, + pwr_modem_enabled_a, dac_calib4, dac_calib19, flash_strobe, cci_timer0, + cci_timer1, cam_irq, cci_timer2, blsp1_spi, pwr_nav_enabled_a, ois_sync, + cci_timer3, cci_timer4, blsp3_spi, qdss_cti_trig_out_a0, dac_calib7, + accel_int, gcc_gp1_clk_a, dac_calib8, alsp_int, gcc_gp2_clk_a, dac_calib9, + mag_int, gcc_gp3_clk_a, pwr_crypto_enabled_a, cci_async, cam1_standby, + dac_calib5, cam1_rst, dac_calib6, dac_calib10, gyro_int, dac_calib11, + pressure_int, dac_calib12, blsp6_spi, dac_calib13, fp_int, + qdss_cti_trig_in_b1, dac_calib14, uim_batt, cam0_ldo, sd_write, uim1_data, + uim1_clk, uim1_reset, uim1_present, uim2_data, uim2_clk, uim2_reset, + uim2_present, ts_xvdd, mipi_dsi0, nfc_dwl, us_euro, atest_char3, dbg_out, + bimc_dte0, ts_resout, ts_sample, sec_mi2s_mclk_b, pri_mi2s, codec_reset, + cdc_pdm0, atest_char1, ebi_cdc, dac_calib17, us_emitter, atest_char0, + pri_mi2s_mclk_b, lpass_slimbus, lpass_slimbus0, lpass_slimbus1, codec_int1, + codec_int2, wcss_bt, atest_char2, ebi_ch0, wcss_wlan2, wcss_wlan1, + wcss_wlan0, wcss_wlan, wcss_fm, ext_lpass, mss_lte, key_volp, pbs0, + cri_trng0, key_snapshot, pbs1, cri_trng1, key_focus, pbs2, cri_trng, + gcc_tlmm, key_home, pwr_down, dmic0_clk, blsp7_spi, hdmi_int, dmic0_data, + qdss_cti_trig_in_a1, pri_mi2s_ws, wsa_io, wsa_en, blsp_spi8, wsa_irq, + blsp_i2c8, gcc_plltest, nav_pps_in_a, pa_indicator, nav_pps_in_b, nav_pps, + modem_tsync, nav_tsync, ssbi_wtr1, gsm1_tx, dac_calib18, gsm0_tx, + atest_char, atest_tsens, bimc_dte1, dac_calib20, cam2_rst, ddr_bist, + dac_calib21, cam2_standby, dac_calib22, cam3_rst, dac_calib23, + cam3_standby, dac_calib24, sdcard_det, dac_calib25, cam1_ldo, sec_mi2s, + blsp_spi7, blsp_i2c7, ss_switch, tsens_max + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@1000000 { + compatible = "qcom,msm8953-pinctrl"; + reg = <0x1000000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + pmx-uartconsole { + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + uart_console_sleep: uart_console_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm830-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-pinctrl similarity index 95% rename from Documentation/devicetree/bindings/pinctrl/qcom,sdm830-pinctrl rename to Documentation/devicetree/bindings/pinctrl/qcom,sdm670-pinctrl index 0fe8a1bd4c3ebd4bf84422b05a2225551ad7ed0a..0eb1043ffc0b5b807df03489babf922aa72f6478 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm830-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-pinctrl @@ -1,12 +1,12 @@ -Qualcomm Technologies, Inc. SDM830 TLMM block +Qualcomm Technologies, Inc. SDM670 TLMM block This binding describes the Top Level Mode Multiplexer block found in the -SDM830 platform. +SDM670 platform. - compatible: Usage: required Value type: - Definition: must be "qcom,sdm830-pinctrl" + Definition: must be "qcom,sdm670-pinctrl" - reg: Usage: required @@ -135,9 +135,9 @@ to specify in a pin configuration subnode: Example: - tlmm: pinctrl@03800000 { - compatible = "qcom,sdm830-pinctrl"; - reg = <0x03800000 0xc00000>; + tlmm: pinctrl@03400000 { + compatible = "qcom,sdm670-pinctrl"; + reg = <0x03400000 0xc00000>; interrupts = <0 208 0>; gpio-controller; #gpio-cells = <2>; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl index 9c263740fffb86c7ad2dafe4f90ebb3a0fb40658..7e75d2cae4a6597030d50ca3a9ed1becd90c5aad 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl @@ -6,7 +6,7 @@ SDM845 platform. - compatible: Usage: required Value type: - Definition: must be "qcom,sdm845-pinctrl" + Definition: must be "qcom,sdm845-pinctrl" or "qcom,sdm845-pinctrl-v2" - reg: Usage: required diff --git a/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bb85a4860abcda981291546546e5f104d8c4ba7 --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt @@ -0,0 +1,25 @@ +GPIO USB VBUS Detection + +Discrete USB VBUS detection circuitry can be connected to the AP or PMICs. +Such circuits can be used to detect the when a USB cable is connected to +an upstream port such as a standard host or a wall charger by detecting +the presence of VBUS voltage. The GPIO can be configured to trigger an +interrupt, and allow the software driver to in turn notify the USB +subsytem using the power_supply framework. + +Required Properties: + - compatible: must be "qcom,gpio-usbdetect" + - qcom,vbus-det-gpio: GPIO from which VBUS detection can be read from. + - interrupts: an interrupt triggered by the output of the detection circuit + - interrupt-names: must be "vbus_det_irq" + +Optional Properties: + - vin-supply: phandle to a regulator that powers this circuit, if needed + +Example: + + usb_detect { + compatible = "qcom,gpio-usbdetect"; + qcom,vbus-det-gpio = <&pm8084 2 0>; + vin-supply = <&vbus_det_reg>; + }; diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index 3a03addc7a35e655d14657029d916d429bda7f96..d272b7f3426a1063e354ec50fd6d212cd7deae3d 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -19,13 +19,15 @@ IPA node: "bam-irq" - string to identify the IPA BAM interrupt. "a2-bam-irq" - string to identify the A2 BAM interrupt. - qcom,ipa-hw-ver: Specifies the IPA hardware version. +- qcom,ipa-ram-mmap: An array of unsigned integers representing addresses and + sizes which are used by the driver to access IPA RAM. Optional: -- qcom,wan-rx-ring-size: size of WAN rx ring, default is 32 +- qcom,wan-rx-ring-size: size of WAN rx ring, default is 192 +- qcom,lan-rx-ring-size: size of LAN rx ring, default is 192 - qcom,arm-smmu: SMMU is present and ARM SMMU driver is used - qcom,msm-smmu: SMMU is present and QSMMU driver is used -- qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass - qcom,smmu-fast-map: Boolean context flag to set SMMU to fastpath mode - ipa_smmu_ap: AP general purpose SMMU device compatible "qcom,ipa-smmu-ap-cb" @@ -59,12 +61,12 @@ memory allocation over a PCIe bridge - qcom,bandwidth-vote-for-ipa: Boolean context flag to indicate whether ipa clock voting is done by bandwidth voting via msm-bus-scale driver or not +- qcom,use-64-bit-dma-mask: Boolean context flag to indicate whether + using 64bit dma mask or not - qcom,use-dma-zone: Boolean context flag to indicate whether memory allocations controlled by IPA driver that do not specify a struct device * should use GFP_DMA to workaround IPA HW limitations -- qcom,use-gsi: Boolean context flag to indicate if the - transport protocol is GSI - qcom,use-rg10-limitation-mitigation: Boolean context flag to activate the mitigation to register group 10 AP access limitation @@ -77,8 +79,12 @@ memory allocation over a PCIe bridge - qcom,rx-polling-sleep-ms: Receive Polling Timeout in millisecond, default is 1 millisecond. - qcom,ipa-polling-iteration: IPA Polling Iteration Count,default is 40. +- qcom,mhi-event-ring-id-limits: Two elements property. Start and End limits + for MHI event rings ids. - qcom,ipa-tz-unlock-reg: Register start addresses and ranges which need to be unlocked by TZ. +- qcom,ipa-uc-monitor-holb: Boolean context flag to indicate whether + monitoring of holb via IPA uc is required. IPA pipe sub nodes (A2 static pipes configurations): @@ -119,10 +125,16 @@ IPA SMMU sub nodes -compatible: "qcom,ipa-smmu-uc-cb" - represents IPA uC context bank (for uC offload scenarios). + +- qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass. + - iommus : the phandle and stream IDs for the SMMU used by this root - qcom,iova-mapping: specifies the start address and size of iova space. +- qcom,additional-mapping: specifies any addtional mapping needed for this + context bank. The format is + IPA SMP2P sub nodes -compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from @@ -198,18 +210,24 @@ qcom,ipa@fd4c0000 { ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; - iommus = <&anoc2_smmu 0x30>; - qcom,iova-mapping = <0x10000000 0x40000000>; + iommus = <&apps_smmu 0x720>; + qcom,iova-mapping = <0x20000000 0x40000000>; + qcom,additional-mapping = + /* modem tables in IMEM */ + <0x146bd000 0x146bd000 0x2000>; }; ipa_smmu_wlan: ipa_smmu_wlan { compatible = "qcom,ipa-smmu-wlan-cb"; - iommus = <&anoc2_smmu 0x31>; + iommus = <&apps_smmu 0x721>; + qcom,additional-mapping = + /* ipa-uc ram */ + <0x1e60000 0x1e60000 0x80000>; }; ipa_smmu_uc: ipa_smmu_uc { compatible = "qcom,ipa-smmu-uc-cb"; - iommus = <&anoc2_smmu 0x32>; + iommus = <&apps_smmu 0x722>; qcom,iova-mapping = <0x40000000 0x20000000>; }; }; diff --git a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt new file mode 100644 index 0000000000000000000000000000000000000000..b4ce7cb101d8fe257b13fdf854b07f633038192d --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt @@ -0,0 +1,83 @@ +* TSPP ( QTI Transport Stream Packet Processor ) + +Hardware driver for QTI TSIF 12seg wrapper core, which consists of a TSPP, a +BAM (Bus access manager, used for DMA) and two TSIF inputs. + +The TSPP driver is responsible for: + - TSPP/TSIF hardware configuration (using SPS driver to configure BAM hardware) + - TSIF GPIO/Clocks configuration + - Memory resource management + - Handling TSIF/TSPP interrupts and BAM events + - TSPP Power management + +Required properties: +- compatible : Should be "qcom,msm_tspp" +- reg : Specifies the base physical addresses and sizes of TSIF, TSPP & BAM registers. +- reg-names : Specifies the register names of TSIF, TSPP & BAM base registers. +- interrupts : Specifies the interrupts associated with TSIF 12 seg core. +- interrupt-names: Specifies interrupt names for TSIF, TSPP & BAM interrupts. +- clock-names: Specifies the clock names used for interface & reference clocks. +- clocks: GCC_TSIF_AHB_CLK clock for interface clock & GCC_TSIF_REF_CLK clock for reference clock. +- qcom, msm_bus,name: Should be "tsif" +- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling +- qcom, msm_bus,num_paths: The paths for source and destination ports +- qcom, msm_bus,vectors: Vectors for bus topology. +- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active. +- qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation. +- iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + +Example: + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x20 0x0f>; + }; diff --git a/Documentation/devicetree/bindings/platform/msm/qcom-geni-se.txt b/Documentation/devicetree/bindings/platform/msm/qcom-geni-se.txt new file mode 100644 index 0000000000000000000000000000000000000000..7da95f8b795f3f06418ba23c93ca24f0fdb06a91 --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/qcom-geni-se.txt @@ -0,0 +1,37 @@ +Qualcomm Technologies, Inc. GENI Serial Engine Driver + +GENI Serial Engine Driver is used to configure and read the configuration +from the Serial Engines on Qualcomm Technologies, Inc. Universal Peripheral +(QUPv3) core. It is also used to enable the stage1 IOMMU translation and +manage resources associated with the QUPv3 core. + +Required properties: +- compatible: Must be "qcom,qupv3-geni-se". +- reg: Must contain QUPv3 register address and length. +- qcom,bus-mas-id: Master Endpoint ID for bus driver. +- qcom,bus-slv-id: Slave Endpoint ID for bus driver. + +Optional properties: +- qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation. + +Optional subnodes: +qcom,iommu_qupv3_geni_se_cb: Child node representing the QUPV3 context + bank. + +Subnode Required properties: +- compatible : Must be "qcom,qupv3-geni-se-cb"; +- iommus: A list of phandle and IOMMU specifier pairs that + describe the IOMMU master interfaces of the device. + +Example: + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x6000>; + qcom,bus-mas-id = <100>; + qcom,bus-slv-id = <300>; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x1 0x0>; + }; + } diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt index babc4523a29a59fb877b28754132afbadde2a8a7..dd14890123e6e26b82f0f0b6596d4ba7940ebf34 100644 --- a/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt +++ b/Documentation/devicetree/bindings/platform/msm/qpnp-revid.txt @@ -9,6 +9,8 @@ Required properties: Optional property: - qcom,fab-id-valid: Use this property when support to read Fab identification from REV ID peripheral is available. +- qcom,tp-rev-valid: Use this property when support to read TP + revision identification from REV ID peripheral. Example: qcom,revid@100 { diff --git a/Documentation/devicetree/bindings/power/supply/nx30p6093.txt b/Documentation/devicetree/bindings/power/supply/nx30p6093.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d579bb22c23bd3d6efdcf408726bddc03f6d32d --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/nx30p6093.txt @@ -0,0 +1,72 @@ +Binding for NXP NX30P6093 moisture detection module + +NX30P6093 is an I2C controlled module and features an input impedance detection +function, along with OVP protection upto 29V. The impedance detection can detect +moisture or dust on USB lines and report the same to system to take necessary +steps to avoid circuit damage to the Type-C port power supply pin. + +======================= +Supported Properties +======================= + +- compatible + Usage: required + Value type: + Definition: should be "nxp,nx30p6093". + +- reg + Usage: required + Value type: + Definition: The device 8-bit I2C address. + +- interrupts + Usage: required + Value type: + Definition: Moisture detect interrupt specifier. + +- nxp,always-on-detect + Usage: optional + Value type: + Definition: If specified, the NX30P6093 is configured to perform + mositure detection on every detection duty cycle configured + in "nxp,always-on-tduty-val" property. + +- nxp,always-on-tduty-ms + Usage: required if "nxp,always-on-detect" specified + Value type: + Definition: The detection duty cycle (Tduty) in milliseconds. + Supported values are 10, 20, 50, 100, 200, 500, 1000, + 2000, 3000, 6000, 12000, 30000, 60000, 120000 and 300000. + If this property is not specified a default value of + 300000 milliseconds is used. + +- nxp,long-wakeup-sec + Usage: required if "nxp,always-on-detect" not specified. + Value type: + Definition: A longer time interval in seconds maintained between + moisture detection events after a previous moisture + detection event resulted in a good impedance detected + on USB lines. If this property is not specified a default + value of 28800 seconds (8 hrs) is used. + +- nxp,short-wakeup-ms + Usage: required if "nxp,always-on-detect" not specified. + Value type: + Definition: A shorter time interval in milliseconds maintained + between moisture detection events after a previous + moisture detection event resulted in a bad impedance + detected on USB lines. If this property is not specified + a default value of 180000 milliseconds (3 mins) is used. + +======= +Example +======= + +nx30p6093@0 { + compatible = "nxp,nx30p6093"; + reg = <0x36>; + interrupt-parent = <&tlmm>; + interrupts = <5 IRQ_TYPE_NONE>; + nxp,long-wakeup-sec = <28800>; /* 8 hours */ + nxp,short-wakeup-ms = <180000>; /* 3 mins */ +}; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt index 12d32ec74369a6e2c138335590b3e84fe040e361..f50fd88894c684ac8c373403f7e5d5c4ae2d5be6 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt @@ -145,22 +145,30 @@ First Level Node - FG Gen3 device - qcom,fg-esr-timer-charging Usage: optional - Value type: + Value type: Definition: Number of cycles between ESR pulses while the battery is - charging. + charging. Array of 2 elements if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-timer-awake Usage: optional - Value type: + Value type: Definition: Number of cycles between ESR pulses while the system is - awake and the battery is discharging. + awake and the battery is discharging. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-timer-asleep Usage: optional - Value type: + Value type: Definition: Number of cycles between ESR pulses while the system is asleep and the battery is discharging. This option requires - qcom,fg-esr-timer-awake to be defined. + qcom,fg-esr-timer-awake to be defined. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer - qcom,fg-esr-pulse-thresh-ma Usage: optional @@ -200,14 +208,14 @@ First Level Node - FG Gen3 device Value type: Definition: Lower limit of battery temperature to start the capacity learning. If this is not specified, then the default value - used will be 150. Unit is in decidegC. + used will be 150 (15 C). Unit is in decidegC. - qcom,cl-max-temp Usage: optional Value type: Definition: Upper limit of battery temperature to start the capacity learning. If this is not specified, then the default value - used will be 450 (45C). Unit is in decidegC. + used will be 500 (50 C). Unit is in decidegC. - qcom,cl-max-increment Usage: optional @@ -263,6 +271,14 @@ First Level Node - FG Gen3 device Definition: A boolean property that when defined holds SOC at 100% when the battery is full. +- qcom,linearize-soc + Usage: optional + Value type: + Definition: A boolean property that when defined linearizes SOC when + the SOC drops after charge termination monotonically to + improve the user experience. This is applicable only if + "qcom,hold-soc-while-full" is specified. + - qcom,ki-coeff-soc-dischg Usage: optional Value type: @@ -293,6 +309,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,ki-coeff-full-dischg + Usage: optional + Value type: + Definition: Ki coefficient full SOC value that will be applied during + discharging. If not specified, a value of 0 will be set. + Allowed range is from 245 to 62256. + - qcom,fg-rconn-mohms Usage: optional Value type: @@ -377,6 +400,11 @@ First Level Node - FG Gen3 device property "qcom,slope-limit-temp-threshold" to make dynamic slope limit adjustment functional. +- qcom,fg-bmd-en-delay-ms + Usage: optional + Value type: + Definition: The delay in ms for FG to enable BMD after reading RID. + ========================================================== Second Level Nodes - Peripherals managed by FG Gen3 driver ========================================================== diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6a7a1ba300528d27ca3d386a184043851187172 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg.txt @@ -0,0 +1,275 @@ +QTI's QPNP PMIC Fuel Gauge Device + +QPNP PMIC FG provides interface to clients to read properties related +to the battery. Its main function is to retrieve the State of Charge (SOC), +a 0-100 percentage representing the amount of charge left in the battery. + +There are two required peripherals in the FG driver, both implemented as +subnodes in the example. These peripherals must not be disabled if the FG +device is to enabled: + +- qcom,fg-soc : The main FG device. Supports battery fuel gauge controls and + sensors. +- qcom,fg-batt : The FG battery device supports interrupts and controls with + respect to the state of the connected battery.For example: the + peripheral informs the driver if the battery has been identified + by the fuel gauge based on a given battery resistance range. + +Optionally ADC nodes can be added +- qcom,revid-tp-rev: A subnode with a register address for the TP_REV register + in the REVID peripheral. This is used to apply workarounds that + may depend on the trim program. +- qcom,fg-adc-vbat : A subnode with a register address for the FG_ADC_USR + peripheral which is used mainly for battery current limiting (BCL). + This node maps out the VBAT reading register which allows to have + a +/- 32 mV accurate reading of VBAT. +- qcom,fg-adc-ibat : A subnode with a register address for the FG_ADC_USR + peripheral which is used mainly for battery current limiting (BCL). + This node maps out the IBAT current reading register which allows + to have a +/- 32 mA accurate reading of IBAT. + +Parent node required properties: +- compatible : should be "qcom,qpnp-fg" for the FG driver. +- qcom,pmic-revid : Should specify the phandle of PMIC + revid module. This is used to identify + the PMIC subtype. + +Parent node optional properties: +- qcom,warm-bat-decidegc: Warm battery temperature in decidegC. +- qcom,cool-bat-decidegc: Cool battery temperature in decidegC. +- qcom,hot-bat-decidegc: Hot battery temperature in decidegC. +- qcom,cold-bat-decidegc: Cold battery temperature in decidegC. +- qcom,cold-hot-jeita-hysteresis: A tuple of 2. Index[0] is cold + hysteresis and index[1] is hot + hysterisis(in decidegC). +- qcom,ext-sense-type: Current sense channel used by the FG. + Set this to use external rsense. +- qcom,thermal-coefficients: Byte array of thermal coefficients for + reading battery thermistor. This should + be exactly 6 bytes in length. + Example: [01 02 03 04 05 06] +- qcom,resume-soc: soc to resume charging in percentage. +- qcom,resume-soc-raw: soc to resume charging in the scale of + [0-255]. This overrides qcom,resume-soc + if defined. +- qcom,hold-soc-while-full: A boolean property that when defined + holds SOC at 100% when the battery is + full. +- qcom,bcl-lm-threshold-ma: BCL LPM to MPM mode transition threshold + in milliAmpere. +- qcom,bcl-mh-threshold-ma: BCL MPM to HPM mode transition threshold + in milliAmpere. +- qcom,use-otp-profile: Specify this flag to avoid RAM loading + any battery profile. +- qcom,sw-rbias-control: Boolean property which defines whether + the Rbias needs to be controlled by + software. If this is not set, it will + be controlled by hardware (default). +- qcom,fg-iterm-ma: Battery current at which the fuel gauge + will try to scale 100% towards. When + the charge current goes above this, the + SoC should be at 100%. +- qcom,fg-chg-iterm-ma: Battery current at which the fuel gauge + will issue end of charge if the charger + is configured to use the fuel gauge + ADCs for end of charge detection. This + property is in milliamps and should be + positive (e.g. 100mA to terminate at + -100mA). +- qcom,irq-volt-empty-mv: The voltage threshold that the empty + soc interrupt will be triggered. When + the empty soc interrupt fires, battery + soc will be pulled to 0 and the + userspace will be notified via the + power supply framework. The userspace + will read 0% soc and immediately + shutdown. +- qcom,fg-cutoff-voltage-mv: The voltage where the fuel gauge will + steer the SOC to be zero. For example, + if the cutoff voltage is set to 3400mv, + the fuel gauge will try to count SoC so + that the battery SoC will be 0 when it + is 3400mV. +- qcom,fg-vbat-estimate-diff-mv: If the estimated voltage based on SoC + and battery current/resistance differs + from the actual voltage by more than + this amount, the fuel gauge will + redo the first SoC estimate when the + driver probes. +- qcom,fg-delta-soc: How many percent the monotonic SoC must + change before a new delta_soc interrupt + is asserted. If this value is raised + above 3-4, some period workarounds may + not function well, so it's best to + leave this at 1 or 2%. +- qcom,fg-vbatt-low-threshold: Voltage (in mV) which upon set will be + used for configuring the low battery + voltage threshold. Interrupt will be + asserted and handled based upon + this. If this property is not specified, + low battery voltage threshold will be + configured to 4200 mV. +- qcom,cycle-counter-en: Boolean property which enables the cycle + counter feature. If this property is + present, then the following properties + to specify low and high soc thresholds + should be defined. +- qcom,capacity-learning-on: A boolean property to have the fuel + gauge driver attempt to learn the + battery capacity when charging. Takes + precedence over capacity-estimation-on. +- qcom,capacity-learning-feedback: A boolean property to have the fuel + gauge driver to feedback the learned + capacity into the capacity learning + algorithm. This has to be used only if + the property "qcom,capacity-learning-on" + is specified. +- qcom,cl-max-increment-deciperc: The maximum percent that the capacity + can rise as the result of a single + charge cycle. This property corresponds + to .1% increments. +- qcom,cl-max-decrement-deciperc: The maximum percent that the capacity + can fall as the result of a single + charge cycle. This property corresponds + to .1% decrements. +- qcom,cl-max-temp-decidegc: Above this temperature, capacity + learning will be canceled. +- qcom,cl-mix-temp-decidegc: Below this temperature, capacity + learning will be canceled. +- qcom,cl-max-start-soc: The battery soc has to be below this + value at the start of a charge cycle + for capacity learning to be run. +- qcom,cl-vbat-est-thr-uv: The maximum difference between the + battery voltage shadow and the current + predicted voltage in uV to initiate + capacity learning. +- qcom,capacity-estimation-on: A boolean property to have the fuel + gauge driver attempt to estimate the + battery capacity using battery + resistance. +- qcom,aging-eval-current-ma: Current used to evaluate battery aging. + This value should be around the steady + state current drawn from the battery + when the phone is low on battery. +- qcom,fg-cc-cv-threshold-mv: Voltage threshold in mV for configuring + constant charge (CC) to constant + voltage (CV) setpoint in FG upon + which the battery EOC status will + be determined. This value should be + 10 mV less than the float voltage + configured in the charger. + This property should only be specified + if "qcom,autoadjust-vfloat" property is + specified in the charger driver to + ensure a proper operation. +- qcom,bad-battery-detection-enable: A boolean property to enable the fuel + gauge driver to detect the damaged battery + when the safety-timer expires by using the + coulomb count. +- qcom,fg-therm-delay-us: The time in microseconds to delay battery + thermistor biasing. +- qcom,esr-pulse-tuning-en: A boolean property to enable ESR pulse + tuning feature. If this is enabled, + ESR pulse extraction will be disabled + when state of charge (SOC) is less than + 2%. It will be enabled back when SOC + gets above 2%. In addition, for SOC + between 2% and 5%, ESR pulse timing + settings will be different from default. + Once SOC crosses 5%, ESR pulse timings + will be restored back to default. + +qcom,fg-soc node required properties: +- reg : offset and length of the PMIC peripheral register map. +- interrupts : the interrupt mappings. + The format should be + . +- interrupt-names : names for the mapped fg soc interrupts + The following interrupts are required: + 0: high-soc + 1: low-soc + 2: full-soc + 3: empty-soc + 4: delta-soc + 5: first-est-done + 6: sw-fallbk-ocv + 7: sw-fallbk-new-batt + +qcom,fg-memif node required properties: +- reg : offset and length of the PMIC peripheral register map. +- interrupts : the interrupt mappings. + The format should be + . +- interrupt-names : names for the mapped fg adc interrupts + The following interrupts are required: + 0: mem-avail + +Example: +pmi8994_fg: qcom,fg { + compatible = "qcom,qpnp-fg"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + qcom,pmic-revid = <&pmi8994_revid>; + + qcom,fg-soc@4000 { + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0>, + <0x2 0x40 0x1>, + <0x2 0x40 0x2>, + <0x2 0x40 0x3>, + <0x2 0x40 0x4>, + <0x2 0x40 0x5>, + <0x2 0x40 0x6>, + <0x2 0x40 0x7>; + + interrupt-names = "high-soc", + "low-soc", + "full-soc", + "empty-soc", + "delta-soc", + "first-est-done", + "sw-fallbk-ocv", + "sw-fallbk-new-batt"; + }; + + qcom,fg-batt@4100 { + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0>, + <0x2 0x41 0x1>, + <0x2 0x41 0x2>, + <0x2 0x41 0x3>, + <0x2 0x41 0x4>, + <0x2 0x41 0x5>, + <0x2 0x41 0x6>, + <0x2 0x41 0x7>; + + interrupt-names = "soft-cold", + "soft-hot", + "vbatt-low", + "batt-ided", + "batt-id-req", + "batt-unknown", + "batt-missing", + "batt-match"; + }; + + qcom,fg-adc-vbat@4254 { + reg = <0x4254 0x1>; + }; + + qcom,fg-adc-ibat@4255 { + reg = <0x4255 0x1>; + }; + + qcom,fg-memif@4400 { + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0>, + <0x2 0x44 0x1>; + + interrupt-names = "mem-avail", + "data-rcvry-sug"; + + qcom,cold-hot-jeita-hysteresis = <30 50>; + }; +}; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt index 96b7dd5172318466dada3f3e907fdefe90d3e45c..8f35e56816cee57bdb628f6e9d6c5a0ef8a21fa1 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt @@ -20,6 +20,7 @@ Required properties: Optional Properties: - qcom,external-rsense: To indicate whether the platform uses external or internal rsense for measuring battery current. +- qcom,enable-for-dc: To enable qnovo for dc charging path. Example: diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt index e1f194f3c2769f43af0da8242dbdcc33b57ab940..8795affdaf26cae69ba70620fdb4de38f1150a55 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt @@ -35,11 +35,6 @@ Charger specific properties: addition battery properties will be faked such that the device assumes normal operation. -- qcom,external-vconn - Usage: optional - Value type: - Definition: Boolean flag which indicates VCONN is sourced externally. - - qcom,fcc-max-ua Usage: optional Value type: @@ -90,21 +85,6 @@ Charger specific properties: maximum charge current in mA for each thermal level. -- qcom,step-soc-thresholds - Usage: optional - Value type: Array of - Definition: Array of SOC threshold values, size of 4. This should be a - flat array that denotes the percentage ranging from 0 to 100. - If the array is not present, step charging is disabled. - -- qcom,step-current-deltas - Usage: optional - Value type: Array of - Definition: Array of delta values for charging current, size of 5, with - FCC as base. This should be a flat array that denotes the - offset of charging current in uA, from -3100000 to 3200000. - If the array is not present, step charging is disabled. - - io-channels Usage: optional Value type: List of @@ -157,12 +137,6 @@ Charger specific properties: be based off battery voltage. For both SOC and battery voltage, charger receives the signal from FG to resume charging. -- qcom,micro-usb - Usage: optional - Value type: - Definition: Boolean flag which indicates that the platform only support - micro usb port. - - qcom,suspend-input-on-debug-batt Usage: optional Value type: @@ -181,6 +155,37 @@ Charger specific properties: Definition: Specifies the maximum charger buck/boost switching frequency in KHz. It overrides the max frequency defined for the charger. +- qcom,otg-deglitch-time-ms + Usage: optional + Value type: + Definition: Specifies the deglitch interval for OTG detection. + If the value is not present, 50 msec is used as default. + +- qcom,step-charging-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables step-charging. + +- qcom,wd-bark-time-secs + Usage: optional + Value type: + Definition: WD bark-timeout in seconds. The possible values are + 16, 32, 64, 128. If not defined it defaults to 64. + +- qcom,sw-jeita-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables sw compensation for jeita + +- qcom,battery-data + Usage: optional + Value type: + Definition: Specifies the phandle of the node which contains the battery + profiles supported on the device. This is only specified + when step charging and sw-jeita configurations are desired + to be get from these properties defined in battery profile: + qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges. + ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= @@ -216,9 +221,6 @@ pmi8998_charger: qcom,qpnp-smb2 { dpdm-supply = <&qusb_phy0>; - qcom,step-soc-thresholds = <60 70 80 90>; - qcom,step-current-deltas = <500000 250000 150000 0 (-150000)>; - qcom,chgr@1000 { reg = <0x1000 0x100>; interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smbcharger.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smbcharger.txt new file mode 100644 index 0000000000000000000000000000000000000000..efd64cd90878e1bf3b10d0cf089675079cd7af29 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smbcharger.txt @@ -0,0 +1,394 @@ +QPNP SMB Battery Charger + +QPNP SMB Charger is a single-cell switching mode battery charger. It can charge +the battery and power the system via the USB and AC adapter input. + +The QPNP SMB Charger interfaces via the SPMI bus. + +There are six different peripherals adding the following functionality. +Each of these peripherals are implemented as subnodes in the example at the +end of this file. + +- qcom,chgr: Supports charging control and status + reporting. +- qcom,bat-if: Battery status reporting such as presence, + temperature reporting and voltage collapse + protection. +- qcom,usb-chgpth: USB charge path detection and input current + limiting configuration. +- qcom,dc-chgpth: DC charge path detection and input current + limiting configuration. +- qcom,chg-misc: Miscellaneous features such as watchdog timers + and SYSOK pin control +- qcom,chg-otg: OTG configuration control. + +Parent node required properties: +- compatible: Must be "qcom,qpnp-smbcharger" +- #address-cells: Must be <1> +- #size-cells: Must be <1> +- qcom,pmic-revid: Should specify the phandle of PMIC + revid module. This is used to identify + the PMIC subtype. + + + +Sub node required properties: +- reg: The SPMI address for this peripheral +- interrupts: Specifies the interrupt associated with the peripheral. +- interrupt-names: Specifies the interrupt names for the peripheral. Every + available interrupt needs to have an associated name + with it to indentify its purpose. + + The following lists each subnode and their corresponding + required interrupt names: + + qcom,chgr: + - chg-tcc-thr: Triggers on charge completion. + - chg-taper-thr: Triggers on the taper charge + transtion. + - chg-inhibit: Notifies on battery voltage + being too high to resume + charging. + - chg-p2f-thr: Triggers on transitioning from + precharge to fastcharge. + - chg-rechg-thr: Triggers on battery voltage + falling below the resume + threshold. + + qcom,bat-if: + - batt-hot: Triggers on battery temperature + hitting the hot threshold. + Charging stops. + - batt-warm: Triggers on battery temperature + hitting the warm threshold. + Charging current is reduced. + - batt-cool: Triggers on battery temperature + hitting the cool threshold. + Charging current is reduced + - batt-cold: Triggers on battery temperature + hitting the cold threshold. + Charging stops. + - batt-missing: Battery missing status + interrupt. + - batt-low: Triggers on battery voltage + falling across a low threshold. + + qcom,usb-chgpth: + - usbin-uv: USB input voltage falls below a + valid threshold. + - usbin-src-det: USB automatic source detection + finishes. + + qcom,dc-chgpth: + - dcin-uv: DC input voltage falls below a + valid threshold. + + qcom,chgr-misc: + - wdog-timeout-mins: Charger watchdog timer + interrupt. + - temp-shutdown: Triggers when charger goes + overtemp and causes a shutdown. + - power-ok: Triggers when the charger + switcher turns on or off. + +Regulator Subnodes: +- qcom,smbcharger-boost-otg A subnode for a regulator device that turns on + the charger boost for OTG operation. +- qcom,smbcharger-external-otg A subnode for a regulator device that switches + off charging and the USB input charge path + in order to allow an external regulator to + operate. This can be used in place of the + qcom,smbcharger-boost-otg if an external boost + is available. + +Regulator Sub node required properties: +- regulator-name A name string for the regulator in question + +Optional Properties: +- qcom,battery-psy-name The name of the main battery power supply that + the charger will register. Failing to define + this property will default the name to + "battery". +- qcom,bms-psy-name The psy name to use for reporting battery + capacity. If left unspecified the capacity uses + a preprogrammed default value of 50. +- qcom,float-voltage-mv Float Voltage in mV - the maximum voltage up + to which the battery is charged. Supported + range 3600mV to 4500mV +- qcom,float-voltage-comp Specifies the JEITA float voltage compensation. + Value ranges from 0 to 63. +- qcom,fastchg-current-ma Specifies the fast charge current in mA. Supported + range is from 300mA to 3000mA. +- qcom,fastchg-current-comp Specifies the fast charge current compensation in + mA. Supported values are 250, 700, 900 and 1200mA. +- qcom,charging-timeout-mins Maximum duration in minutes that a single + charge cycle may last. Supported values are: + 0, 192, 384, 768, and 1536. A value of 0 + means that no charge cycle timeout is used and + charging can continue indefinitely. +- qcom,precharging-timeout-mins Maximum duration in minutes that a single + precharge cycle may last. Supported values + are: 0, 24, 48, 96, 192. A value of 0 means + that no precharge cycle timeout is used and + charging can continue indefinitely. Note that + the qcom,charging-timeout-mins property must + be specified in order for this to take effect. +- qcom,dc-psy-type The type of charger connected to the DC path. + Can be "Mains", "Wireless" or "Wipower" +- qcom,dc-psy-ma The current in mA dc path can support. Must be + specified if dc-psy-type is specified. Valid + range 300mA to 2000mA. +- qcom,dcin-vadc The phandle to pmi8994 voltage adc. The ADC is + used to get notifications when the DCIN voltage + crosses a programmed min/max threshold. This is + used to make configurations for optimized power + draw for Wipower. +- qcom,wipower-div2-ilim-map +- qcom,wipower-pt-ilim-map +- qcom,wipower-default-ilim-map + Array of 5 elements to indicate the voltage ranges and their corresponding + current limits. The 5 elements with index [0..4] are: + [0] => voltage_low in uV + [1] => voltage_high in uV + [2] => current limit for pass through in mA + [3] => current limit for div2 mode dcin low voltage in mA + [4] => current limit for div2 mode dcin high voltage in mA + The div2 and pt tables indicate the current limits + to use when Wipower is operating in divide_by_2 mode + and pass through mode respectively. + The default table is used when the voltage ranges + are beyond the ones specified in the mapping table. + Note that if dcin-vadc or any of these mapping + tables are not specified, dynamic dcin input + is disabled. +- qcom,charging-disabled Set this if charging should be disabled in the + build by default. +- qcom,resume-delta-mv Specifies the minimum voltage drop in + millivolts below the float voltage that is + required in order to initiate a new charging + cycle. Supported values are: 50, 100, 200 and + 300mV. +- qcom,chg-inhibit-en Boolean that indicates whether the charge inhibit + feature needs to be enabled. If this is not set, + charge inhibit feature is disabled by default. +- qcom,chg-inhibit-fg Indicates if the recharge threshold source has + to be Fuel gauge ADC. If this is not set, it + will be analog sensor by default. +- qcom,bmd-algo-disabled Indicates if the battery missing detection + algorithm is disabled. If this node is present + SMB uses the THERM pin for battery missing + detection. +- qcom,charge-unknown-battery Boolean that indicates whether an unknown + battery without a matching profile will be + charged. If this is not set, if the fuel gauge + does not recognize the battery based on its + battery ID, the charger will not start + charging. +- qcom,bmd-pin-src A string that indicates the source pin for the + battery missind detection. This can be either: + - "bpd_none" + battery is considered always present + - "bpd_id" + battery id pin is used + - "bpd_thm" + battery therm pin is used + - "bpd_thm_id" + both pins are used (battery is + considered missing if either pin is + floating). +- qcom,iterm-ma Specifies the termination current to indicate + end-of-charge. Possible values in mA: + 50, 100, 150, 200, 250, 300, 500, 600. +- qcom,iterm-disabled Disables the termination current feature. This + is a boolean property. +- otg-parent-supply A phandle to an external boost regulator for + OTG if it exists. +- qcom,thermal-mitigation: Array of input current limit values for + different system thermal mitigation levels. + This should be a flat array that denotates the + maximum charge current in mA for each thermal + level. +- qcom,rparasitics-uohm: The parasitic resistance of the board following + the line from the battery connectors through + vph_power. This is used to calculate maximum + available current of the battery. +- qcom,vled-max-uv: The maximum input voltage of the flash leds. + This is used to calculate maximum available + current of the battery. +- qcom,autoadjust-vfloat A boolean property that when set, makes the + driver automatically readjust vfloat using the + fuel gauge ADC readings to make charging more + accurate. +- qcom,jeita-temp-hard-limit property when present will enable or disable + the jeita temperature hard limit based on the + value 1 or 0. Specify 0 if the jeita temp hard + limit needs to be disabled. If it is not present, + jeita temperature hard limit will be based on what + the bootloader had set earlier. +- qcom,low-volt-dcin: A boolean property which upon set will enable the + AICL deglitch configuration dynamically. This needs + to be set if the DCIN supply is going to be less + than or equal to 5V. +- qcom,force-aicl-rerun: A boolean property which upon set will enable the + AICL rerun by default along with the deglitch time + configured to long interval (20 ms). Also, specifying + this property will not adjust the AICL deglitch time + dynamically for handling the battery over-voltage + oscillations when the charger is headroom limited. +- qcom,aicl-rerun-period-s If force-aicl-rerun is on, this property dictates + how often aicl is reran in seconds. Possible values + are 45, 90, 180, and 360. +- qcom,ibat-ocp-threshold-ua Maximum current before the battery will trigger + overcurrent protection. Use the recommended + battery pack value minus some margin. +- qcom,soft-vfloat-comp-disabled Set this property when the battery is + powered via external source and could + go above the float voltage. +- qcom,parallel-usb-min-current-ma Minimum current drawn by the primary + charger before enabling the parallel + charger if one exists. Do not define + this property if no parallel chargers + exist. +- qcom,parallel-usb-9v-min-current-ma Minimum current drawn by the primary + charger before enabling the parallel + charger if one exists. This property + applies only for 9V chargers. +- qcom,parallel-allowed-lowering-ma Acceptable current drop from the initial limit + to keep parallel charger activated. If the + charger current reduces beyond this threshold + parallel charger is disabled. Must be specified + if parallel charger is used. +- qcom,parallel-main-chg-fcc-percent Percentage of the fast charge current allotted to the + main charger when parallel charging is enabled and + operational. If this property is not defined, the + driver defaults to a 50%/50% split between the main + and parallel charger. +- qcom,parallel-main-chg-icl-percent Percentage of the input current allotted to the + main charger when parallel charging is enabled and + operational. If this property is not defined, the + driver defaults to a 60%/40% split between the main + and parallel charger. +- qcom,battery-data Points to the phandle of node which + contains the battery-profiles supported + by the charger/FG. +- qcom,chg-led-support A bool property to support the charger led feature. +- qcom,chg-led-sw-controls A bool property to allow the software to control + the charger led without a valid charger. +- qcom,skip-usb-notification A boolean property to be used when usb gets present + and type from other means. Especially true on + liquid hardware, where usb presence is detected based on GPIO. +- qcom,skip-usb-suspend-for-fake-battery A boolean property to skip + suspending USB path for fake + battery. +- qcom,vchg_sns-vadc Phandle of the VADC node. +- qcom,vchg-adc-channel-id The ADC channel to which the VCHG is routed. + +Example: + qcom,qpnp-smbcharger { + compatible = "qcom,qpnp-smbcharger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,iterm-ma = <100>; + qcom,float-voltage-mv = <4200>; + qcom,resume-delta-mv = <100>; + qcom,bmd-pin-src = "bpd_thm_id"; + qcom,dc-psy-type = "Mains"; + qcom,dc-psy-ma = <1500>; + qcom,bms-psy-name = "bms"; + qcom,battery-psy-name = "battery"; + qcom,thermal-mitigation = <1500 700 600 325>; + qcom,vchg_sns-vadc = <&pmi8950_vadc>; + qcom,vchg-adc-channel-id = <3>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0>, + <0x2 0x10 0x1>, + <0x2 0x10 0x2>, + <0x2 0x10 0x3>, + <0x2 0x10 0x4>, + <0x2 0x10 0x5>, + <0x2 0x10 0x6>, + <0x2 0x10 0x7>; + + interrupt-names = "chg-error", + "chg-inhibit", + "chg-prechg-sft", + "chg-complete-chg-sft", + "chg-p2f-thr", + "chg-rechg-thr", + "chg-taper-thr", + "chg-tcc-thr"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0>, + <0x2 0x12 0x1>, + <0x2 0x12 0x2>, + <0x2 0x12 0x3>, + <0x2 0x12 0x4>, + <0x2 0x12 0x5>, + <0x2 0x12 0x6>, + <0x2 0x12 0x7>; + + interrupt-names = "batt-hot", + "batt-warm", + "batt-cold", + "batt-cool", + "batt-ov", + "batt-low", + "batt-missing", + "batt-term-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0>, + <0x2 0x13 0x1>, + <0x2 0x13 0x2>, + <0x2 0x13 0x3>, + <0x2 0x13 0x4>, + <0x2 0x13 0x5>, + <0x2 0x13 0x6>; + + interrupt-names = "usbin-uv", + "usbin-ov", + "usbin-src-det", + "otg-fail", + "otg-oc", + "aicl-done", + "usbid-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0>, + <0x2 0x14 0x1>; + + interrupt-names = "dcin-uv", + "dcin-ov"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0>, + <0x2 0x16 0x1>, + <0x2 0x16 0x2>, + <0x2 0x16 0x3>, + <0x2 0x16 0x4>, + <0x2 0x16 0x5>; + + interrupt-names = "power-ok", + "temp-shutdown", + "wdog-timeout", + "flash-fail", + "otst2", + "otst3"; + }; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-typec.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-typec.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa4d2f1ecfecef5c307b3215d2b85e596c47fda3 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-typec.txt @@ -0,0 +1,61 @@ +QPNP USB Type-C module + +QPNP USB Type-C module supports USB type-c ports and detection of +USB Type-C chargers that can supply upto 3A Vbus current for charging. + +The QPNP USB Type-C interfaces via the SPMI bus. + +Required properties : +- compatible : Must be "qcom,qpnp-typec" +- reg: The SPMI address for this peripheral +- interrupts: Specifies the interrupt associated with the peripheral. +- interrupt-names: Specifies the interrupt names for the peripheral. Every + available interrupt needs to have an associated name + with it to indentify its purpose. + + - vrd-change: Triggers on change in current + capability of charger. + - ufp-detach: Triggers on cable detach in + UFP mode. + - ufp-detect: Triggers on charger insertion. + - dfp-detach: Triggers on cable detach in + DFP mode. + - dfp-detect: Triggers on OTG cable insertion. + - vbus-err: Triggers if VBUS is not + detected within 275 msec after + CC detection in UFP mode. + - vconn-oc: Triggers on VCONN overcurrent + in DFP mode with active cable. + +Optional properties: +- pinctrl-names : This should be defined if a target uses pinctrl framework + for SSMUX control pin. See "pinctrl" in + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt. + It should specify the names of the configs that pinctrl can install in driver. + Following are the pinctrl config that can be installed: + "typec_ssmux_config" : Default configuration of pins. +- -supply: handle to the regulator device tree node. + "supply-name" is "ss-mux" regulator to drive super-speed MUX chip. +- qcom,role-reversal-supported : A boolean property that when present enables + support of dual role class. + +Example: + qcom,qpnp-typec@bf00 { + compatible = "qcom,qpnp-typec"; + reg = <0xbf00 0x100>; + interrupts = <0x0 0xbf 0x0>, + <0x0 0xbf 0x1>, + <0x0 0xbf 0x2>, + <0x0 0xbf 0x3>, + <0x0 0xbf 0x4>, + <0x0 0xbf 0x6>, + <0x0 0xbf 0x7>; + + interrupt-names = "vrd-change", + "ufp-detach", + "ufp-detect", + "dfp-detach", + "dfp-detect", + "vbus-err", + "vconn-oc"; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1351-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1351-charger.txt index c200f942338436ebfab5ce6851fea971536f81a0..d7111cffb97b4ba47d582263fe1a7cedbe59e2b3 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb1351-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1351-charger.txt @@ -71,6 +71,8 @@ Optional Properties: If not specified the default value is active-low. - qcom,parallel-external-current-sense If present specifies external rsense is used for charge current sensing. +- qcom,stacked-batfet: Boolean flag. Specifies if parallel charger has stacked BATFET + cofiguration. Example for standalone charger: diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f12ec09e1f16a70e15483df747f7a6fbc9c7769 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt @@ -0,0 +1,95 @@ +Qualcomm Technologies, Inc. SMB1355 Charger Specific Bindings + +SMB1355 slave charger is paired with QTI family of standalone chargers to +enable a high current, low profile Li+ battery charging system. + +The device provides 28V DC withstand, wide operating input range of 3.8 to +14.2V for standard 5V USB inputs as well as a wide variety of HVDCP Travel +Adapters and is compatible with QTI's Quick Charge technology. + +======================= +Required Node Structure +======================= + +SMB1355 Charger must be described in two levels of device nodes. + +================================== +First Level Node - SMB1355 Charger +================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,smb1355". + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of SMB's revid module. This is used + to identify the SMB subtype. + +- qcom,disable-ctm + Usage: optional + Value type: + Definition: boolean flag. Usually a thermistor near usb/typeC connector is + connected to AUX. Set this flag to indicate the thermistor + doesn't exist. + +- qcom,parallel-mode + Usage: optional + Value type: + Definition: Specifies parallel charging mode. If not specified, MID-MID + option is selected by default. + +- qcom,stacked-batfet + Usage: optional + Value type: + Definition: boolean flag. Specifies if parallel charger has stacked BATFET + configuration. + In stacked batfet the main and parallel charger's batfet are + stacked one after the other and thus all the charge current + (FCC) flows through main. In a non-stacked configuration each + charger controls the charge current (FCC) separately. +================================================ +Second Level Nodes - SMB1355 Charger Peripherals +================================================ + +Peripheral specific properties: +- reg + Usage: required + Value type: + Definition: Address and size of the peripheral's register block. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +smb1355_charger: qcom,smb1355-charger { + compatible = "qcom,smb1355"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "wdog-bark"; + }; +}; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt index 5529e30811fb783361007c896120a74feb5f6cc3..fc0ee1f4a921b595e0d64cfef2c17d61d4db9aca 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt @@ -22,8 +22,7 @@ Charger specific properties: Definition: String which indicates the charging mode. Can be one of the following: Standalone/Parallel Master - "qcom,smb138x-charger" - smb138x Parallel Slave - "qcom,smb138x-parallel-slave" - smb1355 Parallel Slave - "qcom,smb1355-parallel-slave", + Parallel Slave - "qcom,smb138x-parallel-slave" - qcom,pmic-revid Usage: required @@ -36,8 +35,7 @@ Charger specific properties: Usage: optional Value type: Definition: Specifies parallel charging mode. If not specified, MID-MID - option is selected by default. Note that smb1355 can only - run in MID-MID configuration. + option is selected by default. - qcom,suspend-input Usage: optional @@ -45,6 +43,13 @@ Charger specific properties: Definition: Boolean flag which indicates that the charger should not draw current from any of its input sources (USB, DC). +- qcom,use-extcon + Usage: optional + Value type: + Definition: Boolean flag which specify that smb138x will act as main charger + to do extcon USB calls. If not defined, other charger driver can + act as main charger to do extcon USB calls. + - qcom,fcc-max-ua Usage: optional Value type: @@ -88,6 +93,12 @@ Charger specific properties: will use io-channel-names to match IIO input names with IIO specifiers. +- qcom,stacked-batfet + Usage: optional + Value type: + Definition: boolean flag. Specifies if parallel charger has stacked BATFET + cofiguration. + ================================================ Second Level Nodes - SMB138X Charger Peripherals ================================================ @@ -127,7 +138,7 @@ Example ======= smb138x_charger: qcom,smb138x-charger { - compatible = "qcom,smb138x-charger"; + compatible = "qcom,qpnp-smb138x-charger"; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt b/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt index 98d131acee95dbff1631e63a5c01db39c2b3def1..a11072c5a8660d362958995a6fd27123c296b2fa 100644 --- a/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt +++ b/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt @@ -2,11 +2,16 @@ TPS65217 Charger Required Properties: -compatible: "ti,tps65217-charger" +-interrupts: TPS65217 interrupt numbers for the AC and USB charger input change. + Should be <0> for the USB charger and <1> for the AC adapter. +-interrupt-names: Should be "USB" and "AC" This node is a subnode of the tps65217 PMIC. Example: tps65217-charger { - compatible = "ti,tps65090-charger"; + compatible = "ti,tps65217-charger"; + interrupts = <0>, <1>; + interrupt-names = "USB", "AC"; }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt new file mode 100644 index 0000000000000000000000000000000000000000..3174ccb0fd2d0ce26e4d729e86b130a53b10114f --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt @@ -0,0 +1,36 @@ +Qualcomm Technologies, Inc. LPG driver specific bindings + +This binding document describes the properties of LPG (Light Pulse Generator) +device module in Qualcomm Technologies, Inc. PMIC chips. + +- compatible: + Usage: required + Value type: + Definition: Must be "qcom,pwm-lpg". + +- reg: + Usage: required + Value type: + Definition: Register base and length for LPG modules. The length + varies based on the number of channels available in + the PMIC chips. + +- reg-names: + Usage: required + Value type: + Definition: The name of the register defined in the reg property. + It must be "lpg-base". + +- #pwm-cells: + Usage: required + Value type: + Definition: See Documentation/devicetree/bindings/pwm/pwm.txt; + +Example: + + pmi8998_lpg: lpg@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x600>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/qbt1000/qbt1000.txt b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9861e4948f9ca74c9cb203877fc56bcddd13ea2 --- /dev/null +++ b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt @@ -0,0 +1,54 @@ +Qualcomm Technologies, Inc. QBT1000 Specific Bindings + +QBT is a fingerprint sensor ASIC capable of performing fingerprint image scans +and detecting finger presence on the sensor using programmable firmware. + +======================= +Required Node Structure +======================= + +- compatible + Usage: required + Value type: + Definition: "qcom,qbt1000". + +- clock-names + Usage: required + Value type: + Definition: List of clock names that need to be voted on/off. + +- clocks + Usage: required + Value type: + Definition: Property pair that represents the clock controller and the clock + id. This in combination with the clock-name is used to obtain + the handle for the clock that needs to be voted on/off. + +- clock-frequency + Usage: required + Value type: + Definition: Frequency of clock in Hz. + +- qcom,ipc-gpio + Usage: required + Value type: + Definition: phandle for GPIO to be used for IPC. + +- qcom,finger-detect-gpio + Usage: required + Value type: + Definition: phandle for GPIO to be used for finger detect. + +======= +Example +======= + +qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clocks = <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>, + <&clock_gcc clk_gcc_blsp2_ahb_clk>; + clock-frequency = <15000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&pmcobalt_gpios 2 0>; +}; diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt index 9b1b9ee39b95c90bcb0aee12a43939bcb613ca3c..be8c2f00daa38023b6a5a06ac9888f6430fd02d9 100644 --- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt +++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt @@ -12,6 +12,9 @@ Required properties: Optional properties: - qcom,fastrpc-glink: Flag to use glink instead of smd for IPC +- qcom,rpc-latency-us: FastRPC QoS latency vote +- qcom,adsp-remoteheap-vmid: FastRPC remote heap VMID list +- qcom,fastrpc-adsp-audio-pdr: Flag to enable ADSP Audio PDR Optional subnodes: - qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context @@ -26,6 +29,8 @@ Example: qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-adsp"; qcom,fastrpc-glink; + qcom,rpc-latency-us = <2343>; + qcom,adsp-remoteheap-vmid = <22 37>; qcom,msm_fastrpc_compute_cb_1 { compatible = "qcom,msm-fastrpc-compute-cb"; diff --git a/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt b/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt new file mode 100644 index 0000000000000000000000000000000000000000..db7ab75ee5dbbf93203ba1587ede2efa20359693 --- /dev/null +++ b/Documentation/devicetree/bindings/qdsp/msm-ssc-sensors.txt @@ -0,0 +1,21 @@ +Qualcomm Technologies, Inc. SSC Driver + +msm-ssc-sensors driver implements the mechanism that allows to load SLPI firmware images. + +Required properties: + + - compatible: This must be "qcom,msm-ssc-sensors" + +Optional properties: + + - qcom,firmware-name: SLPI firmware name, must be "slpi" or "slpi_v1" or "slpi_v2" + Firmware name is not required, if sensors driver is sharing processor for execution. + + +Example: + The following for sdm845. + + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + qcom,firmware-name = "slpi"; + }; diff --git a/Documentation/devicetree/bindings/regulator/cpr-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c4dfbf5879549635a9b4f6ad6f81b5499c371c6 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/cpr-regulator.txt @@ -0,0 +1,978 @@ +QTI CPR (Core Power Reduction) Regulator + +CPR regulator device is for QTI RBCPR (RapidBridge CPR) on + application processor core. It takes voltage corner level + as input and converts it to actual voltage based on the + suggestions from factory production process. When CPR is + enabled for application processer core, it will suggest + scaling the voltage up or down for best performance and + power of the core. The scaling based on factory production + process is called PVS (Process Voltage Scaling) with efuse + bits to indicate what bin (and voltage range) a chip is in. + +Required properties: +- compatible: Must be "qcom,cpr-regulator" +- reg: Register addresses for RBCPR, RBCPR clock + select, PVS and CPR eFuse address +- reg-names: Register names. Must be "rbcpr" and "efuse_addr". + "rbcpr_clk" is optional. +- regulator-name: A string used to describe the regulator +- interrupts: Interrupt line from RBCPR to interrupt controller. +- qcom,cpr-fuse-corners: Number of fuse corners present. Many other properties + are sized based upon this value. +- regulator-min-microvolt: Minimum corner value which should be 1 to + represent the lowest supported corner. +- regulator-max-microvolt: Maximum corner value which should be equal to + qcom,cpr-fuse-corners if consumers request fuse + corners or the length of qcom,cpr-corner-map if + consumers request virtual corners. +- qcom,cpr-voltage-ceiling: Array of ceiling voltages in microvolts for fuse + corners ordered from lowest voltage corner to highest + voltage corner. This property must be of length + defined by qcom,cpr-fuse-corners. +- qcom,cpr-voltage-floor: Array of floor voltages in microvolts for fuse + corners ordered from lowest voltage corner to highest + voltage corner. This property must be of length + defined by qcom,cpr-fuse-corners. +- vdd-apc-supply: Regulator to supply VDD APC power +- qcom,vdd-apc-step-up-limit: Limit of vdd-apc-supply steps for scaling up. +- qcom,vdd-apc-step-down-limit: Limit of vdd-apc-supply steps for scaling down. +- qcom,cpr-ref-clk: The reference clock in kHz. +- qcom,cpr-timer-delay: The delay in microseconds for the timer interval. +- qcom,cpr-timer-cons-up: Consecutive number of timer interval (qcom,cpr-timer-delay) + occurred before issuing UP interrupt. +- qcom,cpr-timer-cons-down: Consecutive number of timer interval (qcom,cpr-timer-delay) + occurred before issuing DOWN interrupt. +- qcom,cpr-irq-line: Internal interrupt route signal of RBCPR, one of 0, 1 or 2. +- qcom,cpr-step-quotient: Defines the number of CPR quotient (i.e. Ring Oscillator(RO) + count) per vdd-apc-supply output voltage step. A single + integer value may be specified which is to be used for all + RO's. Alternatively, 8 integer values may be specified which + define the step quotients for RO0 to RO7 in order. +- qcom,cpr-up-threshold: The threshold for CPR to issue interrupt when + error_steps is greater than it when stepping up. +- qcom,cpr-down-threshold: The threshold for CPR to issue interrupt when + error_steps is greater than it when stepping down. +- qcom,cpr-idle-clocks: Idle clock cycles RO can be in. +- qcom,cpr-gcnt-time: The time for gate count in microseconds. +- qcom,cpr-apc-volt-step: The voltage in microvolt per CPR step, such as 5000uV. +- qcom,cpr-fuse-row: Array of row number of CPR fuse and method to read that row. It should have + index and value like this: + [0] => the fuse row number + [1] => fuse reading method, 0 for direct reading or 1 for SCM reading +- qcom,cpr-fuse-target-quot: Array of bit positions in the primary CPR fuse row defined + by qcom,cpr-fuse-row for the target quotients of each + fuse corner. Each bit position corresponds to the LSB + of the quotient parameter. The elements in the array + are ordered from lowest voltage corner to highest voltage + corner. This property must be of length defined by + qcom,cpr-fuse-corners. +- qcom,cpr-fuse-ro-sel: Array of bit positions in the primary CPR fuse row defined + by qcom,cpr-fuse-row for the ring oscillator selection for each + fuse corner. Each bit position corresponds to the LSB + of the RO select parameter. The elements in the array + are ordered from lowest voltage corner to highest voltage + corner. This property must be of length defined by + qcom,cpr-fuse-corners. + +Optional properties: +- vdd-mx-supply: Regulator to supply memory power as dependency + of VDD APC. +- qcom,vdd-mx-vmax: The maximum voltage in uV for vdd-mx-supply. This + is required when vdd-mx-supply is present. +- qcom,vdd-mx-vmin-method: The method to determine the minimum voltage for + vdd-mx-supply, which can be one of following + choices compared with VDD APC: + 0 => equal to the voltage(vmin) of VDD APC + 1 => equal to PVS corner ceiling voltage + 2 => equal to slow speed corner ceiling + 3 => equal to qcom,vdd-mx-vmax + 4 => equal to VDD_APC fuse corner mapped vdd-mx voltage + 5 => equal to VDD_APC virtual corner mapped vdd-mx voltage + This is required when vdd-mx-supply is present. +- qcom,vdd-mx-corner-map: Array of integers which defines the mapping from VDD_APC + voltage corners to vdd-mx-supply voltages. + Each element is a voltage to request from vdd-mx for the + corresponding fuse corner or virtual corner. The elements + in the array are ordered from lowest voltage corner + to highest voltage corner. The length of this property + depends on the value of qcom,vdd-mx-vmin-method property. + When qcom,vdd-mx-vmin-method property has a value of 4, the length + of this property must be equal to the value defined by qcom,cpr-fuse-corners. + When qcom,vdd-mx-vmin-method property has a value of 5, the length of + this property must be equal to the number of elements in the qcom,cpr-corner-map + property. +- qcom,pvs-voltage-table: Array of N-tuples in which each tuple specifies the + initial voltage in microvolts of the PVS bin for each + fuse voltage corner. The location or 0-based index + of a tuple in the list corresponds to the PVS bin number. + Each tuple must be of length defined by qcom,cpr-fuse-corners. + A given cpr-regulator device must have either + qcom,pvs-voltage-table specified or + qcom,cpr-fuse-init-voltage (and its associated properties). +- qcom,pvs-fuse-redun-sel: Array of 5 elements to indicate where to read the bits, what value to + compare with in order to decide if the redundant PVS fuse bits would be + used instead of the original bits and method to read fuse row, reading + register through SCM or directly. The 5 elements with index [0..4] are: + [0] => the fuse row number of the selector + [1] => LSB bit position of the bits + [2] => number of bits + [3] => the value to indicate redundant selection + [4] => fuse reading method, 0 for direct reading or 1 for SCM reading + When the value of the fuse bits specified by first 3 elements equals to + the value in 4th element, redundant PVS fuse bits should be selected. + Otherwise, the original PVS bits should be selected. If the 5th + element is 0, read the fuse row from register directly. Otherwise, + read it through SCM. + This property is required if qcom,pvs-voltage-table is present. +- qcom,pvs-fuse: Array of 4 elements to indicate the bits for PVS fuse and read method. + The array should have index and value like this: + [0] => the PVS fuse row number + [1] => LSB bit position of the bits + [2] => number of bits + [3] => fuse reading method, 0 for direct reading or 1 for SCM reading + This property is required if qcom,pvs-voltage-table is present. +- qcom,pvs-fuse-redun: Array of 4 elements to indicate the bits for redundant PVS fuse. + The array should have index and value like this: + [0] => the redundant PVS fuse row number + [1] => LSB bit position of the bits + [2] => number of bits + [3] => fuse reading method, 0 for direct reading or 1 for SCM reading + This property is required if qcom,pvs-voltage-table is present. +- qcom,cpr-fuse-redun-sel: Array of 5 elements to indicate where to read the bits, what value to + compare with in order to decide if the redundant CPR fuse bits would be + used instead of the original bits and method to read fuse row, using SCM + to read or read register directly. The 5 elements with index [0..4] are: + [0] => the fuse row number of the selector + [1] => LSB bit position of the bits + [2] => number of bits + [3] => the value to indicate redundant selection + [4] => fuse reading method, 0 for direct reading or 1 for SCM reading + When the value of the fuse bits specified by first 3 elements equals to + the value in 4th element, redundant CPR fuse bits should be selected. + Otherwise, the original CPR bits should be selected. If the 5th element + is 0, read the fuse row from register directly. Otherwise, read it through + SCM. +- qcom,cpr-fuse-redun-row: Array of row number of redundant CPR fuse and method to read that + row. It should have index and value like this: + [0] => the redundant fuse row number + [1] => the value to indicate reading the fuse row directly or using SCM + This property is required if qcom,cpr-fuse-redun-sel is present. +- qcom,cpr-fuse-redun-target-quot: Array of bit positions in the redundant CPR fuse row defined + by qcom,cpr-fuse-redun-row for the target quotients of each + fuse corner. Each bit position corresponds to the LSB + of the quotient parameter. The elements in the array + are ordered from lowest voltage corner to highest voltage corner. + This property must be of length defined by qcom,cpr-fuse-corners. + This property is required if qcom,cpr-fuse-redun-sel is present. +- qcom,cpr-fuse-redun-ro-sel: Array of bit positions in the redundant CPR fuse row defined + by qcom,cpr-fuse-redun-row for the ring oscillator select of each + fuse corner. Each bit position corresponds to the LSB of the RO + select parameter. The elements in the array are ordered from + lowest voltage corner to highest voltage corner. + This property must be of length defined by qcom,cpr-fuse-corners. + This property is required if qcom,cpr-fuse-redun-sel is present. +- qcom,cpr-fuse-redun-bp-cpr-disable: Redundant bit position of the bit to indicate if CPR should be disable +- qcom,cpr-fuse-redun-bp-scheme: Redundant bit position of the bit to indicate if it's a global/local scheme + This property is required if cpr-fuse-redun-bp-cpr-disable + is present, and vise versa. +- qcom,cpr-fuse-bp-cpr-disable: Bit position of the bit to indicate if CPR should be disabled +- qcom,cpr-fuse-bp-scheme: Bit position of the bit to indicate if it's a global/local scheme +- qcom,cpr-fuse-revision: Array of 4 integer elements which define the location of the bits for + the CPR fusing revision fuse parameter. The 4 elements are: + [0]: => the fuse row number of the bits + [1]: => LSB bit position of the bits + [2]: => the number of bits + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading + The fusing revision value is used to determine which specific adjustments + are required on some chips. +- qcom,cpr-fuse-target-quot-size: Array of target quotient parameter bit sizes in the primary + or redundant CPR fuse row for each fuse corner. The elements in the + array are ordered from lowest voltage corner to highest voltage corner. + If this property is not present, then all target quotient fuse values + are assumed to be the default length of 12 bits. +- qcom,cpr-fuse-target-quot-scale: Array of doubles which defines the scaling coefficients to decode + the target quotients of each fuse corner. The first element in each + double represents the offset to add to the scaled quotient. The second + element represents the multiplier to scale the quotient by. For example, + given a tuple , quot_decoded = A + (B * quot_raw). + The doubles in the array are ordered from lowest voltage corner to highest + voltage corner. This property must contain a number of doubles equal to + the value of qcom,cpr-fuse-corners. If this property is not present, + then all target quotient parameters are assumed to have an offset of 0 + and a multiplier of 1 (i.e. no decoding needed). +- qcom,cpr-enable: Present: CPR enabled by default. + Not Present: CPR disable by default. +- qcom,cpr-fuse-cond-min-volt-sel: Array of 5 elements to indicate where to read the bits, what value to + compare with in order to decide if the conditional minimum apc voltage needs + to be applied and the fuse reading method. + The 5 elements with index[0..4] are: + [0] => the fuse row number; + [1] => LSB bit position of the bits; + [2] => number of the bits; + [3] => the expected data to read; + [4] => fuse reading method, 0 for direct reading or 1 for SCM reading; + When the value of the fuse bits specified by first 3 elements is not equal to + the value in 4th element, then set the apc voltage for all parts running + at each voltage corner to be not lower than the voltage defined + using "qcom,cpr-cond-min-voltage". +- qcom,cpr-cond-min-voltage: Minimum voltage in microvolts allowed for cpr-regulator output if the fuse bits + defined in qcom,cpr-fuse-cond-min-volt-sel have not been programmed with the + expected data. This is required if cpr-fuse-cond-min-volt-sel is present. +- qcom,cpr-fuse-uplift-sel: Array of 5 elements to indicate where to read the bits, what value to + compare with in order to enable or disable the pvs voltage uplift workaround, + and the fuse reading method. + The 5 elements with index[0..4] are: + [0]: => the fuse row number of the selector; + [1]: => LSB bit position of the bits; + [2]: => number of the bits; + [3]: => the value to indicate if the apc pvs voltage uplift workaround will + be enabled; + [4]: => fuse reading method, 0 for direct reading or 1 for SCM reading. + When the value of the fuse bits specified by first 3 elements equals to the + value in 4th element, the pvs voltage uplift workaround will be enabled. +- qcom,speed-bin-fuse-sel: Array of 4 elements to indicate where to read the speed bin of the processor, + and the fuse reading method. + The 4 elements with index[0..3] are: + [0]: => the fuse row number of the selector; + [1]: => LSB bit position of the bits; + [2]: => number of the bits; + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading. + This is required if cpr-fuse-uplift-disable-sel is present. +- qcom,cpr-uplift-voltage: Uplift in microvolts used for increasing pvs init voltage. If this property is present, + This is required if cpr-fuse-uplift-disable-sel is present. +- qcom,cpr-uplift-max-volt: Maximum voltage in microvolts used for pvs voltage uplift workaround to limit + the maximum pvs voltage. + This is required if cpr-fuse-uplift-disable-sel is present. +- qcom,cpr-uplift-quotient: Array of target quotient increments to add to the fused quotients of each + fuse corner as part of the PVS voltage uplift workaround. + The elements in the array are ordered from lowest voltage + corner to highest voltage corner. This property must be of + length defined by qcom,cpr-fuse-corners. This is required + if cpr-fuse-uplift-disable-sel is present. +- qcom,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the + pvs voltage uplift workaround. + This is required if cpr-fuse-uplift-disable-sel is present. +- qcom,cpr-fuse-version-map: Array of integer tuples which each match to a given combination of CPR + fuse parameter values. Each tuple consists of N + 3 elements. Where + N is the number of fuse corners defined by the qcom,cpr-fuse-corners + property. The elements in one tuple are: + [0]: => the speed bin of the CPU + [1]: => the PVS version of the CPU + [2]: => the CPR fuse revision + [3 - N+2]: => the ring oscillator select value of each fuse corner + ordered from lowest to highest + Any element in a tuple may use the value 0xffffffff as a wildcard + which will match against any fuse parameter value. The first tuple + that matches against the fuse values read from hardware will be used. + This property is used by several properties to provide an index into + their lists. +- qcom,cpr-allowed: Integer values that specifies whether the closed loop CPR is allowed or + not for a particular fuse revision. If the qcom,cpr-fuse-version-map + property is specified, then qcom,cpr-allowed must contain the same number + of integers as that of the number of tuples in qcom,cpr-fuse-version-map. + If the integer value has a value 0 for a particular fuse revision, then it + is treated as if the closed loop operation is disabled in the fuse. If the + integer value has a value 1 for a particular fuse revision, then the closed + loop operation is enabled for that fuse revision. If nothing is specified + for a particular fuse revision, then the closed loop operation is enabled + for that fuse revision by default. +- qcom,cpr-quotient-adjustment: Array of integer tuples of target quotient adjustments to add to the fused + quotients of each fuse corner. The elements in a tuple are ordered from + lowest voltage corner to highest voltage corner. Each tuple must be of + length defined by qcom,cpr-fuse-corners. If the qcom,cpr-fuse-version-map + property is specified, then qcom,cpr-quotient-adjustment must contain the + same number of tuples as qcom,cpr-fuse-version-map. These tuples are then + mapped one-to-one in the order specified. E.g. if the second + qcom,cpr-fuse-version-map tuple matches for a given device, then the quotient + adjustments defined in the second qcom,cpr-quotient-adjustment tuple will + be applied. If the qcom,cpr-fuse-version-map property is not specified, + then qcom,cpr-quotient-adjustment must contain a single tuple which is then + applied unconditionally. If this property is specified, then the quotient + adjustment values are added to the target quotient values read from fuses + before writing them into the CPR GCNT target control registers. + This property can be used to add or subtract static voltage margin from the + regulator managed by the CPR controller. +- qcom,cpr-init-voltage-adjustment: Array of integer tuples of initial voltage adjustments in microvolts to + add to the fused initial voltage values of each fuse corner. The elements + in a tuple are ordered from lowest voltage corner to highest voltage corner. + Each tuple must be of the length defined by qcom,cpr-fuse-corners. If the + qcom,cpr-fuse-version-map property is specified, then + qcom,cpr-init-voltage-adjustment must contain the same number of tuples as + qcom,cpr-fuse-version-map. These tuples are then mapped one-to-one in the + order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches + for a given device, then the initial voltage adjustments defined in the + second qcom,cpr-init-voltage-adjustment tuple will be applied. If the + qcom,cpr-fuse-version-map property is not specified, then + qcom,cpr-init-voltage-adjustment must contain a single tuple which is then + applied unconditionally. This property can be used to add or subtract + static initial voltage margin from the regulator managed by the CPR + controller. +- qcom,cpr-quot-offset-adjustment: Array of integer tuples of target quotient offset adjustments to add + to the fused quotient offsets of each fuse corner. The elements in a tuple + are ordered from lowest voltage corner to highest voltage corner. Each tuple + must be of length defined by qcom,cpr-fuse-corners. If the qcom,cpr-fuse-version-map + property is specified, then qcom,cpr-quot-offset-adjustment must contain the + same number of tuples as qcom,cpr-fuse-version-map. These tuples are then + mapped one-to-one in the order specified. E.g. if the second + qcom,cpr-fuse-version-map tuple matches for a given device, then the quotient + offset adjustments defined in the second qcom,cpr-quot-offset-adjustment tuple + will be applied. If the qcom,cpr-fuse-version-map property is not specified, + then qcom,cpr-quot-offset-adjustment must contain a single tuple which is then + applied unconditionally. If this property is specified, then the quotient + offset adjustment values are added to the target quotient offset values read + from fuses. + This property can be used to add or subtract static quotient offset margin from + the regulator managed by the CPR controller. +- qcom,cpr-clamp-timer-interval: The number of 64 reference clock cycle blocks to delay for whenever + the clamp signal, sensor mask registers or sensor bypass registers + change. The CPR controller loop is disabled during this delay. + Supported values are 0 to 255. If this property is not specified, + then a value of 0 is assumed. Note that if this property has a + value greater than 0, then software cannot accurately determine the + error_steps value that corresponds to a given CPR measurement + unless processor power collapsing is disabled. If this property + has a value of 0, then the CPR controller loop is not disabled and + re-enabled while idle if the clamp signal changes. Instead, it + will remain idle until software issues an ACK or NACK command. + This ensures that software can read the error_steps value which + resulted in the CPR up or down interrupt. Setting this property to + a value greater than 0 is useful for resetting the CPR sensors of a + processor that uses BHS type voltage switches in order to avoid + anomalous CPR up interrupts when exiting from power collapse. +- vdd-apc-optional-prim-supply: Present: Regulator of highest priority to supply VDD APC power + Not Present: No such regulator. +- vdd-apc-optional-sec-supply: Present: Regulator of second highest priority to supply VDD APC power. + Not Present: No such regulator. +- qcom,cpr-speed-bin-max-corners: Array of (N+2)-tuples in which each tuple maps a CPU speed bin and PVS version to + the maximum virtual voltage corner corresponding to each fuse corner. The value N + corresponds to the number of fuse corners specified by qcom,cpr-fuse-corners. + The elements in one tuple are: + [0]: => the speed bin of the CPU. It may use the value 0xffffffff as a + wildcard to match any speed bin values. + [1]: => the PVS version of the CPU. It may use the value 0xffffffff as + a wildcard to match any PVS version values. + [2 - N+1]: => the max virtual voltage corner value corresponding to each fuse corner + for this speed bin, ordered from lowest voltage corner to highest + voltage corner. + No CPR target quotient scaling is applied on chips which have a speed bin + PVS version + pair that does not appear in one of the tuples in this property. If the property is + specified, then quotient scaling is enabled for the highest voltage corner. If this property is + not specified, then no quotient scaling can take place. +- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner. + The location or 1-based index of an element in the list corresponds to + the virtual corner value. For example, the first element in the list is the fuse corner + value that virtual corner 1 maps to. + This property is required if qcom,cpr-speed-bin-max-corners is present. +- qcom,cpr-corner-frequency-map: Array of tuples in which a tuple describes a corner to application processor frequency + mapping. + The 2 elements in one tuple are: + [0]: => a virtual voltage corner. + [1]: => the application processor frequency in Hz corresponding to the virtual corner. + This property is required if qcom,cpr-speed-bin-max-corners is present. +- qcom,pvs-version-fuse-sel: Array of 4 elements to indicate where to read the pvs version of the processor, + and the fuse reading method. + The 4 elements with index[0..3] are: + [0]: => the fuse row number of the selector; + [1]: => LSB bit position of the bits; + [2]: => the number of bits; + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading. +- qcom,cpr-voltage-ceiling-override: Array of (N+2)-tuples in which each tuple maps a CPU speed bin and PVS version + to the ceiling voltage to apply for each virtual voltage corner. The value N + corresponds to the number of virtual corners as specified by the number of elements + in the qcom,cpr-corner-map property. + The elements in one tuple are: + [0]: => the speed bin of the CPU. It may use the value 0xffffffff as a + wildcard to match any speed bin values. + [1]: => the PVS version of the CPU. It may use the value 0xffffffff as a + wildcard to match any PVS version values. + [2 - N+1]: => the ceiling voltage value in microvolts corresponding to each virtual + corner for this speed bin, ordered from lowest voltage corner to + highest voltage corner. + No ceiling override is applied on chips which have a speed bin + PVS version + pair that does not appear in one of the tuples in this property. If the property is + specified and the speed bin + PVS version matches, then the per-virtual-corner ceiling + voltages will be used in place of the per-fuse-corner ceiling voltages defined in the + qcom,cpr-voltage-ceiling property. If this property is not specified, then the + per-fuse-corner ceiling voltages will always be used. +- qcom,cpr-voltage-floor-override: Array of (N+2)-tuples in which each tuple maps a CPU speed bin and PVS version + to the floor voltage to apply for each virtual voltage corner. The value N + corresponds to the number of virtual corners as specified by the number of elements + in the qcom,cpr-corner-map property. + The elements in one tuple are: + [0]: => the speed bin of the CPU. It may use the value 0xffffffff as a + wildcard to match any speed bin values. + [1]: => the PVS version of the CPU. It may use the value 0xffffffff as a + wildcard to match any PVS version values. + [2 - N+1]: => the floor voltage value in microvolts corresponding to each virtual + corner for this speed bin, ordered from lowest voltage corner to + highest voltage corner. + No floor override is applied on chips which have a speed bin + PVS version + pair that does not appear in one of the tuples in this property. If the property is + specified and the speed bin + PVS version matches, then the per-virtual-corner floor + voltages will be used in place of the per-fuse-corner floor voltages defined in the + qcom,cpr-voltage-floor property. If this property is not specified, then the + per-fuse-corner floor voltages will always be used. +- qcom,cpr-floor-to-ceiling-max-range: Array of integer tuples of floor-to-ceiling max range values in microvolts + to be subtracted from the ceiling voltage values of each virtual corner. + Supported values are those greater than or equal 0, or (-1). The value 0 for a corner + implies that the floor value for that corner has to equal to its ceiling value. + The value (-1) for a corner implies that no modification to the default floor voltage + is required. The elements in a tuple are ordered from lowest voltage corner to highest + voltage corner. Each tuple must be of the length equal to the number of virtual corners + as specified by the number of elements in the qcom,cpr-corner-map property. If the + qcom,cpr-fuse-version-map property is specified, then + qcom,cpr-dynamic-floor-override-adjustment must contain the same number of + tuples as qcom,cpr-fuse-version-map. These tuples are then mapped one-to-one in the + order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches + for a given device, then voltage adjustments defined in the second + qcom,cpr-dynamic-floor-override-adjustment tuple will be applied. If the + qcom,cpr-fuse-version-map property is not specified, then + qcom,cpr-dynamic-floor-override-adjustment must contain a single tuple which + is then applied unconditionally. +- qcom,cpr-virtual-corner-init-voltage-adjustment: Array of integer tuples of voltage adjustments in microvolts to be + added to the initial voltage values of each virtual corner. The elements + in a tuple are ordered from lowest voltage corner to highest voltage corner. + Each tuple must be of the length equal to the number of virtual corners as + specified by the number of elements in the qcom,cpr-corner-map property. If the + qcom,cpr-fuse-version-map property is specified, then + qcom,cpr-virtual-corner-init-voltage-adjustment must contain the same number of + tuples as qcom,cpr-fuse-version-map. These tuples are then mapped one-to-one in the + order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches + for a given device, then voltage adjustments defined in the second + qcom,cpr-virtual-corner-init-voltage-adjustment tuple will be applied. If the + qcom,cpr-fuse-version-map property is not specified, then + qcom,cpr-virtual-corner-init-voltage-adjustment must contain a single tuple which + is then applied unconditionally. +- qcom,cpr-virtual-corner-quotient-adjustment: Array of integer tuples of quotient offsets to be added to + the scaled target quotient of each virtual corner. The elements + in a tuple are ordered from lowest voltage corner to highest voltage corner. + Each tuple must be of the length equal to the number of virtual corners as + specified by the number of elements in the qcom,cpr-corner-map property. + If the qcom,cpr-fuse-version-map property is specified, then + qcom,cpr-virtual-corner-quotient-adjustment must contain the same number of tuples as + qcom,cpr-fuse-version-map. These tuples are then mapped one-to-one in the + order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches + for a given device, then quotient adjustments defined in the second + qcom,cpr-virtual-corner-quotient-adjustment tuple will be applied. If the + qcom,cpr-fuse-version-map property is not specified, then + qcom,cpr-virtual-corner-quotient-adjustment must contain a single tuple which is then + applied unconditionally. +- qcom,cpr-cpus: Array of CPU phandles which correspond to the cores that this cpr-regulator + device must monitor when adjusting the voltage and/or target quotient based + upon the number of online cores or make sure that one of them must be online + when performing de-aging measurements. This property must be specified in order to + utilize the qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment or + qcom,cpr-online-cpu-virtual-corner-quotient-adjustment or qcom,cpr-aging-sensor-id properties. +- qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment: Array of tuples where each tuple specifies + the voltage adjustment for each corner. These adjustments apply to the + initial voltage of each corner. The size of each tuple must be equal + to qcom,cpr-fuse-corners if consumers request fuse corners or the length of + qcom,cpr-corner-map if consumers request virtual corners. In each tuple, the + value corresponds to the voltage adjustment when running at that corner at + init, from lowest to highest. The tuples must be organized into 1 group if + qcom,cpr-fuse-version-map is not specified or the same number of groups as + the number of tuples in qcom,cpr-fuse-version-map. The i-th group of tuples + corresponds to the voltage adjustments for i-th fuse version map tuple. In + each group, there are 1 plus length of qcom,cpr-cpus tuples, each tuple + corresponds to the number of cores online, from 0 to the number of elements + in qcom,cpr-cpus. +- qcom,cpr-online-cpu-init-voltage-as-ceiling: Boolean which indicates that the ceiling voltage used for a + given virtual corner may be reduced to the per number of cores online, + per-virtual corner ceiling voltage value. This property takes precedence + over qcom,cpr-scaled-init-voltage-as-ceiling if both are specified. +- qcom,cpr-online-cpu-virtual-corner-quotient-adjustment: Array of tuples where each tuple specifies + the quotient adjustment for each corner. These adjustments will be applied + to each corner at run time. The size of each tuple must be equal to + qcom,cpr-fuse-corners if consumers request fuse corners or the length of + qcom,cpr-corner-map if consumers request virtual corners. In each tuple, + the value corresponds to the quotient adjustment when running at that corner, + from lowest to highest. The tuples must be organized into 1 group if + qcom,cpr-fuse-version-map is not specified or the same number of groups + as the number of tuples in qcom,cpr-fuse-version-map. The i-th group of + tuples corresponds to the quotient adjustments for i-th fuse version map + tuple. In each group, there are 1 plus length of qcom,cpr-cpus tuples, + each tuple corresponds to the number of cores online, from 0 to the + number of elements in qcom,cpr-cpus. +- qcom,cpr-init-voltage-as-ceiling: Boolean which indicates that the ceiling voltage used for a given virtual + corner may be reduced to the per-fuse-corner initial voltage fuse value. +- qcom,cpr-scaled-init-voltage-as-ceiling: Boolean which indicates that the ceiling voltage used for a given + virtual corner may be reduced to the interpolated, per-virtual-corner initial + voltage value. Note that if both qcom,cpr-init-voltage-as-ceiling and + qcom,cpr-scaled-init-voltage-as-ceiling are specified, then + qcom,cpr-scaled-init-voltage-as-ceiling will take precedence since the interpolated + voltages are necessarily less than or equal to the fused initial voltage values. +- qcom,cpr-voltage-scaling-factor-max: Array of values which define the maximum allowed scaling factor to apply + when calculating per-corner initial voltage values for each fuse corner. The + array must be of length equal to the value of the qcom,cpr-fuse-corners property. + Each element in the array maps to the fuse corners in increasing order. + The elements have units of uV/MHz. Each element corresponds to 'max_factor' in + the following equation: + init_voltage_min(f) = fuse_init_voltage(f) - (fuse_f_max - f) * max_factor + If this property is not specified, then the initial voltage for each virtual + corner will be set to the initial voltage of the associated fuse corner. +- qcom,cpr-quot-adjust-scaling-factor-max: Array of values which define the maximum allowed scaling factor to + apply when calculating per-virtual-corner target quotients for each fuse + corner. Two data formats are allowed for this property. The primary one + requires that the array be of length equal to the value of the + qcom,cpr-fuse-corners property. When using this format, each element in the + array maps to the fuse corners in increasing order. The second depreciated + format allows for only a single element to be specified which defines the + maximum scaling factor for the highest fuse corner. In this case, a value of + 0 is assumed for the lower fuse corners. The elements of this property have + units of QUOT/GHz. Each element corresponds to 'max_factor' in the following + equation: + quot_min(f) = fuse_quot(f) - (fuse_f_max - f) * max_factor / 1000 + where f and fuse_f_max have units of MHz. + This property is required if qcom,cpr-speed-bin-max-corners is present. +- qcom,cpr-fuse-init-voltage: Array of quadruples in which each quadruple specifies a fuse location to + read in order to get an initial voltage for a fuse corner. The fuse values + are encoded as voltage steps higher or lower than the voltages defined in + qcom,cpr-voltage-ceiling. Each step corresponds to the voltage defined by + the qcom,cpr-init-voltage-step property. + The 4 elements in one quadruple are: + [0]: => the fuse row number of the bits + [1]: => LSB bit position of the bits + [2]: => number of the bits + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading + The quadruples are ordered from the lowest voltage fuse corner to the + highest voltage fuse corner. + A given cpr-regulator device must have either qcom,cpr-fuse-init-voltage + specified or qcom,pvs-voltage-table (and its associated properties). +- qcom,cpr-fuse-redun-init-voltage: Array of quadruples in which each quadruple specifies a fuse location + to read in order to get the redundant initial voltage for a fuse corner. + This property is the same as qcom,cpr-fuse-init-voltage except that it is + only utilized if a chip is configured to use the redundant set of fuse + values. This property is required if qcom,cpr-fuse-redun-sel and + qcom,cpr-fuse-init-voltage are specified. +- qcom,cpr-init-voltage-ref: Array of reference voltages in microvolts used when decoding the initial + voltage fuse values. The elements in the array are ordered from lowest + voltage corner to highest voltage corner. This property must be of length + defined by qcom,cpr-fuse-corners. + This property is required if qcom,cpr-fuse-init-voltage is present. +- qcom,cpr-init-voltage-step: The voltage step size in microvolts of the CPR initial voltage fuses described by the + qcom,cpr-fuse-init-voltage property. + This property is required if qcom,cpr-fuse-init-voltage is present. +- mem-acc-supply: Regulator to vote for the memory accelerator configuration. + Not Present: memory accelerator configuration not supported. +- qcom,mem-acc-corner-map: Array of integer which defines the mapping from mem-acc corner value for each + virtual corner. Each element is a mem-acc state for the corresponding virtual corner. + The elements in the array are ordered from lowest voltage corner to highest voltage corner. +- qcom,fuse-remap-source: Array of quadruples in which each quadruple specifies a fuse location to + remap. The 4 elements in one quadruple are: + [0]: => the fuse row number of the bits + [1]: => LSB bit position of the bits + [2]: => the number of bits + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading + The fuse bits for all quadruples are packed together in the order specified + into 64-bit virtual fuse rows beginning at the row number defined in the + qcom,fuse-remap-base-row property. The remapped rows may be used by any + other properties. + Example: + qcom,fuse-remap-base-row = <1000>; + qcom,fuse-remap-source = + <13 57 2 0>, + <14 30 3 0>, + <20 1 7 0>, + <40 47 120 0>; + + This results in the following bit remapping: + + Row Bits Remap Row Remap Bits + 13 57..58 --> 1000 0..1 + 14 30..32 --> 1000 2..4 + 20 1..7 --> 1000 5..11 + 40 47..63 --> 1000 12..28 + 41 0..34 --> 1000 29..63 + 41 35..63 --> 1001 0..28 + 42 0..34 --> 1001 29..63 + 42 35..38 --> 1002 0..3 + + A tuple like this could then be used to reference some of the + concatenated bits from rows 13, 14, and 20: + + qcom,cpr-fuse-init-voltage = <1000 0 6 0>; +- qcom,fuse-remap-base-row: Integer which defines the virtual row number to use as a base when remapping + fuse bits. The remap base row number can be any value as long as it is + greater than all of the real row numbers addressed in other properties of + the cpr-regulator device node. This property is required if + qcom,fuse-remap-source is specified. +- qcom,cpr-quot-min-diff: Integer which defines the minimum target-quotient difference between + the highest and (highest - 1) fuse corner to keep CPR enabled. If this + property is not specified a default value of 50 is used. +- qcom,cpr-fuse-quot-offset: Array of quadruples in which each quadruple specifies a fuse location to + read in order to get the quotient offset for a fuse corner. The fuse values + are encoded as the difference between quotients of that fuse corner and its + adjacent lower fuse corner divided by an unpacking multiplier value defined + under qcom,cpr-fuse-quot-offset-scale property. + The 4 elements in one quadruple are: + [0]: => the fuse row number of the bits + [1]: => LSB bit position of the bits + [2]: => number of the bits + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading + The quadruples are ordered from the lowest fuse corner to the highest + fuse corner. + Quotient offset read from the fuse locations above can be overridden with + the property qcom,cpr-quot-adjust-scaling-factor-max. +- qcom,cpr-fuse-quot-offset-scale: Array of integer values which defines the multipliers to decode the quotient offsets + of each fuse corner. The elements in the array are ordered from the lowest voltage fuse corner + to the highest voltage fuse corner. If this property is not present, then all target quotient + parameters are assumed to have a multiplier of 1 (i.e. no decoding needed). +- qcom,cpr-redun-fuse-quot-offset: Array of quadruples in which each quadruple specifies a fuse location to + read in order to get the redundant quotient offset for a fuse corner. This + property is the same as qcom,cpr-fuse-quot-offset except that it is only + utilized if a chip is configured to use the redundant set of fuse values. +- qcom,cpr-fuse-min-quot-diff: Array of values which define the minimum difference allowed between the adjusted + quotients of the fuse corners. The length of the array should be equal to the value + of the qcom,cpr-fuse-corners property. Where each element in the array maps to the + fuse corners in increasing order. +- qcom,cpr-min-quot-diff-adjustment: Array of integer tuples of target quotient offsets to be added to + the adjusted target quotients of each fuse corner. When the quotient difference + between two adjacent fuse corners is insufficient, the quotient for the higher fuse corner is + replaced with that of the lower fuse corner plus the adjustment value. + The elements in a tuple are ordered from lowest voltage corner to highest voltage corner. + Each tuple must be of the length defined by qcom,cpr-fuse-corners. + If the qcom,cpr-fuse-version-map property is specified, then qcom,cpr-min-quot-diff-adjustment + must contain the same number of tuples as qcom,cpr-fuse-version-map. These tuples are then mapped + one-to-one in the order specified. E.g. if the second qcom,cpr-fuse-version-map tuple matches + for a given device, then the quotient adjustments defined in the + second qcom,cpr-min-quot-diff-adjustment tuple will be applied. If the + qcom,cpr-fuse-version-map property is not specified, then + qcom,cpr-min-quot-diff-adjustment must contain a single tuple which is then + applied unconditionally. The qcom,cpr-min-quot-diff-adjustment property must be specified + if the qcom,cpr-fuse-min-quot-diff property is specified. +- qcom,cpr-skip-voltage-change-during-suspend: Boolean property which indicates that the CPR voltage + should not be adjusted based upon the number of online cores while + entering or exiting system suspend. +- rpm-apc-supply: Regulator to notify RPM of the APC operating + corner +- qcom,rpm-apc-corner-map: Array of integers which define the mapping of + the RPM corner to the corresponding APC virtual + corner. This property must be defined if + 'rpm-apc-supply' is present. +- qcom,vsens-corner-map: Array of integers which define the mapping of the VSENS corner to the + corresponding APC fuse corner. The qcom,vsens-corner-map and + vdd-vsense-corner-supply properties must both be specified for a given + cpr-regulator device or neither must be specified. +- vdd-vsens-corner-supply: Regulator to specify the current operating fuse corner to the Voltage Sensor. +- vdd-vsens-voltage-supply: Regulator to specify the corner floor/ceiling voltages to the Voltage Sensor. +- qcom,cpr-aging-sensor-id: Array of CPR sensor IDs to be used in the CPR de-aging algorithm. The number + of values should be equal to number of sensors selected for age calibration. + If this property is not specified, then the de-aging procedure is not enabled. +- qcom,cpr-de-aging-allowed: Integer values that specify whether the CPR de-aging procedure is allowed or + not for a particular fuse revision. If the qcom,cpr-fuse-version-map + property is specified, then qcom,cpr-de-aging-allowed must contain the same number + of elements as there are tuples in qcom,cpr-fuse-version-map. If qcom,cpr-fuse-version-map + is not specified, then qcom,cpr-de-aging-allowed must contain a single value that + is used unconditionally. An element value of 1 means that the CPR de-aging procedure + can be performed for parts with the corresponding fuse revision. An element value of 0 + means that CPR de-aging cannot be performed. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-aging-ref-corner: The vdd-apc-supply reference virtual voltage corner to be set during the CPR de-aging + measurements. This corner value is needed to set appropriate voltage on + the dependent voltage rails such as vdd-mx and mem-acc. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-aging-ref-voltage: The vdd-apc-supply reference voltage in microvolts to be set during the + CPR de-aging measurements. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-max-aging-margin: The maximum allowed aging voltage margin in microvolts. This is used to limit + the calculated aging voltage margin. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-non-collapsible-sensors: Array of CPR sensor IDs which are in non-collapsible domain. The sensor IDs not + specified in the array should be bypassed for the de-aging procedure. The number of + elements should be less than or equal to 32. The values of the array elements should + be greater than or equal to 0 and less than or equal to 31. + This property is required for power-domains with bypass mux present in HW. + This property can be required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-aging-ro-scaling-factor: The aging ring oscillator (RO) scaling factor with units of QUOT/V. + This value is used for calculating a voltage margin from RO measurements. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-ro-scaling-factor: Array of scaling factors with units of QUOT/V for each ring oscillator ordered + from the lowest to the highest RO. These values are used to calculate + the aging voltage margin adjustment for all of the ROs. Since CPR2 supports + exactly 8 ROs, the array must contain 8 elements corresponding to RO0 through RO7 in order. + If a given RO is unused for a fuse corner, then its scaling factor may be specified as 0. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-aging-derate: Array of scaling factors which define the amount of derating to apply to the reference + aging voltage margin adjustment for each of the fuse corners. Each element has units + of uV/mV. This property must be of length defined by qcom,cpr-fuse-corners. + The elements are ordered from the lowest to the highest fuse corner. + This property is required if the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-fuse-aging-init-quot-diff: Array of quadruples in which each quadruple specifies a fuse location to read in + order to get an initial quotient difference. The difference between quot min and quot max + is fused as the initial quotient difference. + The 4 elements in one quadruple are: + [0]: => the fuse row number of the bits + [1]: => LSB bit position of the bits + [2]: => number of the bits + [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading + The number of quadruples should be equal to the number of values specified in + the qcom,cpr-aging-sensor-id property. This property is required if + the qcom,cpr-aging-sensor-id property has been specified. +- qcom,cpr-thermal-sensor-id: TSENS hardware sensor-id of the sensor which + needs to be monitored. +- qcom,cpr-disable-temp-threshold: The TSENS temperature threshold in degrees Celsius at which CPR + closed-loop is disabled. CPR closed-loop will stay disabled as long as the + temperature is below this threshold. This property is required + only if 'qcom,cpr-thermal-sensor-id' is present. +- qcom,cpr-enable-temp-threshold: The TSENS temperature threshold in degrees Celsius at which CPR + closed-loop is enabled. CPR closed-loop will stay enabled above this + temperature threshold. This property is required only if + 'qcom,cpr-thermal-sensor-id' is present. +- qcom,disable-closed-loop-in-pc: Bool property to disable closed-loop CPR during + power-collapse. This can be enabled only for single core + designs. The property 'qcom,cpr-cpus' is required to enable this logic. +Example: + apc_vreg_corner: regulator@f9018000 { + status = "okay"; + compatible = "qcom,cpr-regulator"; + reg = <0xf9018000 0x1000>, <0xfc4b8000 0x1000>; + reg-names = "rbcpr", "efuse_addr"; + interrupts = <0 15 0>; + regulator-name = "apc_corner"; + qcom,cpr-fuse-corners = <3>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <12>; + + qcom,pvs-fuse = <22 6 5 1>; + qcom,pvs-fuse-redun-sel = <22 24 3 2 1>; + qcom,pvs-fuse-redun = <22 27 5 1>; + + qcom,pvs-voltage-table = + <1050000 1150000 1350000>, + <1050000 1150000 1340000>, + <1050000 1150000 1330000>, + <1050000 1150000 1320000>, + <1050000 1150000 1310000>, + <1050000 1150000 1300000>, + <1050000 1150000 1290000>, + <1050000 1150000 1280000>, + <1050000 1150000 1270000>, + <1050000 1140000 1260000>, + <1050000 1130000 1250000>, + <1050000 1120000 1240000>, + <1050000 1110000 1230000>, + <1050000 1100000 1220000>, + <1050000 1090000 1210000>, + <1050000 1080000 1200000>, + <1050000 1070000 1190000>, + <1050000 1060000 1180000>, + <1050000 1050000 1170000>, + <1050000 1050000 1160000>, + <1050000 1050000 1150000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>, + <1050000 1050000 1140000>; + qcom,cpr-voltage-ceiling = <1050000 1150000 1280000>; + qcom,cpr-voltage-floor = <1050000 1050000 1100000>; + vdd-apc-supply = <&pm8226_s2>; + vdd-apc-optional-prim-supply = <&ncp6335d>; + vdd-apc-optional-sec-supply = <&fan53555>; + vdd-mx-supply = <&pm8226_l3_ao>; + qcom,vdd-mx-vmax = <1350000>; + qcom,vdd-mx-vmin-method = <1>; + qcom,vdd-apc-step-up-limit = <1>; + qcom,vdd-apc-step-down-limit = <1>; + qcom,cpr-ref-clk = <19200>; + qcom,cpr-timer-delay = <5000>; + qcom,cpr-timer-cons-up = <1>; + qcom,cpr-timer-cons-down = <2>; + qcom,cpr-irq-line = <0>; + qcom,cpr-step-quotient = <15>; + qcom,cpr-up-threshold = <1>; + qcom,cpr-down-threshold = <2>; + qcom,cpr-idle-clocks = <5>; + qcom,cpr-gcnt-time = <1>; + qcom,cpr-clamp-timer-interval = <1>; + qcom,cpr-apc-volt-step = <5000>; + + qcom,vsens-corner-map = <1 2 2>; + vdd-vsens-corner-supply = <&vsens_apc0_corner>; + vdd-vsens-voltage-supply = <&vsens_apc0_voltage>; + + rpm-apc-supply = <&rpm_apc_vreg>; + qcom,rpm-apc-corner-map = <4 4 5 5 7 7 7 7 7 7 7 7>; + + qcom,cpr-fuse-row = <138 1>; + qcom,cpr-fuse-bp-cpr-disable = <36>; + qcom,cpr-fuse-bp-scheme = <37>; + qcom,cpr-fuse-target-quot = <24 12 0>; + qcom,cpr-fuse-target-quot-size = <12 12 12>; + qcom,cpr-fuse-ro-sel = <54 38 41>; + qcom,cpr-fuse-revision = <140 26 2 0>; + qcom,cpr-fuse-redun-sel = <138 57 1 1 1>; + qcom,cpr-fuse-redun-row = <139 1>; + qcom,cpr-fuse-redun-target-quot = <24 12 0>; + qcom,cpr-fuse-redun-ro-sel = <46 36 39>; + qcom,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>; + qcom,cpr-cond-min-voltage = <1140000>; + qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>; + qcom,cpr-uplift-voltage = <50000>; + qcom,cpr-uplift-quotient = <0 0 120>; + qcom,cpr-uplift-max-volt = <1350000>; + qcom,cpr-uplift-speed-bin = <1>; + qcom,speed-bin-fuse-sel = <22 0 3 0>; + qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>; + qcom,cpr-corner-frequency-map = + <1 300000000>, + <2 384000000>, + <3 600000000>, + <4 787200000>, + <5 998400000>, + <6 1094400000>, + <7 1190400000>, + <8 1305600000>, + <9 1344000000>, + <10 1401600000>, + <11 1497600000>, + <12 1593600000>; + qcom,pvs-version-fuse-sel = <22 4 2 0>; + qcom,cpr-speed-bin-max-corners = + <0 1 2 4 7>, + <1 1 2 4 12>, + <2 1 2 4 10>, + <5 1 2 4 14>; + qcom,cpr-fuse-target-quot-scale = + <0 1>, + <0 1>, + <0 1>; + qcom,cpr-quot-adjust-scaling-factor-max = <0 650 650>; + qcom,cpr-fuse-quot-offset = + <138 53 5 0>, + <138 53 5 0>, + <138 48 5 0>, + <138 58 5 0>; + qcom,cpr-fuse-redun-quot-offset = + <200 53 5 0>, + <200 53 5 0>, + <200 48 5 0>, + <200 58 5 0>; + qcom,cpr-fuse-init-voltage = + <27 36 6 0>, + <27 18 6 0>, + <27 0 6 0>; + qcom,cpr-fuse-redun-init-voltage = + <140 36 6 0>, + <140 18 6 0>, + <140 0 6 0>; + qcom,cpr-init-voltage-ref = <1050000 1150000 1280000>; + qcom,cpr-init-voltage-step = <10000>; + qcom,cpr-voltage-ceiling-override = + <1 1 1050000 1050000 1150000 1150000 1280000 + 1280000 1280000 1280000 1280000 1280000 + 1280000 1280000>; + qcom,cpr-voltage-floor-override = + <1 1 1050000 1050000 1050000 1050000 1060000 + 1070000 1080000 1090000 1100000 1100000 + 1100000 1100000>; + qcom,cpr-scaled-init-voltage-as-ceiling; + + qcom,cpr-fuse-version-map = + <0xffffffff 0xffffffff 2 4 4 4>, + <0xffffffff 0xffffffff 2 6 6 6>, + <0xffffffff 0xffffffff 3 4 4 4>; + qcom,cpr-quotient-adjustment = + <0 0 (-210)>, + <0 0 (-60)>, + <0 0 (-94)>; + qcom,cpr-quot-offset-adjustment = + <0 0 (-5)>; + qcom,cpr-init-voltage-adjustment = + <0 0 (-100000)>, + <0 0 (-100000)>, + <0 0 (-45000)>; + qcom,cpr-fuse-min-quot-diff = <0 0 40>; + qcom,cpr-min-quot-diff-adjustment = + <0 0 0>, + <0 0 72>, + <0 0 104>; + qcom,cpr-floor-to-ceiling-max-range = + <(-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1)>, + <(-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1) (-1)>, + <(-1) (-1) (-1) (-1) (-1) (-1) (-1) 50000 50000 50000 50000 50000>; + qcom,cpr-virtual-corner-init-voltage-adjustment = + <0 0 0 (-10000) 0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0 0 0 0 (-20000)>, + <0 0 0 0 0 0 0 0 0 0 0 (-30000)>; + qcom,cpr-virtual-corner-quotient-adjustment = + <0 0 0 100 0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0 0 0 0 (-300)>, + <0 0 0 (-60) 0 0 0 0 0 0 0 0>; + qcom,cpr-cpus = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment = + /* 1st fuse version tuple matched */ + <0 0 0 (-10000) (-10000) (-10000) (-15000) (-15000) (-20000) 0 (-20000) (-30000) >, /* 0 CPUs online */ + <0 0 0 (-10000) (-10000) (-10000) (-15000) (-15000) (-20000) 0 (-20000) (-30000) >, /* 1 CPUs online */ + <0 0 0 (-5000) (-5000) (-5000) (-5000) (-5000) (-10000) 0 (-10000) (-10000) >, /* 2 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 3 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 4 CPUs online */ + /* 2nd fuse version tuple matched */ + <0 0 0 (-10000) (-10000) (-10000) (-15000) (-15000) (-20000) 0 (-20000) (-30000) >, /* 0 CPUs online */ + <0 0 0 (-10000) (-10000) (-10000) (-15000) (-15000) (-20000) 0 (-20000) (-30000) >, /* 1 CPUs online */ + <0 0 0 (-5000) (-5000) (-5000) (-5000) (-5000) (-10000) 0 (-10000) (-10000) >, /* 2 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 3 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 4 CPUs online */ + /* 3rd fuse version tuple matched */ + <0 0 0 (-10000) (-10000) (-10000) (-15000) (-15000) (-20000) 0 (-20000) (-30000) >, /* 0 CPUs online */ + <0 0 0 (-10000) (-10000) (-10000) (-15000) (-15000) (-20000) 0 (-20000) (-30000) >, /* 1 CPUs online */ + <0 0 0 (-5000) (-5000) (-5000) (-5000) (-5000) (-10000) 0 (-10000) (-10000) >, /* 2 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 3 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>; /* 4 CPUs online */ + qcom,cpr-online-cpu-virtual-corner-quotient-adjustment = + /* 1st fuse version tuple matched */ + <0 0 0 (-6) (-6) (-6) (-9) (-9) (-12) 0 (-12) (-18)>, /* 0 CPUs online */ + <0 0 0 (-6) (-6) (-6) (-9) (-9) (-12) 0 (-12) (-18)>, /* 1 CPUs online */ + <0 0 0 (-3) (-3) (-3) (-3) (-3) (-6) 0 (-6) (-6)>, /* 2 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 3 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 4 CPUs online */ + /* 2nd fuse version tuple matched */ + <0 0 0 (-6) (-6) (-6) (-9) (-9) (-12) 0 (-12) (-18)>, /* 0 CPUs online */ + <0 0 0 (-6) (-6) (-6) (-9) (-9) (-12) 0 (-12) (-18)>, /* 1 CPUs online */ + <0 0 0 (-3) (-3) (-3) (-3) (-3) (-6) 0 (-6) (-6)>, /* 2 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 3 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 4 CPUs online */ + /* 3rd fuse version tuple matched */ + <0 0 0 (-21) (-21) (-21) (-32) (-32) (-42) 0 (-42) (-63)>, /* 0 CPUs online */ + <0 0 0 (-21) (-21) (-21) (-32) (-32) (-42) 0 (-42) (-63)>, /* 1 CPUs online */ + <0 0 0 (-11) (-11) (-11) (-11) (-11) (-21) 0 (-21) (-21)>, /* 2 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>, /* 3 CPUs online */ + <0 0 0 0 0 0 0 0 0 0 0 0>; /* 4 CPUs online */ + qcom,cpr-allowed = + <0>, + <1>, + <1>; + + qcom,fuse-remap-base-row = <1000>; + qcom,fuse-remap-source = + <140 7 3 0>, + <138 45 5 0>; + qcom,cpr-fuse-quot-offset-scale = <5 5 5>; + + qcom,cpr-aging-sensor-id = <17, 18>; + qcom,cpr-aging-ref-corner = <4>; + qcom,cpr-aging-ref-voltage = <1050000>; + qcom,cpr-max-aging-margin = <15000>; + qcom,cpr-de-aging-allowed = + <0>, + <0>, + <1>; + qcom,cpr-non-collapsible-sensors= <7 12 17 22>; + qcom,cpr-aging-ro-scaling-factor = <3500>; + qcom,cpr-ro-scaling-factor = <0 2500 2500 2500 0 0 0 0>; + qcom,cpr-aging-derate = <1000 1000 1250>; + qcom,cpr-fuse-aging-init-quot-diff = + <101 0 8 0>, + <101 8 8 0>; + + qcom,cpr-thermal-sensor-id = <9>; + qcom,cpr-disable-temp-threshold = <5>; + qcom,cpr-enable-temp-threshold = <10>; + }; diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt index 5bf560ee1df9b3515f83807048aae780d22194d5..846bd22e5fcb1c453aaf05879402c96837bef8d9 100644 --- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt @@ -216,6 +216,15 @@ Platform independent properties: as the corresponding addresses are specified in the qcom,cpr-panic-reg-addr-list property. +- qcom,cpr-reset-step-quot-loop-en + Usage: optional; only meaningful for CPR4 and CPRh controllers + Value type: + Definition: Boolean value which indicates that the CPR controller should + be configured to reset step_quot on each loop_en = 0 + transition. This configuration allows the CPR controller to + first use the default step_quot and then later switch to the + run-time calibrated step_quot. + - qcom,saw-avs-ctrl Usage: required if "saw" registers are specified by reg and reg-names properties diff --git a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt index 29bb2d32bf91bade61c69b1c8eddfdbdf75c51ce..05792b02fa6e51c4906c723dec02578b2963d951 100644 --- a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt @@ -165,7 +165,7 @@ APSS specific properties: and Turbo. - qcom,cpr-fuse-combos - Usage: required + Usage: optional Value type: Definition: Specifies the number of fuse combinations being supported by the device. This value is utilized by several other @@ -178,6 +178,11 @@ APSS specific properties: The last 8 fuse combos correspond to speed bin fuse value 7 along with CPR revision fuse values 0 to 7. + This property must be specified unless qcom,cpr-fuse-combo-map + is present. In that case, qcom,cpr-fuse-combos is implicitly + assumed to have a value equal to the number of tuple lists (rows) + found in the qcom,cpr-fuse-combo-map property. + - qcom,cpr-speed-bins Usage: optional Value type: @@ -368,6 +373,27 @@ APSS specific properties: speed bins 1-to-1 or exactly 1 list which is used regardless of the speed bin found on a given chip. +- qcom,cpr-fuse-combo-map + Usage: optional + Value type: + Definition: A grouping of integer tuple lists where each tuple list (row) + defines a mapping from combinations of fuse parameter ranges + to fuse combo ID (i.e., map row index). Each tuple defines the + beginning and ending fuse parameter value that matches. The + number of tuples in each row is equal to the number of selection + fuse parameters used in fuse combo logic. For MSM8953, the fuse + parameters are "speed-bin", "cpr fuse revision", and "foundry id". + The tuples in each row correspond to the fuses in order: + "speed-bin", "cpr fuse revision" and "foundry id". An example entry + for speed-bin '3', cpr fuse revisions >= '2', and foundry '2' is + as shown below: + <3 3>, <2 7>, <2 2> + + The number of rows in the property is arbitrary but used to size + other properties. qcom,cpr-fuse-combos must be set to the number + of rows specified in this property. For msm8953, the maximum number + of rows for this property is 512 (8 * 8 * 8). + ======= Example ======= @@ -414,6 +440,8 @@ apc_cpr: cpr4-ctrl@b018000 { "APCS_ALIAS0_APM_CTLER_STATUS", "APCS0_CPR_CORE_ADJ_MODE_REG"; + qcom,cpr-aging-ref-voltage = <990000>; /* Turbo corner */ + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <1>; @@ -517,6 +545,14 @@ apc_cpr: cpr4-ctrl@b018000 { <(-20000) (-15000) (-10000) 0>; qcom,allow-boost = <1>; + + qcom,cpr-aging-max-voltage-adjustment = <15000>; + qcom,cpr-aging-ref-corner = <6>; /* Turbo corner */ + qcom,cpr-aging-ro-scaling-factor = <2800>; + qcom,cpr-aging-derate = + <1000 1000 1000 1000 1000 + 1000 1000 1000>; + qcom,allow-aging-voltage-adjustment = <1>; }; }; }; diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt index 8efa85d982fe20e01f9636b7c4758c29dc2ffc8c..0c6a9f2faba63feeb0814d1d01a5a976aa629276 100644 --- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt @@ -213,6 +213,18 @@ KBSS specific properties: target quotient adjustment due to an ACD up recommendation. Valid values are 0 through 3. +- qcom,cpr-acd-notwait-for-cl-settled + Usage: optional; meaningful only if qcom,cpr-acd-avg-enable is specified. + Value type: + Definition: Boolean flag which indicates ACD down recommendations do not + need to wait for CPR closed-loop to settle. + +- qcom,cpr-acd-avg-fast-update + Usage: optional; meaningful only if qcom,cpr-acd-avg-enable is specified. + Value type: + Definition: Boolean flag which indicates CPR should issue immediate + voltage updates following ACD requests. + - qcom,cpr-acd-avg-enable Usage: optional Value type: diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 5d0499c34b937eb3eae19354fc90b174c0b25a75..803df6fbeb6aa5b2ccf91bae6ed4323d116889a1 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -59,6 +59,8 @@ Optional properties: - qcom,poll-cfg-gdscr: Poll the CFG register of the GDSC to determine if the GDSC is enabled/disabled. This flag should not be set in conjunction with "hw-ctrl-addr". + - qcom,toggle-sw-collapse-in-disable: If set, SW_COLLAPSE bit is toggled + in disable call. Example: gdsc_oxili_gx: qcom,gdsc@fd8c4024 { diff --git a/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt b/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt index 55154579840a83799cc60d3c58fa538ab5dd620e..f4f549a171419694225c17c49cf21687eb75f191 100644 --- a/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt @@ -159,6 +159,21 @@ Optional properties: not specified, then "qcom,override-cornerX-reg-config" must contain a single register configuration sequence list which is then applied unconditionally. This property can only be specified if qcom,cornerX-reg-config property is already defined. +- qcom,override-acc-range-fuse-list: Array of tuples define the selection parameters used for selecting the override + mem-acc configuration. The fused values for these selection parameters are used by the + qcom,override-fuse-range-map to identify the correct set of override properties. + Each tuple contains 4 elements as defined below: + [0] => the fuse row number of the selector + [1] => LSB bit position of the bits + [2] => number of bits + [3] => fuse reading method, 0 for direct reading or 1 for SCM reading +- qcom,override-fuse-range-map: Array of tuples where each tuple specifies the allowed range for all the selection parameters + defined in qcom,override-acc-range-fuse-list. The fused values of these selection parameters + are compared against their allowed range in each tuple starting from 0th tuple and use the + first matched tuple index to select the right tuples from the other override properties. + Either qcom,override-fuse-range-map or qcom,override-fuse-version-map is used to select + the override configuration. The qcom,override-fuse-range-map is used if both the + properties are specified. mem_acc_vreg_corner: regulator@fd4aa044 { compatible = "qcom,mem-acc-regulator"; @@ -184,6 +199,13 @@ mem_acc_vreg_corner: regulator@fd4aa044 { qcom,override-fuse-version-map = <0>, <2>, <(-1)>; + qcom,override-acc-range-fuse-list = + <37 40 3 0>, + <36 30 8 0>; + qcom,override-fuse-range-map = + <0 0>, < 0 0>, <49 63>, + <1 1>, < 0 0>, <50 63>, + <0 1>, < 95 255>, < 0 63>; qcom,override-corner-acc-map = <0 0 1>, <0 1 2>, <0 1 1>; diff --git a/Documentation/devicetree/bindings/regulator/qcom,refgen.txt b/Documentation/devicetree/bindings/regulator/qcom,refgen.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c54e29f9652e43751821625dadeae4de70f2564 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/qcom,refgen.txt @@ -0,0 +1,38 @@ +Qualcomm Technologies, Inc. REFGEN Regulator + +Some Qualcomm Technologies, Inc. SoCs utilize reference bias generators for +various internal PHY blocks. These are called REFGENs. + +Supported properties: +- compatible + Usage: required + Value type: + Definition: Must be "qcom,refgen-regulator". + +- reg + Usage: required + Value type: + Definition: Address and size of the REFGEN registers. + +- regulator-name + Usage: required + Value type: + Definition: Specifies the name for this REFGEN regulator. + +- regulator-enable-ramp-delay + Usage: optional + Value type: + Definition: REFGEN enable time in microseconds. + +- parent-supply + Usage: optional + Value type: + Definition: phandle to the parent supply/regulator node if one exists. + +Example: + +refgen-regulator@ff1000 { + compatible = "qcom,refgen-regulator"; + reg = <0xff1000 0x60>; + regulator-name = "refgen"; +}; diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt index c9cfc889fababafc3ceaa70fef6b6dedda52e4d3..a5e607de69d8d258b53b2fa49c88f98cf0204339 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt @@ -82,15 +82,17 @@ LAB subnode required properties: - qcom,qpnp-lab-init-lcd-voltage: The default output voltage when LAB regulator is configured in lcd mode. - qcom,qpnp-lab-ps-threshold: The threshold in mA of Pulse Skip Mode for - LAB regulator. Supported values are 20, 30, - 40 and 50. + LAB regulator. Supported values for + PMI8994/6 are 20, 30, 40 and 50. + Supported values for PMI8998/PM660A are + 50, 60, 70 and 80. - interrupts: Specify the interrupts as per the interrupt encoding. - Currently "lab-vreg-ok" is required for - LCD mode in pmi8998. For AMOLED mode, - "lab-vreg-ok" is required only when SWIRE - control is enabled and skipping 2nd SWIRE - pulse is required in pmi8952/8996. + Currently "lab-vreg-ok" is required and "lab-sc_err" + is optional for LCD mode in pmi8998. + For AMOLED mode, "lab-vreg-ok" is required + only when SWIRE control is enabled and skipping + 2nd SWIRE pulse is required in pmi8952/8996. - interrupt-names: Interrupt names to match up 1-to-1 with the interrupts specified in 'interrupts' property. @@ -151,6 +153,10 @@ LAB subnode optional properties: any value in the allowed limit. - qcom,notify-lab-vreg-ok-sts: A boolean property which upon set will poll and notify the lab_vreg_ok status. +- qcom,qpnp-lab-sc-wait-time-ms: This property is used to specify the time + (in ms) to poll for the short circuit + detection. If not specified the default time + is 5 sec. Following properties are available only for PM660A: @@ -207,6 +213,14 @@ IBB subnode required properties: IBB subnode optional properties: +- interrupts: Specify the interrupts as per the interrupt + encoding. + Currently "ibb-sc-err" could be used for LCD mode + in pmi8998 to detect the short circuit fault. +- interrupt-names: Interrupt names to match up 1-to-1 with + the interrupts specified in 'interrupts' + property. + - qcom,qpnp-ibb-discharge-resistor: The discharge resistor in Kilo Ohms which controls the soft start time. Supported values are 300, 64, 32 and 16. diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt index 63da8ecbfa4c285dbeeceb69ad16e0ec2232dc76..9798ac60b4931f96d9ba76daab50541a7e05a7cd 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt @@ -26,12 +26,10 @@ First Level Node - LCDB module Value type: Definition: Base address of the LCDB SPMI peripheral. -- qcom,force-module-reenable - Usage: required if using SW mode for module enable - Value type: - Definition: This enables the workaround to force enable - the vph_pwr_2p5_ok signal required for - turning on the LCDB module. +- qcom,pmic-revid + Usage: required + Value type: + Definition: Phandle to the PMIC's revid node Touch-to-wake (TTW) properties: @@ -211,6 +209,12 @@ Properties below are specific to BOOST subnode only. Definition: Current limit (in mA) of the BOOST rail. Possible values are 200 to 1600mA in 200mA steps. +- qcom,bst-headroom-mv + Usage: optional + Value type: + Definition: Headroom of the boost (in mV). The minimum headroom is + 200mV and if not specified defaults to 200mV. + ======= Example ======= @@ -252,5 +256,6 @@ pm660l_lcdb: qpnp-lcdb@ec00 { qcom,bst-pd-strength = <1>; qcom,bst-ps = <1>; qcom,bst-ps-threshold-ma = <50>; + qcom,bst-headroom-mv = <200>; }; }; diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt index 38f599ba5321f2acc757417a5931975ce8e6d56c..55fde0d4feb6321295314745e07b3316af5c9f60 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt @@ -14,6 +14,11 @@ Required Node Structure Value type: Definition: should be "qcom,qpnp-oledb-regulator". +- qcom,pmic-revid + Usage: required + Value type: + Definition: Used to identify the PMIC subtype. + - reg Usage: required Value type: @@ -57,13 +62,6 @@ Required Node Structure rail. This property is applicable only if qcom,ext-pin-ctl property is specified and it is specific to PM660A. -- qcom,force-pd-control - Usage: optional - Value type: - Definition: Used to enable the pull down control forcibly via SPMI by - disabling the pull down configuration done by hardware - automatically through SWIRE pulses. - - qcom,pbs-client Usage: optional Value type: @@ -224,6 +222,7 @@ pm660a_oledb: qpnp-oledb@e000 { compatible = "qcom,qpnp-oledb-regulator"; #address-cells = <1>; #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; reg = <0xe000 0x100>; label = "oledb"; diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f40a0967404ce42369c099d3e65fec7854ee0fc --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt @@ -0,0 +1,328 @@ +Qualcomm Technologies, Inc. RPM Regulators + +rpm-regulator-smd is a regulator driver which supports regulators inside of +PMICs which are controlled by the RPM processor. Communication with the RPM +processor takes place over SMD. + +Required structure: +- RPM regulators must be described in two levels of devices nodes. The first + level describes the interface with the RPM. The second level describes + properties of one regulator framework interface (of potentially many) to + the regulator. + +[First Level Nodes] + +Required properties: +- compatible: Must be "qcom,rpm-smd-regulator-resource" +- qcom,resource-name: Resource name string for this regulator to be used in RPM + transactions. Length is 4 characters max. +- qcom,resource-id: Resource instance ID for this regulator to be used in RPM + transactions. +- qcom,regulator-type: Type of this regulator. Supported values are: + 0 = LDO + 1 = SMPS + 2 = VS + 3 = NCP + 4 = Buck or Boost (BoB) + +Optional properties: +- qcom,allow-atomic: Flag specifying if atomic access is allowed for this + regulator. Supported values are: + 0 or not present = mutex locks used + 1 = spinlocks used +- qcom,enable-time: Time in us to delay after enabling the regulator +- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load + which requires the regulator to be in high power mode. +- qcom,apps-only: Flag which indicates that the regulator only has + consumers on the application processor. If this flag + is specified, then voltage and current updates are + only sent to the RPM if the regulator is enabled. +- qcom,always-wait-for-ack: Flag which indicates that the application + processor must wait for an ACK or a NACK from the RPM + for every request sent for this regulator including + those which are for a strictly lower power state. + +[Second Level Nodes] + +Required properties: +- compatible: Must be "qcom,rpm-smd-regulator" +- regulator-name: A string used as a descriptive name for regulator outputs +- qcom,set: Specifies which sets that requests made with this + regulator interface should be sent to. Regulator + requests sent in the active set take effect immediately. + Requests sent in the sleep set take effect when the Apps + processor transitions into RPM assisted power collapse. + Supported values are: + 1 = Active set only + 2 = Sleep set only + 3 = Both active and sleep sets + + + +Optional properties: +- parent-supply: phandle to the parent supply/regulator node +- qcom,system-load: Load in uA present on regulator that is not + captured by any consumer request +- qcom,use-voltage-corner: Flag that signifies if regulator_set_voltage + calls should modify the corner parameter instead + of the voltage parameter. When used, voltages + specified inside of the regulator framework + represent corners that have been incremented by + 1. This value shift is necessary to work around + limitations in the regulator framework which + treat 0 uV as an error. +- qcom,use-voltage-floor-corner: Flag that signifies if regulator_set_voltage + calls should modify the floor corner parameter + instead of the voltage parameter. When used, + voltages specified inside of the regulator + framework represent corners that have been + incremented by 1. The properties + qcom,use-voltage-corner and + qcom,use-voltage-floor-corner are mutually + exclusive. Only one may be specified for a + given regulator. +- qcom,use-voltage-level: Flag that signifies if regulator_set_voltage + calls should modify the level parameter instead + of the voltage parameter. +- qcom,use-voltage-floor-level: Flag that signifies if regulator_set_voltage + calls should modify the floor level parameter + instead of the voltage parameter. + The properties qcom,use-voltage-level and + qcom,use-voltage-floor-level are mutually + exclusive. Only one may be specified for a + given regulator. +- qcom,use-pin-ctrl-voltage1: Flag which indicates that updates to voltage + should be sent to the pin control voltage 1 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,use-pin-ctrl-voltage2: Flag which indicates that updates to voltage + should be sent to the pin control voltage 2 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,use-pin-ctrl-voltage3: Flag which indicates that updates to voltage + should be sent to the pin control voltage 3 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,always-send-voltage: Flag which indicates that updates to the + voltage, voltage corner or voltage level set + point should always be sent immediately to the + RPM. If this flag is not specified, then + voltage set point updates are only sent if the + given regulator has also been enabled by a + Linux consumer. +- qcom,always-send-current: Flag which indicates that updates to the load + current should always be sent immediately to the + RPM. If this flag is not specified, then load + current updates are only sent if the given + regulator has also been enabled by a Linux + consumer. +- qcom,send-defaults: Boolean flag which indicates that the initial + parameter values should be sent to the RPM + before consumers make their own requests. If + this flag is not specified, then initial + parameters values will only be sent after some + consumer makes a request. +- qcom,enable-with-pin-ctrl: Double in which the first element corresponds to + the pin control enable parameter value to send + when all consumers have requested the regulator + to be disabled. The second element corresponds + to the pin control enable parameter value to + send when any consumer has requested the + regulator to be enabled. Each element supports + the same set of values as the + qcom,init-pin-ctrl-enable property listed below. + +The following properties specify initial values for parameters to be sent to the +RPM in regulator requests. +- qcom,init-enable: 0 = regulator disabled + 1 = regulator enabled +- qcom,init-voltage: Voltage in uV +- qcom,init-current: Current in mA +- qcom,init-ldo-mode: Operating mode to be used with LDO regulators + Supported values are: + 0 = mode determined by current requests + 1 = force HPM (NPM) +- qcom,init-smps-mode: Operating mode to be used with SMPS regulators + Supported values are: + 0 = auto; hardware determines mode + 1 = mode determined by current requests + 2 = force HPM (PWM) +- qcom,init-bob-mode: Operating mode to be used with BoB regulators + Supported values are: + 0 = pass; use priority order + 1 = force PFM + 2 = auto; hardware determines mode + 3 = force PWM +- qcom,init-pin-ctrl-enable: Bit mask specifying which hardware pins should be + used to enable the regulator, if any; supported + bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal +- qcom,init-pin-ctrl-mode: Bit mask specifying which hardware pins should be + used to force the regulator into high power + mode, if any. Supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state +- qcom,init-pin-ctrl-voltage1: Minimum voltage in micro-volts to use while pin + control 1 is enabled. This property only + applies to BoB type regulators. +- qcom,init-pin-ctrl-voltage2: Minimum voltage in micro-volts to use while pin + control 2 is enabled. This property only + applies to BoB type regulators. +- qcom,init-pin-ctrl-voltage3: Minimum voltage in micro-volts to use while pin + control 3 is enabled. This property only + applies to BoB type regulators. +- qcom,init-frequency: Switching frequency divisor for SMPS regulators. + Supported values are n = 0 to 31 where + freq = 19.2 MHz / (n + 1). +- qcom,init-head-room: Voltage head room in mV required for the + regulator. This head room value should be used + in situations where the device connected to the + output of the regulator has low noise tolerance. + Note that the RPM independently enforces a + safety head room value for subregulated LDOs + which is sufficient to account for LDO drop-out + voltage. +- qcom,init-quiet-mode: Specify that quiet mode is needed for an SMPS + regulator in order to have lower output noise. + Supported values are: + 0 = No quiet mode + 1 = Quiet mode + 2 = Super quiet mode +- qcom,init-freq-reason: Consumer requiring specified frequency for an + SMPS regulator. Supported values are: + 0 = None + 1 = Bluetooth + 2 = GPS + 4 = WLAN + 8 = WAN +- qcom,init-voltage-corner: Performance corner to use in order to determine + voltage set point. This value corresponds to + the actual value that will be sent and is not + incremented by 1 like the values used inside of + the regulator framework. The meaning of corner + values is set by the RPM. It is possible that + different regulators on a given platform or + similar regulators on different platforms will + utilize different corner values. These are + corner values supported on MSM8974 for PMIC + PM8841 SMPS 2 (VDD_Dig); nominal voltages for + these corners are also shown: + 0 = None (don't care) + 1 = Retention (0.5000 V) + 2 = SVS Krait (0.7250 V) + 3 = SVS SOC (0.8125 V) + 4 = Normal (0.9000 V) + 5 = Turbo (0.9875 V) + 6 = Super Turbo (1.0500 V) +- qcom,init-disallow-bypass: Specify that bypass mode should not be used for a + given LDO regulator. When in bypass mode, an + LDO performs no regulation and acts as a simple + switch. The RPM can utilize this mode for an + LDO that is subregulated from an SMPS when it is + possible to reduce the SMPS voltage to the + desired LDO output level. Bypass mode may be + disallowed if lower LDO output noise is + required. Supported values are: + 0 = Allow RPM to utilize LDO bypass mode + if possible + 1 = Disallow LDO bypass mode +- qcom,init-voltage-floor-corner: Minimum performance corner to use if any + processor in the system is awake. This property + supports the same values as + qcom,init-voltage-corner. +- qcom,init-voltage-level: Performance level to use in order to determine + voltage set point. The meaning of level + values is set by the RPM. It is possible that + different regulators on a given platform or + similar regulators on different platforms will + utilize different level values. These are + level values supported on MSM8952 for PMIC + PM8952 SMPS 2 (VDD_Dig); nominal voltages for + these level are also shown: + 16 = Retention (0.5000 V) + 128 = SVS (1.0500 V) + 192 = SVS+ (1.1550 V) + 256 = Normal (1.2250 V) + 320 = Normal+ (1.2875 V) + 384 = Turbo (1.3500 V) +- qcom,init-voltage-floor-level: Minimum performance level to use if any + processor in the system is awake. This property + supports the same values as + qcom,init-voltage-level. + +All properties specified within the core regulator framework can also be used in +second level nodes. These bindings can be found in: +Documentation/devicetree/bindings/regulator/regulator.txt. + +Examples: + +rpm-regulator-smpb1 { + qcom,resource-name = "smpb"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + compatible = "qcom,rpm-smd-regulator-resource"; + status = "disabled"; + + pm8841_s1: regulator-s1 { + regulator-name = "8841_s1"; + qcom,set = <3>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1150000>; + qcom,init-voltage = <1150000>; + compatible = "qcom,rpm-smd-regulator"; + }; + pm8841_s1_ao: regulator-s1-ao { + regulator-name = "8841_s1_ao"; + qcom,set = <1>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1150000>; + compatible = "qcom,rpm-smd-regulator"; + }; + pm8841_s1_corner: regulator-s1-corner { + regulator-name = "8841_s1_corner"; + qcom,set = <3>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <6>; + qcom,init-voltage-corner = <3>; + qcom,use-voltage-corner; + compatible = "qcom,rpm-smd-regulator"; + }; +}; + +rpm-regulator-ldoa2 { + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + compatible = "qcom,rpm-smd-regulator-resource"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8941_l2"; + qcom,set = <3>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + }; + regulator-l2-pin-ctrl { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8941_l2_pin_ctrl"; + qcom,set = <3>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + qcom,enable-with-pin-ctrl = <0 1>; + }; +}; diff --git a/Documentation/devicetree/bindings/regulator/rpmh-regulator.txt b/Documentation/devicetree/bindings/regulator/rpmh-regulator.txt index 9deb7d41410079a22a0d755356501cfbdb5384f8..b7607587cdf9e5d908d597dd1b102f5798eac607 100644 --- a/Documentation/devicetree/bindings/regulator/rpmh-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/rpmh-regulator.txt @@ -1,12 +1,13 @@ Qualcomm Technologies, Inc. RPMh Regulators -rpmh-regulator devices support PMIC regulator management via the VRM and ARC -RPMh accelerators. The APPS processor communicates with these hardware blocks -via an RSC using command packets. The VRM allows changing four parameters for -a given regulator: enable state, output voltage, operating mode, and minimum -headroom voltage. The ARC allows changing only a single parameter for a given -regulator: its operating level. This operating level is fed into CPR which then -decides upon a final explicit voltage for the regulator. +rpmh-regulator devices support PMIC regulator management via the VRM, ARC and +XOB RPMh accelerators. The APPS processor communicates with these hardware +blocks via an RSC using command packets. The VRM allows changing four +parameters for a given regulator: enable state, output voltage, operating mode, +and minimum headroom voltage. The ARC allows changing only a single parameter +for a given regulator: its operating level. This operating level is fed into +CPR which then decides upon a final explicit voltage for the regulator. The XOB +allows changing only a single parameter for a given regulator: its enable state. ======================= Required Node Structure @@ -24,9 +25,10 @@ First Level Nodes - RPMh Interface - compatible Usage: required Value type: - Definition: Must be "qcom,rpmh-vrm-regulator" or - "qcom,rpmh-arc-regulator" depending upon the hardware type, - VRM or ARC, of the RPMh managed regulator resource. + Definition: Must be "qcom,rpmh-vrm-regulator", "qcom,rpmh-arc-regulator" + or "qcom,rpmh-xob-regulator" depending upon the hardware + type, VRM, ARC or XOB, of the RPMh managed regulator + resource. - mboxes Usage: required @@ -42,6 +44,16 @@ First Level Nodes - RPMh Interface a particular PMIC found in the system. This name must match to one that is defined by the bootloader. +- qcom,regulator-type + Usage: required if qcom,supported-modes is specified or if + qcom,init-mode is specified in any subnodes + Value type: + Definition: The physical type of the regulator including the PMIC + family. This is used for mode control. Supported values: + "pmic4-ldo", "pmic4-hfsmps", "pmic4-ftsmps", "pmic4-bob", + "pmic5-ldo", "pmic5-hfsmps", "pmic5-ftsmps", and + "pmic5-bob". + - qcom,use-awake-state Usage: optional Value type: @@ -70,7 +82,7 @@ First Level Nodes - RPMh Interface Value type: Definition: A list of integers specifying the PMIC regulator modes supported by this regulator. Supported values are - RPMH_REGULATOR_MODE_* (i.e. 0 to 7). Elements must be + RPMH_REGULATOR_MODE_* (i.e. 0 to 4). Elements must be specified in order from lowest to highest. - qcom,mode-threshold-currents @@ -116,8 +128,8 @@ Second Level Nodes - Regulator Interfaces - regulator-enable-ramp-delay Usage: optional Value type: - Definition: For VRM resources, the time in microseconds to delay after - enabling a regulator. + Definition: For VRM and XOB resources, the time in microseconds to delay + after enabling a regulator. - qcom,set Usage: required @@ -130,7 +142,7 @@ Second Level Nodes - Regulator Interfaces one of RPMH_REGULATOR_SET_* (i.e. 1, 2, or 3). - qcom,init-enable - Usage: optional; VRM regulators only + Usage: optional; VRM and XOB regulators only Value type: Definition: Specifies the initial enable state to request for a VRM regulator. Supported values are 0 (regulator disabled) and @@ -146,7 +158,7 @@ Second Level Nodes - Regulator Interfaces Usage: optional; VRM regulators only Value type: Definition: Specifies the initial mode to request for a VRM regulator. - Supported values are RPMH_REGULATOR_MODE_* (i.e. 0 to 7). + Supported values are RPMH_REGULATOR_MODE_* (i.e. 0 to 4). - qcom,init-headroom-voltage Usage: optional; VRM regulators only @@ -210,9 +222,10 @@ rpmh-regulator-smpa2 { compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "smpa2"; + qcom,regulator-type = "pmic4-smps"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 2000000>; pm8998_s2: regulator-s2 { regulator-name = "pm8998_s2"; @@ -220,7 +233,7 @@ rpmh-regulator-smpa2 { regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1200000>; regulator-enable-ramp-delay = <200>; - qcom,init-mode = ; + qcom,init-mode = ; qcom,init-voltage = <1150000>; }; }; @@ -230,9 +243,10 @@ rpmh-regulator-ldoa3-disp { mboxes = <&disp_rsc 0>; qcom,use-awake-state; qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; qcom,always-wait-for-ack; pm8998_l3_disp_ao: regulator-l3-ao { @@ -248,7 +262,7 @@ rpmh-regulator-ldoa3-disp { qcom,set = ; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1200000>; - qcom,init-mode = ; + qcom,init-mode = ; qcom,init-voltage = <1000000>; qcom,init-enable = <0>; }; @@ -258,6 +272,7 @@ rpmh-regulator-ldoa4 { compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa4"; + qcom,regulator-type = "pmic4-ldo"; pm8998_l4-parent-supply = <&pm8998_s2>; pm8998_l4: regulator-l4 { regulator-name = "pm8998_l4"; @@ -267,3 +282,15 @@ rpmh-regulator-ldoa4 { qcom,init-voltage = <1000000>; }; }; + +rpmh-regulator-ldoc1 { + compatible = "qcom,rpmh-xob-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc1"; + pm855l_l1: regulator-pm855l-l1 { + regulator-name = "pm855l_l1"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; +}; diff --git a/Documentation/devicetree/bindings/regulator/spm-regulator.txt b/Documentation/devicetree/bindings/regulator/spm-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3241577a42935719c19d2e2778cc5e5995ec403 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/spm-regulator.txt @@ -0,0 +1,61 @@ +Qualcomm Technologies Inc. SPM Regulators + +spm-regulator is a regulator device which supports PMIC processor supply +regulators via the SPM module. + +Required properties: +- compatible: Must be "qcom,spm-regulator" +- reg: Specifies the SPMI address and size for this regulator device +- regulator-name: A string used as a descriptive name for the regulator + +Required structure: +- A qcom,spm-regulator node must be a child of an SPMI node that has specified + the spmi-slave-container property + +Optional properties: +- qcom,mode: A string which specifies the mode to use for the regulator. + Supported values are "pwm" and "auto". PWM mode is more + robust, but draws more current than auto mode. If this + property is not specified, then the regulator will remain + in whatever mode hardware or bootloaders set it to. +- qcom,cpu-num: Specifies which CPU this regulator powers. This property is + not need when the SPM regulator is shared between all CPUs. +- qcom,bypass-spm: Boolean flag which indicates that voltage control should not + be managed by an SPM. Instead, the voltage should be + controlled via SPMI. +- qcom,max-voltage-step: Maximum single voltage step size in microvolts. +- qcom,recal-mask: Bit mask of the APSS clusters to recalibrate after each + voltage change. Bit 0 corresponds to the first cluster, + bit 1 corresponds to the second cluster, and so on. + +Optional structure: +- A child node may be specified within a qcom,spm-regulator node which defines + an additional regulator which controls the AVS minimum and maximum + voltage limits. +- The AVS child node must contain these properties defined in regulator.txt: + regulator-name, regulator-min-microvolt, regulator-max-microvolt. + +All properties specified within the core regulator framework can also be used. +These bindings can be found in regulator.txt. + +Example: + qcom,spmi@fc4c0000 { + + qcom,pm8226@1 { + spmi-slave-container; + + spm-regulator@1700 { + compatible = "qcom,spm-regulator"; + regulator-name = "8226_s2"; + reg = <0x1700 0x100>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1275000>; + + avs-limit-regulator { + regulator-name = "8226_s2_avs_limit"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1275000>; + } + }; + }; + }; diff --git a/Documentation/devicetree/bindings/scheduler/energy.txt b/Documentation/devicetree/bindings/scheduler/energy.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c7121c3a74a4aebc688303f4705b5bc6731960b --- /dev/null +++ b/Documentation/devicetree/bindings/scheduler/energy.txt @@ -0,0 +1,13 @@ +* Scheduler Energy Driver + +Scheduler Energy Driver updates capacities in the scheduler group energy array. +The array contains power cost at each CPU operating points so energy aware +scheduler (EAS) can utilize it for task placement. + +Required properties: +- compatible: Must be "sched-energy" + +Example: + energy-costs { + compatible = "sched-energy"; + } diff --git a/Documentation/devicetree/bindings/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/serial/msm_serial_hs.txt new file mode 100644 index 0000000000000000000000000000000000000000..031be45f81b8c2427a354b26ed0857ddfc79394a --- /dev/null +++ b/Documentation/devicetree/bindings/serial/msm_serial_hs.txt @@ -0,0 +1,121 @@ +* Qualcomm MSM HSUART + +Required properties: +- compatible : + - "qcom,msm-hsuart-v14" to be used for UARTDM Core v1.4 +- reg : offset and length of the register set for both the device, + uart core and bam core +- reg-names : + - "core_mem" to be used as name of the uart core + - "bam_mem" to be used as name of the bam core +- interrupts : interrupts for both the device,uart core and bam core +- interrupt-names : + - "core_irq" to be used as uart irq + - "bam irq" to be used as bam irq +- #interrupt-cells: Specifies the number of cells needed to encode an interrupt + source. The type shall be a and the value shall be 1 +- #address-cells: Specifies the number of cells needed to encode an address. + The type shall be and the value shall be 0 +- interrupt-parent = It is needed for interrupt mapping +- bam-tx-ep-pipe-index : BAM TX Endpoint Pipe Index for HSUART +- bam-rx-ep-pipe-index : BAM RX Endpoint Pipe Index for HSUART + +BLSP has a static pipe allocation and assumes a pair-pipe for each uart core. +Pipes [2*i : 2*i+1] are allocated for UART cores where i = [0 : 5]. +Hence, Minimum and Maximum permitted value of endpoint pipe index to be used +with uart core is 0 and 11 respectively. + +There is one HSUART block used in MSM devices, +"qcom,msm-hsuart-v14". The msm-serial-hs driver is +able to handle this, and matches against the "qcom,msm-hsuart-v14" +as the compatibility. + +The registers for the "qcom,msm-hsuart-v14" device need to specify both +register blocks - uart core and bam core. + +Example: + + uart7: uart@f995d000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0xf995d000 0x1000>, + <0xf9944000 0x5000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq"; + #address-cells = <0>; + interrupt-parent = <&uart7>; + interrupts = <0 1>; + #interrupt-cells = <1>; + interrupt-map = <0 &intc 0 113 0 + 1 &intc 0 239 0> + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + }; + +Optional properties: +- qcom,-gpio : handle to the GPIO node, see "gpios property" in +Documentation/devicetree/bindings/gpio/gpio.txt. +"gpio-name" can be "tx", "rx", "cts" and "rfr" based on number of UART GPIOs +need to configured. +Gpio's are optional if it is required to be not configured by UART driver or +case where there is nothing connected and we want to use internal loopback mode +for uart. +- qcom, wakeup_irq : UART RX GPIO IRQ line to be configured as wakeup source. +- qcom,inject-rx-on-wakeup : inject_rx_on_wakeup enables feature where on +receiving interrupt with UART RX GPIO IRQ line (i.e. above wakeup_irq property), +HSUART driver injects provided character with property rx_to_inject. +- qcom, rx-char-to-inject : The character to be inserted on wakeup. +- qcom, no-suspend-delay : This decides system to go to suspend immediately +or not + +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for +below optional properties: + - qcom,msm_bus,name + - qcom,msm_bus,num_cases + - qcom,msm_bus,active_only + - qcom,msm_bus,num_paths + - qcom,msm_bus,vectors + +Aliases : +An alias may be optionally used to bind the UART device to a TTY device +(ttyHS) with a given alias number. Aliases are of the form +uart where is an integer representing the alias number to use. +On systems with multiple UART devices present, an alias may optionally be +defined for such devices. The alias value should be from 0 to 255. + +Example: + + aliases { + uart4 = &uart7; // This device will be enumerated as ttyHS4 + }; + + uart7: uart@f995d000 { + compatible = "qcom,msm-hsuart-v14" + reg = <0x19c40000 0x1000">, + <0xf9944000 0x5000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&uart7>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 113 0 + 1 &intc 0 239 0 + 2 &msmgpio 42 0>; + qcom,tx-gpio = <&msmgpio 41 0x00>; + qcom,rx-gpio = <&msmgpio 42 0x00>; + qcom,cts-gpio = <&msmgpio 43 0x00>; + qcom,rfr-gpio = <&msmgpio 44 0x00>; + qcom,inject-rx-on-wakeup = <1>; + qcom,rx-char-to-inject = <0xFD>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + + qcom,msm-bus,name = "uart7"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + }; diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt b/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt index 04b624b685b6c2a62db93ee0e55b410e4cfdee51..b616bf39ec1fc3c2b4d273686bc8295df0f39f34 100644 --- a/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt +++ b/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt @@ -15,10 +15,10 @@ Required properties: - pinctrl-names/pinctrl-0/1: The GPIOs assigned to this core. The names Should be "active" and "sleep" for the pin confuguration when core is active or when entering sleep state. +- qcom,wrapper-core: Wrapper QUPv3 core containing this UART controller. Optional properties: -- qcom,bus-mas: contains the bus master id needed to put in bus bandwidth votes - for inter-connect buses. +- qcom,wakeup-byte: Byte to be injected in the tty layer during wakeup isr. Example: qupv3_uart11: qcom,qup_uart@0xa88000 { @@ -33,5 +33,6 @@ qupv3_uart11: qcom,qup_uart@0xa88000 { pinctrl-0 = <&qup_1_uart_3_active>; pinctrl-1 = <&qup_1_uart_3_sleep>; interrupts = <0 355 0>; - qcom,bus-mas = ; + qcom,wrapper-core = <&qupv3_0>; + qcom,wakeup-byte = <0xFF>; }; diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt index 95cc85ae58ed261f38500dc1888b6d81931d8a02..7711b8b342079bd6a55d4d86426b9a64decdfcb2 100644 --- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt +++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt @@ -65,6 +65,17 @@ Optional property: and follow appropriate steps to ensure communication on the bus can be resumed after subsytem restart. By default slimbus driver register with ADSP subsystem. + - qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation. + +Optional subnodes: +qcom,iommu_slim_ctrl_cb : Child node representing the Slimbus controller + context bank. + +Subnode Required properties: +- compatible : Must be "qcom,slim-ctrl-cb"; +- iommus : A list of phandle and IOMMU specifier pairs that + describe the IOMMU master interfaces of the device. + Example: slim@fe12f000 { cell-index = <1>; @@ -78,4 +89,9 @@ Example: qcom,rxreg-access; qcom,apps-ch-pipes = <0x60000000>; qcom,ea-pc = <0x30>; + + iommu_slim_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1 0x0>; + }; }; diff --git a/Documentation/devicetree/bindings/soc/qcom/dcc.txt b/Documentation/devicetree/bindings/soc/qcom/dcc.txt index 8a9761c237c98b54fe944688c48d97829bbe0b70..5150459f958c0983b469ab80a2986da4a3311b34 100644 --- a/Documentation/devicetree/bindings/soc/qcom/dcc.txt +++ b/Documentation/devicetree/bindings/soc/qcom/dcc.txt @@ -35,6 +35,14 @@ Optional properties: "atb" : To send captured data over ATB to a trace sink "sram" : To save captured data in dcc internal SRAM. +- qcom,curr-link-list: int, To specify the link list to use for the default list. + +- qcom,link-list: The values to be programmed into the default link list. + The enum values for DCC operations is defined in dt-bindings/soc/qcom,dcc_v2.h + The following gives basic structure to be used for each operation: + + val is to be interpreted based on what operation is to be performed. + Example: dcc: dcc@4b3000 { @@ -47,6 +55,13 @@ Example: clocks = <&clock_gcc clk_gcc_dcc_ahb_clk>; clock-names = "dcc_clk"; + qcom,curr-link-list = <2>; + qcom,link-list = , + , + , + , + , + ; qcom,save-reg; }; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt index 800508afbf69df79f9d8c70e4e83aa74bff7c75c..bf2a91a5249a0db002f26dfab87d960e1bdefba0 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt @@ -10,6 +10,13 @@ Required properties: - interrupts: Interrupt number - reg: Should be address and size of EUD register space - reg-names: Should be "eud_base" + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with + the "clocks" property. + - -supply: phandle to the regulator device tree node + Required "supply-name" examples are: + "vdda33" : 3.3v supply to eud. Driver notifies clients via extcon for VBUS spoof attach/detach and charger enable/disable events. Clients registered for these @@ -23,6 +30,9 @@ An example for EUD device node: interrupts = ; reg = <0x88e0000 0x4000>; reg-names = "eud_base"; + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "cfg_ahb_clk"; + vdda33-supply = <&pm8998_l24>; }; An example for EUD extcon client: diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index e0ab31ff38558a48f1aa0019cebb9b612d44128f..58c9bf809c8c5291ec95c0adcbf0f094cf0fe86b 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -186,6 +186,12 @@ Optional properties: - qcom,msm-pcm-loopback-low-latency : Flag indicating whether the device node is of type low latency. +* msm-transcode-loopback + +Required properties: + + - compatible : "qcom,msm-transcode-loopback" + * msm-dai-q6 [First Level Nodes] @@ -287,6 +293,19 @@ Required properties: - compatible : "qcom,msm-pcm-hostless" +* audio-load-mod + +Required properties: + + - compatible : "qcom,audio-load-mod" + +Optional properties: + + - compatible : "qcom,audio-test-mod" + Add this compatible as child device to load-module device. + This child device is added after lpass is up to invoke + deferred probe devices. + * msm-ocmem-audio Required properties: @@ -323,7 +342,7 @@ Required properties: - qcom,gpio-connect Gpio that connects to parent interrupt controller -* audio-ext-clk +* audio-ext-clk-up Required properties: @@ -347,6 +366,10 @@ Optional properties: - clocks: phandle reference to the parent clock. + - qcom,mclk-clk-reg: Indicate the register address for mclk. + + - qcom,lpass-mclk-id: Property to update LPASS MCLK Id. + * audio_slimslave Required properties: @@ -632,6 +655,13 @@ Example: compatible = "qcom,msm-pcm-hostless"; }; + audio_load_mod { + compatible = "qcom,audio-load-mod"; + audio_test_mod { + compatible = "qcom,audio-test-mod"; + }; + }; + qcom,msm-ocmem-audio { compatible = "qcom,msm-ocmem-audio"; qcom,msm_bus,name = "audio-ocmem"; @@ -1149,12 +1179,9 @@ Required properties: When clock rate is set to zero, then external clock is assumed. - [Second Level Nodes] - -Required properties: - - - compatible : "qcom,msm-dai-q6-tdm" - - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID. + - qcom,msm-cpudai-tdm-clk-internal: Clock Source. + 0 - EBIT clock from clk tree + 1 - IBIT clock from clk tree - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting. 0 - Short sync bit mode @@ -1179,6 +1206,13 @@ Required properties: 1 - 1 bit clock cycle 2 - 2 bit clock cycle + [Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-q6-tdm" + - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID. + - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed within the slot. For example, 32 slot width in case of sample bit width is 24. @@ -1213,17 +1247,18 @@ Example: qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36912>; qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>; pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; qcom,msm-cpudai-tdm-header-start-offset = <0>; qcom,msm-cpudai-tdm-header-width = <2>; @@ -2003,6 +2038,66 @@ Example: qcom,aux-codec = <&stub_codec>; }; +* SDX ASoC Machine driver + +Required properties: +- compatible : "qcom,sdx-asoc-snd-tavil" +- qcom,model : The user-visible name of this sound card. +- qcom,prim_mi2s_aux_master : Handle to prim_master pinctrl configurations +- qcom,prim_mi2s_aux_slave : Handle to prim_slave pinctrl configurations +- qcom,sec_mi2s_aux_master : Handle to sec_master pinctrl configurations +- qcom,sec_mi2s_aux_slave : Handle to sec_slave pinctrl configurations +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order give + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. + +Example: + + sound-tavil { + compatible = "qcom,sdx-asoc-snd-tavil"; + qcom,model = "sdx-tavil-i2s-snd-card"; + qcom,prim_mi2s_aux_master = <&prim_master>; + qcom,prim_mi2s_aux_slave = <&prim_slave>; + qcom,sec_mi2s_aux_master = <&sec_master>; + qcom,sec_mi2s_aux_slave = <&sec_slave>; + + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&hostless>, <&afe>, <&routing>, + <&pcm_dtmf>, <&host_pcm>, <&compress>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-voip-dsp", "msm-pcm-voice", + "msm-pcm-loopback", "msm-pcm-hostless", + "msm-pcm-afe", "msm-pcm-routing", + "msm-pcm-dtmf", "msm-voice-host-pcm", + "msm-compress-dsp"; + asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>, + <&dtmf_tx>, + <&rx_capture_tx>, <&rx_playback_rx>, + <&tx_capture_tx>, <&tx_playback_rx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&dai_sec_auxpcm>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", + "msm-dai-stub-dev.6", "msm-dai-stub-dev.7", + "msm-dai-stub-dev.8", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-auxpcm.2"; + }; + * APQ8096 Automotive ASoC Machine driver Required properties: @@ -2256,8 +2351,8 @@ Optional properties: - qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target - qcom,msm-mbhc-usbc-audio-supported : Property to specify if analog audio feature is enabled or not. -- qcom,usbc-analog-en1_gpio : EN1 GPIO to enable USB type-C analog audio -- qcom,usbc-analog-en2_n_gpio : EN2 GPIO to enable USB type-C analog audio +- qcom,usbc-analog-en1-gpio : EN1 GPIO to enable USB type-C analog audio +- qcom,usbc-analog-en2-gpio : EN2 GPIO to enable USB type-C analog audio - qcom,usbc-analog-force_detect_gpio : Force detect GPIO to enable USB type-C analog audio Example: @@ -2298,14 +2393,15 @@ Example: qcom,tasha-mclk-clk-freq = <9600000>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>; + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&trans_loopback>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", - "msm-compr-dsp"; + "msm-compr-dsp","msm-transcode-loopback"; asoc-cpu = <&dai_hdmi>, <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, @@ -2333,8 +2429,8 @@ Example: qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft", "SpkrRight", "SpkrLeft"; qcom,msm-mbhc-usbc-audio-supported = <1>; - qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>; - qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>; + qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2-gpio = <&tlmm 51 0>; qcom,usbc-analog-force_detect_gpio = <&wcd_usbc_analog_f_gpio>; }; @@ -2445,6 +2541,10 @@ Optional properties: 6-pole-jack : Jack on the hardware is 6-pole. - clock-names : clock name defined for external clock. - clocks : external clock defined for codec clock. +- qcom,msm-mbhc-hs-mic-max-threshold-mv : headset detection threshold. When micbias is + not set to 2.7v, need scale in driver. +- qcom,msm-mbhc-hs-mic-min-threshold-mv : headhpone detection threshold. When micbias is + not set to 2.7v, need scale in driver. - qcom,hph-en1-gpio : GPIO to enable HiFi amplifiers. - qcom,hph-en0-gpio : GPIO to enable HiFi audio route to headset. - qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target @@ -2502,6 +2602,8 @@ Example: qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>; + qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>; qcom,hph-en0-gpio = <&tavil_hph_en0>; qcom,hph-en1-gpio = <&tavil_hph_en1>; qcom,tavil-mclk-clk-freq = <9600000>; @@ -2565,3 +2667,266 @@ Example: qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", "SpkrLeft", "SpkrRight"; }; + +* SDM670 ASoC Machine driver + +Required properties: +- compatible : "qcom,sdm670-asoc-snd" +- qcom,model : The user-visible name of this sound card. +- qcom,msm-hs-micbias-type : This property is used to recognize the headset + micbias type, internal or external. +- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL +switch type on target typically the switch type will be normally open or +normally close, value for this property 0 for normally close and 1 for +normally open. +- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND +switch type on target typically the switch type will be normally open or +normally close, value for this property 0 for normally close and 1 for +normally open. +- qcom,audio-routing : A list of the connections between audio components. +- qcom,msm-gpios : Lists down all the gpio sets that are supported. +- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets +mentioned in qcom,msm-gpios. +- pinctrl-names : The combinations of gpio sets from above that are supported in +the flavor. +- pinctrl-# : Pinctrl states as mentioned in pinctrl-names. + +Optional properties: +- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming. +- qcom,msm-micbias1-ext-cap : Boolean. Enable micbias1 external +capacitor mode. +- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external +capacitor mode. +- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node. +- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa. +- qcom,msm-mclk-freq : This property is used to inform machine driver about +mclk frequency needs to be configured for internal and external PA. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,cdc-pdm-gpios : phandle for pdm gpios. +- qcom,cdc-comp-gpios : phandle for compander gpios. +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,cdc-sdw-gpios : phandle for soundwire clk and data gpios. +- qcom,pri-mi2s-gpios : phandle for primary MI2S clk, word select and data gpios. +- qcom,sec-mi2s-gpios : phandle for secondary MI2S clk, word select and data gpios. +- qcom,tert-mi2s-gpios : phandle for tertiary MI2S clk, word select and data gpios. +- qcom,quat-mi2s-gpios : phandle for quaternary MI2S clk, word select and data gpios. +- qcom,quin-mi2s-gpios : phandle for quinary MI2S clk, word select and data gpios. +- qcom,msm-mbhc-moist-cfg: This property is used to set moisture detection + threshold values for different codecs. First parameter is V(voltage) + second one is i(current), third one is r (resistance). Depending on the + codec set corresponding element in array and set others to 0. + +Example: + sound { + compatible = "qcom,sdm670-asoc-snd"; + qcom,model = "sdm670-snd-card"; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-hs-micbias-type = "internal"; + qcom,msm-micbias1-ext-cap; + qcom,audio-routing = + "RX_BIAS", "MCLK", + "SPK_RX_BIAS", "MCLK", + "INT_LDO_H", "MCLK", + "MIC BIAS External", "Handset Mic", + "MIC BIAS Internal2", "Headset Mic", + "MIC BIAS External", "Secondary Mic", + "AMIC1", "MIC BIAS External", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External"; + qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>; + qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>; + qcom,cdc-comp-gpios = <&cdc_comp_gpios>; + qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>; + qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>; + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&lpa>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", + "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa"; + asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>, + <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>, + <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft", + "SpkrRight", "SpkrLeft"; + }; + +* SDM670 ASoC Slimbus Machine driver + +Required properties: +- compatible : "qcom,sdm670-asoc-snd-tasha" for tasha codec, + "qcom,sdm670-asoc-snd-tavil" for tavil codec. +- qcom,model : The user-visible name of this sound card. +- qcom,msm-mclk-freq : MCLK frequency value for external codec +- qcom,msm-gpios : Lists down all the gpio sets that are supported. +- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets +mentioned in qcom,msm-gpios. Say we have 2^N combinations for N GPIOs, +this would list all the 2^N combinations. +- pinctrl-names : The combinations of gpio sets from above that are supported in +the flavor. This can be sometimes same as qcom, pinctrl-names i.e with 2^N +combinations or will have less incase if some combination is not supported. +- pinctrl-# : Pinctrl states as mentioned in pinctrl-names. +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming. +- clock-names : clock name defined for external clock. +- clocks : external clock defined for codec clock. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,pri-mi2s-gpios : phandle for primary MI2S clk, word select and data gpios. +- qcom,sec-mi2s-gpios : phandle for secondary MI2S clk, word select and data gpios. +- qcom,tert-mi2s-gpios : phandle for tertiary MI2S clk, word select and data gpios. +- qcom,quat-mi2s-gpios : phandle for quaternary MI2S clk, word select and data gpios. +- qcom,quin-mi2s-gpios : phandle for quinary MI2S clk, word select and data gpios. + +Example: + + sound-9335 { + compatible = "qcom,sdm670-asoc-snd-tasha"; + qcom,model = "sdm670-tasha-snd-card"; + + qcom,audio-routing = + "RX_BIAS", "MCLK", + "LDO_H", "MCLK", + "AIF4 MAD", "MCLK", + "ultrasound amp", "LINEOUT1", + "ultrasound amp", "LINEOUT3", + "AMIC1", "MIC BIAS1 Internal1", + "MIC BIAS1 Internal1", "Handset Mic", + "AMIC2", "MIC BIAS2 External", + "MIC BIAS2 External", "Headset Mic", + "AMIC3", "MIC BIAS2 External", + "MIC BIAS2 External", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2 External", + "MIC BIAS2 External", "ANCLeft Headset Mic", + "DMIC1", "MIC BIAS1 External", + "MIC BIAS1 External", "Digital Mic1", + "DMIC2", "MIC BIAS1 External", + "MIC BIAS1 External", "Digital Mic2", + "DMIC3", "MIC BIAS3 External", + "MIC BIAS3 External", "Digital Mic3", + "DMIC4", "MIC BIAS3 External", + "MIC BIAS3 External", "Digital Mic4", + "DMIC5", "MIC BIAS4 External", + "MIC BIAS4 External", "Digital Mic5", + "DMIC6", "MIC BIAS4 External", + "MIC BIAS4 External", "Digital Mic6"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-gpios = + "slim", + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "slim_act", + "us_eu_gpio_act", + "slim_us_eu_gpio_act"; + pinctrl-names = + "all_off", + "slim_act", + "us_eu_gpio_act", + "slim_us_eu_gpio_act"; + pinctrl-0 = <&cdc_slim_lines_sus &cross_conn_det_sus>; + pinctrl-1 = <&cdc_slim_lines_act &cross_conn_det_sus>; + pinctrl-2 = <&cdc_slim_lines_sus &cross_conn_det_act>; + pinctrl-3 = <&cdc_slim_lines_act &cross_conn_det_act>; + qcom,cdc-us-euro-gpios = <&msm_gpio 63 0>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp"; + asoc-cpu = <&dai_hdmi>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft", + "SpkrRight", "SpkrLeft"; + }; diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt index 0df94172674b9920380a8ece2b0457d82cca28a0..6d2ae5ede8800b1e510a2dd2c1e5d96a63373461 100644 --- a/Documentation/devicetree/bindings/sound/wcd_codec.txt +++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt @@ -3,7 +3,7 @@ WCD audio CODEC Required properties: - compatible : "qcom,tasha-slim-pgd" or "qcom,tasha-i2c-pgd" for Tasha Codec - or "qcom,tavil-slim-pgd" for Tavil Codec + "qcom,tavil-slim-pgd" or "qcom,tavil-i2c-pgd" for Tavil Codec - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits) - qcom,cdc-reset-gpio: gpio used for codec SOC reset. @@ -12,7 +12,6 @@ Required properties: - qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio configuration. If this property is not defined, it is expected to atleast define "qcom,cdc-reset-gpio" property. - - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node. - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV. - qcom,cdc-vdd-buck-current: buck supply's max current in mA. @@ -142,6 +141,11 @@ Optional properties: - clock-names : clock name defined for external clock. - clocks : external clock defined for codec clock. + - qcom,has-buck-vsel-gpio: Boolean property to select if WCD_BUCK has VSEL + controlled by GPIO. + - qcom,buck-vsel-gpio-node: Phandle reference to the DT node having wcd buck + VSEL gpio configuration. + Example: taiko_codec { diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt index 868a5f0f42cb29767fc825e053a13075a2c35761..866d004200caff7d4087daea120e2b298c50e425 100644 --- a/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt +++ b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt @@ -23,6 +23,11 @@ Required properties: - spi-max-frequency: Specifies maximum SPI clock frequency, Units - Hz. Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt +- qcom,wrapper-core: Wrapper QUPv3 core containing this SPI controller. + +Optional properties: +- qcom,rt: Specifies if the framework worker thread for this + controller device should have "real-time" priority. SPI slave nodes must be children of the SPI master node and can contain properties described in Documentation/devicetree/bindings/spi/spi-bus.txt @@ -44,6 +49,7 @@ Example: pinctrl-1 = <&qup_1_spi_2_sleep>; interrupts = ; spi-max-frequency = <19200000>; + qcom,wrapper-core = <&qupv3_0>; dev@0 { compatible = "dummy,slave"; diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt new file mode 100644 index 0000000000000000000000000000000000000000..1edf0820398a06adc2bc72d6f70903733a9c66e8 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt @@ -0,0 +1,106 @@ +Qualcomm Serial Peripheral Interface (SPI) + +Required properties: +- compatible : Should be "qcom,spi-qup-v2". +- reg : Offset and length of the register regions for the device +- reg-names : Register region names referenced in reg above. + Required register resource entries are: + "spi_physical" : Physical address of controller register blocks. +- interrupts : Interrupt numbers used by this controller +- interrupt-names : Interrupt resource names referenced in interrupts above. + Required interrupt resource entries are: + "spi_irq" : QUP-core interrupt. +- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz. + +Required alias: +- The desired bus-number is specified via an alias with the following format + 'spi{n}' where n is the bus number. + +Optional properties: +- qcom,gpio-mosi : GPIO pin number of the MOSI bus line. +- qcom,gpio-miso : GPIO pin number of the MISO bus line. +- qcom,gpio-clk : GPIO pin number of the CLK bus line. +- qcom,gpio-cs0 : GPIO pin number of the chipselect0 bus line. +- qcom,gpio-cs1 : GPIO pin number of the chipselect1 bus line. +- qcom,gpio-cs2 : GPIO pin number of the chipselect2 bus line. +- qcom,gpio-cs3 : GPIO pin number of the chipselect3 bus line. +- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When + value is non-zero, the value is the number of words in maximum transfer + length. + - qcom,active-only : Vote for core clock when the application processor goes + to active state and remove that vote when it goes to idle state. This flag may + improve service time of first spi request at the expense of power consumption. + When this entry is not present, voting is done by the runtime-pm callbacks. + - qcom,master-id : Master endpoint number used for voting on clocks using the + bus-scaling driver. + - qcom,rt-priority : whether spi message queue is set to run as a realtime task. + With this spi transaction message pump with high (realtime) priority to reduce + the transfer latency on the bus by minimising the delay between a transfer request + - qcom,shared : whether this qup is shared with other ee's + +Optional properties which are required for support of BAM-mode: +- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW + version support latest features (e.g. BAM) and then enable them. Should be + removed for legacy HW. +- qcom,use-bam : Boolean. When present, enables BAM-mode. +- qcom,use-pinctrl : Boolean. When present, enables pinctrl frame work to configure GPIO's + instead of existing gpio mux hence gpio entries are no more required if present. +- pinctrl-names : Property must contain "spi_default" and "spi_sleep" if + pinctrl is to be used. + instead of existing gpio mux hence gpio entries are no more required if present. +- qcom,bam-consumer-pipe-index : BAM consumer-pipe index. +- qcom,bam-producer-pipe-index : BAM producer-pipe index. +- reg-names : register region names referenced in reg. + Required register resource for BAM are: + "spi_bam_physical" : Physical address of BAM for this controller. +- interrupt-names : interrupt resource names referenced in interrupts. + Required interrupt resource from BAM are: + "spi_bam_irq" : BAM interrupt used by the controller. + +Optional SPI slave nodes must be children of the SPI master node and contain +the following properties. +- reg: (required) chip-select address of the device. +- compatible : (required) Name of SPI device following generic names. +- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz +- interrupts : (recommended) Should contain the SPI slave interrupt number + encoded depending on the type of the interrupt controller. +- interrupt-parent : (recommended) The phandle for the interrupt controller + that services interrupts for this device. +- spi-cpol : (optional) Empty property indicating device requires inverse + clock polarity (CPOL) mode +- spi-cpha : (optional) Empty property indicating device requires shifted + clock phase (CPHA) mode +- spi-cs-high : (optional) Empty property indicating device requires + chip select active high + +Example: + aliases { + spi0 = &spi_0; + }; + + spi_0: spi@f9923000 { + compatible = "qcom,spi-qup-v2"; + + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xf9923000 0x1000>, + <0xf9904000 0x10000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 95 0>, <0 238 0>; + + spi-max-frequency = <19200000>; + #address-cells = <1>; + #size-cells = <0>; + qcom,gpio-mosi = <&msmgpio 0 0>; + qcom,gpio-miso = <&msmgpio 1 0>; + qcom,gpio-clk = <&msmgpio 3 0>; + qcom,gpio-cs2 = <&msmgpio 9 0>; + + qcom,infinite-mode = <0>; + qcom,use-bam; + qcom,use-pinctrl; + qcom,bam-consumer-pipe-index = <12>; + qcom,bam-producer-pipe-index = <13>; + qcom,ver-reg-exists; + qcom,master-id = <86>; + qcom,rt-priority; + }; diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt index ceac719878e7a32dd90a4f7e2227d8bd43d7c447..2131c33237f00953f10f92ac8337b41a63896a87 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt @@ -35,6 +35,19 @@ Supported Properties: the corresponding addresses are specified in the reg property. +- clocks + Usage: optional + Value type: + Definition: Clock tuple consisting of a phandle to a clock controller + device and the clock ID number for the SPMI debug controller + clock. + +- clock-names + Usage: required if clocks property is specified + Value type: + Definition: Defines the name of the clock defined in the "clocks" + property. This must be "core_clk". + - #address-cells Usage: required Value type: @@ -57,6 +70,8 @@ qcom,spmi-debug@6b22000 { compatible = "qcom,spmi-pmic-arb-debug"; reg = <0x6b22000 0x60>, <0x7820A8 4>; reg-names = "core", "fuse"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; qcom,fuse-disable-bit = <12>; #address-cells = <2>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt index bef9193345746a046c70d85b9559272290f23be9..c50d678cd0bf347cc4d8aa335575d25961eaadba 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt @@ -42,6 +42,11 @@ Required properties: cell 4: interrupt flags indicating level-sense information, as defined in dt-bindings/interrupt-controller/irq.h +Optional properties: +- qcom,enable-ahb-bus-workaround : Boolean flag which indicates that the AHB bus + workaround sequence should be used for SPMI + write transactions to avoid corruption + Example V1 PMIC-Arbiter: spmi { diff --git a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt index 8bead0d0abcf0811cdd87435e22ed9c4bf022f9f..be50d45ec4c45a8c15d13a6b58805f047de67f35 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt @@ -31,12 +31,29 @@ Properties: Definition: Should specify the cluster affinity this hardware corresponds to. +- isens_vref-supply: + Usage: optional + Value type: + Definition: Should specify the phandle of the vref regulator used by + the isens hardware. This active only regulator will be + enabled by LMH DCVSh. + +- isens-vref-settings: + Usage: optional + Value type: + Definition: Should specify the min voltage(uV), max voltage(uV) and + max load(uA) for the isens vref regulator. This + property is valid only if there is valid entry for + isens_vref-supply. + Example: lmh_dcvs0: qcom,limits-dcvs@0 { compatible = "qcom,msm-hw-limits"; interrupts = ; qcom,affinity = <0>; + isens_vref-supply = <&pm8998_l1_ao>; + isens-vref-settings = <880000 880000 36000>; }; CPU0: cpu@0 { diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt index 702f25238e5e974017c505ecd3ecb25d4a94c6f8..97b71a738fc00f2c18da14d28214bec318f50b8e 100644 --- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt +++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt @@ -11,8 +11,7 @@ to set thresholds and receive threshold notifications. VADC_TM node Required properties: -- compatible : should be "qcom,qpnp-adc-tm" for thermal ADC driver. - : should be "qcom,qpnp-adc-tm-hc" for thermal ADC driver using +- compatible : should be "qcom,qpnp-adc-tm-hc" for thermal ADC driver using refreshed BTM peripheral. - reg : offset and length of the PMIC Aribter register map. - address-cells : Must be one. @@ -62,6 +61,8 @@ Optional properties: - qcom,adc-tm-recalib-check: Add this property to check if recalibration required due to inaccuracy. - hkadc_ldo-supply : Add this property if VADC needs to perform a Software Vote for the HKADC. - hkadc_ok-supply : Add this property if the VADC needs to perform a Software vote for the HKADC VREG_OK. +- #thermal-sensor-cells : To register ADC sensors with of_thermal. Should be 1. + See ./thermal.txt for a description. Client required property: - qcom,-adc_tm : The phandle to the corresponding adc_tm device. @@ -156,51 +157,6 @@ client_node { qcom,client-adc_tm = <&pm8941_adc_tm>; }; -Example for "qcom,qpnp-adc-tm" device: - /* Main Node */ - qcom,vadc@3400 { - compatible = "qcom,qpnp-adc-tm"; - reg = <0x3400 0x100>; - #address-cells = <1>; - #size-cells = <0>; - interrupts = <0x0 0x34 0x0>, - <0x0 0x34 0x3>, - <0x0 0x34 0x4>; - interrupt-names = "eoc-int-en-set", - "high-thr-en-set", - "low-thr-en-set"; - qcom,adc-bit-resolution = <15>; - qcom,adc-vdd-reference = <1800>; - qcom,adc_tm-vadc = <&pm8941_vadc>; - - /* Channel Node to be registered as part of thermal sysfs */ - chan@b5 { - label = "pa_therm1"; - reg = <0xb5>; - qcom,decimation = <0>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; - qcom,btm-channel-number = <0x70>; - qcom,thermal-node; - }; - - /* Channel Node */ - chan@6 { - label = "vbat_sns"; - reg = <6>; - qcom,decimation = <0>; - qcom,pre-div-channel-scaling = <1>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <3>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; - qcom,btm-channel-number = <0x78>; - }; - }; - Example for "qcom,qpnp-adc-tm-hc" device: /* Main Node */ pm8998_adc_tm: vadc@3400 { @@ -218,7 +174,7 @@ Example for "qcom,qpnp-adc-tm-hc" device: /* Channel Node to be registered as part of thermal sysfs */ chan@b5 { - label = "pa_therm1"; + label = "msm_therm"; reg = <0xb5>; qcom,pre-div-channel-scaling = <0>; qcom,calibration-type = "absolute"; @@ -239,3 +195,21 @@ Example for "qcom,qpnp-adc-tm-hc" device: qcom,btm-channel-number = <0x78>; }; }; + +/* Example to register thermal sensor using of_thermal */ +&thermal_zones { + msm-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0xb5>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt index bb20644afde686b774319c9a931664fd86c6bd7f..fc8ec87c4644f9d33718a47c1a7c5de53910cf23 100644 --- a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt +++ b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt @@ -12,10 +12,17 @@ Required properties: - interrupts: PMIC temperature alarm interrupt - label: A string used as a descriptive name for this thermal device. This name should be 19 characters or less. +- #thermal-sensor-cells: Must be 0. Please refer to + for more + details. Required structure: - A qcom,qpnp-temp-alarm node must be a child of an SPMI node that has specified the spmi-slave-container property +- A top level device tree node named "thermal-zones" must exist. It must + contain a subnode with a property named "thermal-sensors" which is assigned + a phandle to the qpnp-temp-alarm device node. See + for more details. Optional properties: - qcom,channel-num: VADC channel number associated PMIC DIE_TEMP thermistor. @@ -38,11 +45,6 @@ Optional properties: 1 = 50 Hz 2 = 25 Hz 3 = 12.5 Hz -- qcom,allow-override: Boolean which controls the ability of software to - override shutdowns. If present, then software is - allowed to override automatic PMIC hardware stage 2 and - stage 3 over temperature shutdowns. Otherwise, software - is not allowed to override automatic shutdown. - qcom,default-temp: Specifies the default temperature in millicelcius to use if no ADC channel is present to read the real time temperature. @@ -64,7 +66,7 @@ Example: #address-cells = <1>; #size-cells = <1>; - qcom,temp-alarm@2400 { + pm8941_tz: qcom,temp-alarm@2400 { compatible = "qcom,qpnp-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x0 0x24 0x0>; @@ -72,6 +74,36 @@ Example: qcom,channel-num = <8>; qcom,threshold-set = <0>; qcom,temp_alarm-vadc = <&pm8941_vadc>; + #thermal-sensor-cells = <0>; + }; + }; +}; + +Below is an example thermal zone definition for the temperature alarm +peripheral. +thermal-zones { + pm8941_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8941_tz>; + + trips { + pm8941-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm8941-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm8941-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "critical"; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt b/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..51c5eac18113c296c9b872bf35d44c7835be8f95 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qti-qmi-cdev.txt @@ -0,0 +1,113 @@ +QMI thermal mitigation(TMD) cooling devices. + +The QMI TMD cooling device, will be used for various mitigations for remote +subsystem including remote processor mitigation, rail voltage restriction etc. +This cooling device uses kernel qti QMI interface to send the message to +remote subsystem. + +Each child node of the QMI TMD devicetree node represents each remote +subsystem and each child of this subsystem represents separate cooling +devices. It requires minimum one remote subsystem node and each subsystem +node requires minimum one cooling device node. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: should be "qcom,qmi_cooling_devices" + + +Subsystem properties: +- qcom,instance-id: + Usage: required + Value type: + Definition: Remote subsystem QMI server instance id to be used for + communicating with QMI. + + Minimum one child node is required. Child node name and its alias are + used as cooling device name and phandle for that cooling device. + + cooling device node properties: + -qcom,qmi-dev-name: + Usage: required + Value type: + Definition: Remote subsystem device identifier. Below strings + are the only acceptable device names, + "pa" -> for pa cooling device, + "cpuv_restriction_cold" -> for vdd restriction, + "cx_vdd_limit" -> for vdd limit, + "modem" -> for processor passive cooling device, + "modem_current" -> for current limiting device, + "modem_bw" -> for bus bandwidth limiting device, + "cpr_cold" -> for cpr restriction. + + -#cooling-cells: + Usage: required + Value type: + Definition: Must be 2. Needed for of_thermal as cooling device + identifier. Please refer to + for more + details. +Example: + + qmi-tmd-devices { + compatible = "qcom,qmi_cooling_devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_cpr_cold: modem_cpr_cold { + qcom,qmi-dev-name = "cpr_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + slpi { + qcom,instance-id = <0x53>; + + slpi_vdd: slpi_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/thermal/qti-rpmh-reg-cdev.txt b/Documentation/devicetree/bindings/thermal/qti-rpmh-reg-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7734adc508287a5bd8bb41bf183acf50e1cff56 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qti-rpmh-reg-cdev.txt @@ -0,0 +1,44 @@ +RPMh regulator cooling device. + +The RPMh regulator cooling device, will be used to place a voltage floor +restriction on a rail. This cooling device will use a QMP AOP mail box to send +the message to apply and clear voltage floor restriction. + +The cooling device node should be a child of the regulator devicetree node, +which it is trying to place the floor restriction. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: shall be "qcom,rpmh-reg-cdev" + +- qcom,reg-resource-name: + Usage: required + Value type: + Definition: The regulator resource name to be used for communicating + with RPMh. This value should be any of the below + resource name, + cx -> For CX rail, + mx -> For MX rail, + ebi -> For EBI rail. + +- mboxes: + Usage: required + Value type: + Definition: A phandle to the QMP AOP mail box, that needs to be used + for sending the floor restriction message. + +- #cooling-cells: Must be 2. Please refer to + for more + details. + +Example: + + vdd_cx: rpmh-cx-regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/thermal/regulator-cdev.txt b/Documentation/devicetree/bindings/thermal/regulator-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c9abe2053445599958e04fb3819a58f84fc1500 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/regulator-cdev.txt @@ -0,0 +1,38 @@ +Regulator cooling device. + +The regulator cooling device, will be used to place a voltage floor +restriction on a rail. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: shall be "qcom,regulator-cooling-device" + +- cdev-supply: + Usage: required + Value type: + Definition: phandle to the regulator to which the cooling device will + place a floor mitigation. + +- regulator-levels: + Usage: required + Value type: + Definition: Array of regulator voltages the cooling device should + use to place a floor restriction. The voltages should + be specified in descending order. + +- #cooling-cells: Must be 2. Please refer to + for more + details. + +Example: + + mv_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + cdev-supply = <®ulator-cdev-supply>; + regulator-levels = ; + #cooling-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt index 123a65b3d9565cf4b95ed0a4e828966e5150d770..794d2795a616241d29ad121b830f235a6c3a8dda 100644 --- a/Documentation/devicetree/bindings/thermal/thermal.txt +++ b/Documentation/devicetree/bindings/thermal/thermal.txt @@ -187,6 +187,10 @@ Optional property: 2000mW, while on a 10'' tablet is around 4500mW. +- disable-thermal-zone: Disable the thermal zone monitoring by default. These + Type:bool thermal zones will be enabled by userspace daemons + based on usecase. + - tracks-low: Indicates that the temperature sensor tracks the low Type: bool thresholds, so the governors may mitigate by ensuring timing closures and other low temperature operating diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt index 3e59c43ce0c550dfd534dff345a62c02c02777a9..67ffaed4e51ccec9ebbc46d8306379b376f75ad1 100644 --- a/Documentation/devicetree/bindings/thermal/tsens.txt +++ b/Documentation/devicetree/bindings/thermal/tsens.txt @@ -18,6 +18,7 @@ Required properties: should be "qcom,sdm660-tsens" for 660 TSENS driver. should be "qcom,sdm630-tsens" for 630 TSENS driver. should be "qcom,sdm845-tsens" for SDM845 TSENS driver. + should be "qcom,tsens24xx" for 2.4 TSENS controller. The compatible property is used to identify the respective controller to use for the corresponding SoC. - reg : offset and length of the TSENS registers with associated property in reg-names diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index 958194b0f445cde65b6bdfad32785ba9cf97e8b5..7f79f4041e4f2adfce867eaf65d900dc87835f6f 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -23,6 +23,8 @@ Optional properties: with "phys" attribute, provides phandle to UFS PHY node - vdd-hba-supply : phandle to UFS host controller supply regulator node - vcc-supply : phandle to VCC supply regulator node +- vcc-voltage-level : specifies voltage levels for VCC supply. + Should be specified in pairs (min, max), units uV. - vccq-supply : phandle to VCCQ supply regulator node - vccq2-supply : phandle to VCCQ2 supply regulator node - vcc-supply-1p8 : For embedded UFS devices, valid VCC range is 1.7-1.95V @@ -70,6 +72,9 @@ Optional properties: 2: 38.4 MHz 3: 52 MHz Defaults to 26 MHz if not specified. +- extcon: phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details). +- non-removable : defines if the connected ufs device is not removable + Note: If above properties are not defined it can be assumed that the supply regulators or clocks are always on. diff --git a/Documentation/devicetree/bindings/uio/msm_sharedmem.txt b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt index 749c6e85681995b32cc44d508bef4ddb00f755aa..4c89846a9f649535bb968985bad037c707e31b18 100644 --- a/Documentation/devicetree/bindings/uio/msm_sharedmem.txt +++ b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt @@ -9,10 +9,18 @@ Required properties: - reg-names : Indicates various client-names. - qcom,client-id : The client id for the QMI clients. +Optional properties: +- qcom,guard-memory: If this dtsi property is set, then the shared memory + region will be guarded by SZ_4K at the start and at the end. + This is needed to overcome the XPU limitation on few MSM HW, + so as to make this memory not contiguous with other allocations + that may possibly happen from other clients. + Example: qcom,msm_sharedmem@0dc80000 { compatible = "qcom,sharedmem-uio"; reg = <0x0dc80000 0x00180000>, reg-names = "rmtfs"; qcom,client-id = <0x00000001>; + qcom,guard-memory; }; diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 609d8535591ea47565233ec61959a8a2a99b0352..5d3b232c24537b593c1ce3e80a7b204d99a2eb09 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -58,6 +58,9 @@ Optional properties: gating. Default it is enabled. - snps,xhci-imod-value: Interrupt moderation interval for host mode (in increments of 250nsec). + - usb-core-id: Differentiates between different controllers present on a device. + - snps,bus-suspend-enable: If present then controller supports low power mode + during bus suspend. This is usually a subnode to DWC3 glue to which it is connected. diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index e508a4fed2ab27e1a8dc233b9dc0f158fe459673..f8c8a69702ba637d44fd45adf0e55879eb4b989f 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -1,10 +1,45 @@ MSM USB PHY transceivers +HSUSB PHY + +Required properties: + - compatible: Should be "qcom,usb-hsphy-snps-femto" + - reg: Address and length of the register set for the device + Required regs are: + "hsusb_phy_base" : the base register for the PHY + - -supply: phandle to the regulator device tree node + Required "supply-name" examples are: + "vdd" : vdd supply for HSPHY digital circuit operation + "vdda18" : 1.8v supply for HSPHY + "vdda33" : 3.3v supply for HSPHY + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. "ref_clk_src" is a mandatory clock. + - qcom,vdd-voltage-level: This property must be a list of three integer + values (no, min, max) where each value represents either a voltage in + microvolts or a value corresponding to voltage corner + - resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. + - reset-names: reset signal name strings sorted in the same order as the resets + property. + +Example: + hsphy@f9200000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0xff1000 0x400>; + vdd-supply = <&pm8841_s2_corner>; + vdda18-supply = <&pm8941_l6>; + vdda33-supply = <&pm8941_l24>; + qcom,vdd-voltage-level = <0 872000 872000>; + }; + SSUSB-QMP PHY Required properties: - compatible: Should be "qcom,usb-ssphy-qmp", "qcom,usb-ssphy-qmp-v1" or - "qcom,usb-ssphy-qmp-v2" or "qcom,usb-ssphy-qmp-dp-combo" + "qcom,usb-ssphy-qmp-v2" or "qcom,usb-ssphy-qmp-usb3-or-dp" or + "qcom,usb-ssphy-qmp-dp-combo" - reg: Address and length of the register set for the device Required regs are: "qmp_phy_base" : QMP PHY Base register set. @@ -118,12 +153,17 @@ Required properties: and reset lines used by this controller. - reset-names: reset signal name strings sorted in the same order as the resets property. + - qcom,qusb-phy-reg-offset: Provides important phy register offsets in an order defined in phy driver. Optional properties: - reg-names: Additional registers corresponding with the following: "efuse_addr": EFUSE address to read and update analog tune parameter. "emu_phy_base" : phy base address used for programming emulation target phy. "ref_clk_addr" : ref_clk bcr address used for on/off ref_clk before reset. + "tcsr_clamp_dig_n" : To enable/disable digital clamp to the phy. When + de-asserted, it will prevent random leakage from qusb2 phy resulting from + out of sequence turn on/off of 1p8, 3p3 and DVDD regulators. + "refgen_north_bg_reg" : address used to read REFGEN status for overriding QUSB PHY register. - clocks: a list of phandles to the PHY clocks. Use as per Documentation/devicetree/bindings/clock/clock-bindings.txt - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" @@ -140,6 +180,10 @@ Optional properties: - qcom,hold-reset: Indicates that hold QUSB PHY into reset state. - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided. - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0 + - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Names represents "active" + state when attached in host mode and "suspend" state when detached. + - qcom,tune2-efuse-correction: The value to be adjusted from fused value for + improved rise/fall times. Example: qusb_phy: qusb@f9b39000 { @@ -150,6 +194,14 @@ Example: vdda18-supply = <&pm8994_l6>; vdda33-supply = <&pm8994_l24>; qcom,vdd-voltage-level = <1 5 7>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198>; /* QUSB2PHY_PLL_BIAS_CONTROL_2 */ qcom,efuse-bit-pos = <21>; qcom,efuse-num-bits = <3>; diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index bc66690db2d93ac2594fb5baf8699df3c4964580..881f9ca12a34bf61f14b0b983a2a252dffd3f6fb 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -7,7 +7,6 @@ Required properties : "core_base" : usb controller register set - interrupts: IRQ lines used by this controller - interrupt-names : Interrupt resource entries are : - "hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM. "pwr_event_irq" : Interrupt to controller for asynchronous events in LPM. Used for SS-USB power events. - clocks: a list of phandles to the controller clocks. Use as per @@ -36,6 +35,12 @@ Optional properties : - interrupt-names : Optional interrupt resource entries are: "pmic_id_irq" : Interrupt from PMIC for external ID pin notification. "ss_phy_irq" : Interrupt from super speed phy for wake up notification. + "hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM. + "dp_hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM + going through PDC. (use qcom,use-pdc-interrupts property) + "dm_hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM + going through PDC. (use qcom,use-pdc-interrupts property) + - clocks: a list of phandles to the controller clocks. Use as per Documentation/devicetree/bindings/clock/clock-bindings.txt - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" @@ -57,16 +62,26 @@ Optional properties : - qcom,core-clk-rate: If present, indicates clock frequency to be set for USB master clock. - qcom,core-clk-rate-hs: If present, indicates min core clock frequency required to support hs speed. +- qcom,use-pdc-interrupts: It present, it configures provided PDC IRQ with required + configuration for wakeup functionality. - extcon: phandles to external connector devices. First phandle should point to - external connector, which provide "USB" cable events, the second - should point to external connector device, which provide "USB-HOST" - cable events. A single phandle may be specified if a single connector - device provides both "USB" and "USB-HOST" events. + external connector, which provide type-C based "USB" cable events, the + second should point to external connector device, which provide type-C + "USB-HOST" cable events. A single phandle may be specified if a single + connector device provides both "USB" and "USB-HOST" events. An optional + third phandle may be specified for EUD based attach/detach events. A + mandatory fourth phandle has to be specified to provide microUSB based + "USB" cable events. An optional fifth phandle may be specified to provide + microUSB based "USB-HOST" cable events. Only the fourth phandle may be + specified if a single connector device provides both "USB" and "USB-HOST" + events. - qcom,num-gsi-evt-buffs: If present, specifies number of GSI based hardware accelerated event buffers. 1 event buffer is needed per h/w accelerated endpoint. - qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs, which is used as a vote by driver to get max performance in perf mode. - qcom,smmu-s1-bypass: If present, configure SMMU to bypass stage 1 translation. +- qcom,no-vbus-vote-with-type-C: If present, then do not try to get and enable VBUS + regulator in type-C host mode from dwc3-msm driver. Sub nodes: - Sub node for "DWC3- USB3 controller". diff --git a/Documentation/devicetree/bindings/usb/usb-device.txt b/Documentation/devicetree/bindings/usb/usb-device.txt index 1c35e7b665e1f8e9eb64dc6495f029a3d7c3ff64..03ab8f5eab40a6e8f712bd8dcb0f3c6af1847864 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.txt +++ b/Documentation/devicetree/bindings/usb/usb-device.txt @@ -11,7 +11,7 @@ Required properties: be used, but a device adhering to this binding may leave out all except for usbVID,PID. - reg: the port number which this device is connecting to, the range - is 1-31. + is 1-255. Example: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 3bdc896794b107283421b9042de5bd4a1d87f8f8..e996ba5d35169d2fe83612fdfe76f468358e19a4 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -24,6 +24,7 @@ ampire Ampire Co., Ltd. ams AMS AG amstaos AMS-Taos Inc. analogix Analogix Semiconductor, Inc. +android Google apm Applied Micro Circuits Corporation (APM) aptina Aptina Imaging arasan Arasan Chip Systems @@ -38,6 +39,7 @@ atmel Atmel Corporation auo AU Optronics Corporation auvidea Auvidea GmbH avago Avago Technologies +avia avia semiconductor avic Shanghai AVIC Optoelectronics Co., Ltd. axis Axis Communications AB boe BOE Technology Group Co., Ltd. @@ -270,6 +272,7 @@ sunchip Shenzhen Sunchip Technology Co., Ltd SUNW Sun Microsystems, Inc swir Sierra Wireless syna Synaptics Inc. +synaptics Synaptics Inc. synology Synology, Inc. tbs TBS Technologies tcg Trusted Computing Group diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbe1bcadf437f86ea604c2452e7f30d64605f498 --- /dev/null +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -0,0 +1,110 @@ +* Qualcomm Technologies Inc. WCNSS Platform Driver + +WCNSS driver is the platform driver. It is used for performing the cold +boot-up of the wireless device. It is responsible for adjusting +the necessary I/O rails and enabling appropriate gpios for wireless +connectivity subsystem. + +Required properties: +- compatible: "wcnss_wlan" +- reg: physical address and length of the register set for the device. +- reg-names: "wcnss_mmio", "wcnss_fiq", "pronto_phy_base", "riva_phy_base", + "riva_ccu_base", "pronto_a2xb_base", "pronto_ccpu_base", + "pronto_saw2_base", "wlan_tx_phy_aborts","wlan_brdg_err_source", + "wlan_tx_status", "alarms_txctl", "alarms_tactl", + "pronto_mcu_base", "pronto_qfuse". +- interupts: Pronto to Apps interrupts for tx done and rx pending. +- qcom,pronto-vddmx-supply: regulator to supply pronto pll. +- qcom,pronto-vddcx-supply: voltage corner regulator to supply WLAN/BT/FM +digital module. +- qcom,pronto-vddpx-supply: regulator to supply WLAN DAC. +- qcom,iris-vddxo-supply : regulator to supply RF XO. +- qcom,iris-vddrfa-supply : regulator to supply RFA digital. +- qcom,iris-vddpa-supply : regulator to supply RF PA. +- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM). +- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity +- qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF +- qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem +- qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs. +- qcom,wcnss-vadc: VADC handle for battery voltage notification APIs. +- pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt +- pinctrl-names : Names corresponding to the numbered pinctrl states +- clocks: from common clock binding: handle to xo, rf_clk and wcnss snoc clocks. +- clock-names: Names of all the clocks that are accessed by the subsystem +- qcom,vdd-voltage-level: This property represents (nominal, min, max) voltage +for iris and pronto regulators in milli-volts. +- qcom,vdd-current: This property represents current value for +iris and pronto regulators in micro-amps. + +Optional properties: +- qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect +should be performed during boot up. +- qcom,snoc-wcnss-clock-freq: indicates the wcnss snoc clock frequency in Hz. +If wcnss_snoc clock is specified in the list of clocks, this property needs +to be set to make it functional. +- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value, +using a smaller count for this buffer will reduce the memory usage. +- qcom,is-pronto-v3: boolean flag to determine the pronto hardware version +in use. subsequently correct workqueue will be used by DXE engine to push frames +in TX data path. +- qcom,is-dual-band-disable: boolean flag to determine the WLAN dual band +capability. +- qcom,is-pronto-vadc: boolean flag to determine Battery voltage feature +support for pronto hardware. +- qcom,wcnss-pm : +Power manager related parameter for LDO configuration. + 11 - WCN CORE rail LDO number + 21 - WCN PA rail LDO number + 1200 - WCN XO settling time (usec) + 1 - WCN RPM power collapse enabled + 1 - WCN standalone power collapse enabled + 6 - GPIO strength value +- qcom,has-vsys-adc-channel: boolean flag to determine which ADC HW channel need +to use for VBATT feature. +- qcom,has-a2xb-split-reg: boolean flag to determine A2xb split timeout limit +register is available or not. + +Example: + +qcom,wcnss-wlan@fb000000 { + compatible = "qcom,wcnss_wlan"; + reg = <0xfb000000 0x280000>, + <0xf9011008 0x04>; +reg-names = "wcnss_mmio", "wcnss_fiq"; + interrupts = <0 145 0 0 146 0>; + interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq"; + + qcom,pronto-vddmx-supply = <&pm8841_s1>; + qcom,pronto-vddcx-supply = <&pm8841_s2_corner>; + qcom,pronto-vddpx-supply = <&pm8941_s3>; + qcom,iris-vddxo-supply = <&pm8941_l6>; + qcom,iris-vddrfa-supply = <&pm8941_l11>; + qcom,iris-vddpa-supply = <&pm8941_l19>; + qcom,iris-vdddig-supply = <&pm8941_l3>; + + gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, + <&msmgpio 39 0>, <&msmgpio 40 0>; + qcom,has-48mhz-xo; + qcom,is-pronto-vt; + qcom,wlan-rx-buff-count = <512>; + qcom,has-pronto-hw; + qcom,wcnss-adc_tm = <&pm8226_adc_tm>; + + pinctrl-names = "wcnss_default", "wcnss_sleep"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; + pinctrl-2 = <&wcnss_gpio_default>; + + clocks = <&clock_rpm clk_xo_wlan_clk>, + <&clock_rpm clk_rf_clk2>, + <&clock_debug clk_gcc_debug_mux>, + <&clock_gcc clk_wcnss_m_clk>, + <&clock_gcc clk_snoc_wcnss_a_clk>; + + clock-names = "xo", "rf_clk", "measure", "wcnss_debug", + "snoc_wcnss"; + + qcom,snoc-wcnss-clock-freq = <200000000>; + qcom,wcnss-pm = <11 21 1200 1 1 6>; +}; diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 6e027ae50d7e392d8ef1e1bc946b8cb30b5072f4..ea409279ee5d96c4cfedf2ccc0532dcc110e4948 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -138,6 +138,7 @@ Table 1-1: Process specific entries in /proc maps Memory maps to executables and library files (2.4) mem Memory held by this process root Link to the root directory of this process + reclaim Reclaim pages in this process stat Process status statm Process memory status information status Process status in human readable form @@ -528,6 +529,25 @@ current value: Any other value written to /proc/PID/clear_refs will have no effect. +The file /proc/PID/reclaim is used to reclaim pages in this process. +To reclaim file-backed pages, + > echo file > /proc/PID/reclaim + +To reclaim anonymous pages, + > echo anon > /proc/PID/reclaim + +To reclaim all pages, + > echo all > /proc/PID/reclaim + +Also, you can specify address range of process so part of address space +will be reclaimed. The format is following as + > echo addr size-byte > /proc/PID/reclaim + +NOTE: addr should be page-aligned. + +Below is example which try to reclaim 2M from 0x100000. + > echo 0x100000 2M > /proc/PID/reclaim + The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags using /proc/kpageflags and number of times a page is mapped using /proc/kpagecount. For detailed explanation, see Documentation/vm/pagemap.txt. diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 53b872c105d24f0741e06f463ab2fdadbb0c01cd..db86cda6fa349cbd9cc1f3e585d2b9e849cd9bb9 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -308,6 +308,12 @@ Color Management Properties .. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c :export: +Explicit Fencing Properties +--------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_atomic.c + :doc: explicit fencing properties + Existing KMS Properties ----------------------- diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 852796556f38a17c1a9ee4e451748777349167fb..9f5bfd6a7005aac7a854596ac34acf3d2a882036 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2707,6 +2707,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. nosmt [KNL,S390] Disable symmetric multithreading (SMT). Equivalent to smt=1. + nospectre_v2 [X86] Disable all mitigations for the Spectre variant 2 + (indirect branch prediction) vulnerability. System may + allow data leaks with this option, which is equivalent + to spectre_v2=off. + noxsave [BUGS=X86] Disables x86 extended register state save and restore using xsave. The kernel will fallback to enabling legacy floating-point and sse state. @@ -2811,6 +2816,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. nopat [X86] Disable PAT (page attribute table extension of pagetables) support. + nopcid [X86-64] Disable the PCID cpu feature. + norandmaps Don't use address space randomization. Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space @@ -3339,6 +3346,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted. pt. [PARIDE] See Documentation/blockdev/paride.txt. + pti= [X86_64] Control Page Table Isolation of user and + kernel address spaces. Disabling this feature + removes hardening, but improves performance of + system calls and interrupts. + + on - unconditionally enable + off - unconditionally disable + auto - kernel detects whether your CPU model is + vulnerable to issues that PTI mitigates + + Not specifying this option is equivalent to pti=auto. + + nopti [X86_64] + Equivalent to pti=off + pty.legacy_count= [KNL] Number of legacy pty's. Overwrites compiled-in default number. @@ -3943,11 +3965,41 @@ bytes respectively. Such letter suffixes can also be entirely omitted. sonypi.*= [HW] Sony Programmable I/O Control Device driver See Documentation/laptops/sonypi.txt + spectre_v2= [X86] Control mitigation of Spectre variant 2 + (indirect branch speculation) vulnerability. + + on - unconditionally enable + off - unconditionally disable + auto - kernel detects whether your CPU model is + vulnerable + + Selecting 'on' will, and 'auto' may, choose a + mitigation method at run time according to the + CPU, the available microcode, the setting of the + CONFIG_RETPOLINE configuration option, and the + compiler with which the kernel was built. + + Specific mitigations can also be selected manually: + + retpoline - replace indirect branches + retpoline,generic - google's original retpoline + retpoline,amd - AMD-specific minimal thunk + + Not specifying this option is equivalent to + spectre_v2=auto. + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr= spia_peddr= + stack_guard_gap= [MM] + override the default stack gap protection. The value + is in page units and it defines how many pages prior + to (for stacks growing down) resp. after (for stacks + growing up) the main stack are reserved for no other + mapping. Default value is 256 pages. + stacktrace [FTRACE] Enabled the stack tracer on boot up. diff --git a/Documentation/misc-devices/qcom_invoke_driver.txt b/Documentation/misc-devices/qcom_invoke_driver.txt new file mode 100644 index 0000000000000000000000000000000000000000..38c976af5f8d82fe17601ed7cd70fba923e483eb --- /dev/null +++ b/Documentation/misc-devices/qcom_invoke_driver.txt @@ -0,0 +1,54 @@ +Introduction: +============= +Invoke driver is a misc driver which helps communication between non secure +and secure world. Invoke driver communicates with secure side using SCM +driver. To use invoke driver, open must be called on invoke device i.e. +/dev/invoke. Invoke driver exposes only one IOCTL invoke which passes +userspace request to TZ. + +SW Architecture +=============== +Following is SW stack for Invoke driver. + ++++++++++++++++++++++++++++++++++++++++++ ++ Applications + ++++++++++++++++++++++++++++++++++++++++++ ++ System Layer + ++++++++++++++++++++++++++++++++++++++++++ ++ Kernel + ++ +++++++++++++++++++ + ++ + Invoke driver + + ++ +++++++++++++++++++ + ++ + SCM Driver + + ++++++++++++++++++++++++++++++++++++++++++ + || + || + \/ ++++++++++++++++++++++++++++++++++++++++++ ++ Trust Zone + ++ +++++++++++ +++++++++++ + ++ + TZ App1 + + TZ App2 + + ++++++++++++++++++++++++++++++++++++++++++ + + +Interfaces +========== +Invoke driver exposes INVOKE_IOCTL_INVOKE_REQ IOCTL for userspace to +communicate with driver. More details of IOCTL are avilable in +corresponding header file. + + +Driver Parameters +================= +This driver is built and statically linked into the kernel; therefore, +there are no module parameters supported by this driver. + +There are no kernel command line parameters supported by this driver. + +Power Management +================ +TBD + +Dependencies +============ +Invoke driver depends on SCM driver to communicate with TZ. diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 0f0fc7d24ec2a08d68e2a6ffc5476392564d3231..7058d43ca48af52702920426ab7a8a31428bc80a 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -858,6 +858,11 @@ ip_local_reserved_ports - list of comma separated ranges Default: Empty +reserved_port_bind - BOOLEAN + If set, allows explicit bind requests to applications requesting + any port within the range of ip_local_reserved_ports. + Default: 1 + ip_nonlocal_bind - BOOLEAN If set, allows processes to bind() to non-local IP addresses, which can be quite useful - but may break some applications. @@ -1283,6 +1288,10 @@ igmp_link_local_mcast_reports - BOOLEAN 224.0.0.X range. Default TRUE +nf_ipv4_defrag_skip - BOOLEAN + Skip defragmentation per interface if set. + Default : 0 (always defrag) + Alexey Kuznetsov. kuznet@ms2.inr.ac.ru diff --git a/Documentation/timers/timer_stats.txt b/Documentation/timers/timer_stats.txt deleted file mode 100644 index de835ee974550e5d8aa864b40cb038d5adeee14d..0000000000000000000000000000000000000000 --- a/Documentation/timers/timer_stats.txt +++ /dev/null @@ -1,73 +0,0 @@ -timer_stats - timer usage statistics ------------------------------------- - -timer_stats is a debugging facility to make the timer (ab)usage in a Linux -system visible to kernel and userspace developers. If enabled in the config -but not used it has almost zero runtime overhead, and a relatively small -data structure overhead. Even if collection is enabled runtime all the -locking is per-CPU and lookup is hashed. - -timer_stats should be used by kernel and userspace developers to verify that -their code does not make unduly use of timers. This helps to avoid unnecessary -wakeups, which should be avoided to optimize power consumption. - -It can be enabled by CONFIG_TIMER_STATS in the "Kernel hacking" configuration -section. - -timer_stats collects information about the timer events which are fired in a -Linux system over a sample period: - -- the pid of the task(process) which initialized the timer -- the name of the process which initialized the timer -- the function where the timer was initialized -- the callback function which is associated to the timer -- the number of events (callbacks) - -timer_stats adds an entry to /proc: /proc/timer_stats - -This entry is used to control the statistics functionality and to read out the -sampled information. - -The timer_stats functionality is inactive on bootup. - -To activate a sample period issue: -# echo 1 >/proc/timer_stats - -To stop a sample period issue: -# echo 0 >/proc/timer_stats - -The statistics can be retrieved by: -# cat /proc/timer_stats - -While sampling is enabled, each readout from /proc/timer_stats will see -newly updated statistics. Once sampling is disabled, the sampled information -is kept until a new sample period is started. This allows multiple readouts. - -Sample output of /proc/timer_stats: - -Timerstats sample period: 3.888770 s - 12, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) - 15, 1 swapper hcd_submit_urb (rh_timer_func) - 4, 959 kedac schedule_timeout (process_timeout) - 1, 0 swapper page_writeback_init (wb_timer_fn) - 28, 0 swapper hrtimer_stop_sched_tick (hrtimer_sched_tick) - 22, 2948 IRQ 4 tty_flip_buffer_push (delayed_work_timer_fn) - 3, 3100 bash schedule_timeout (process_timeout) - 1, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) - 1, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) - 1, 1 swapper neigh_table_init_no_netlink (neigh_periodic_timer) - 1, 2292 ip __netdev_watchdog_up (dev_watchdog) - 1, 23 events/1 do_cache_clean (delayed_work_timer_fn) -90 total events, 30.0 events/sec - -The first column is the number of events, the second column the pid, the third -column is the name of the process. The forth column shows the function which -initialized the timer and in parenthesis the callback function which was -executed on expiry. - - Thomas, Ingo - -Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable -timer will appear as follows - 10D, 1 swapper queue_delayed_work_on (delayed_work_timer_fn) - diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt new file mode 100644 index 0000000000000000000000000000000000000000..d11eff61fc9addf6cd0ad54db5b30bac73783503 --- /dev/null +++ b/Documentation/x86/pti.txt @@ -0,0 +1,186 @@ +Overview +======== + +Page Table Isolation (pti, previously known as KAISER[1]) is a +countermeasure against attacks on the shared user/kernel address +space such as the "Meltdown" approach[2]. + +To mitigate this class of attacks, we create an independent set of +page tables for use only when running userspace applications. When +the kernel is entered via syscalls, interrupts or exceptions, the +page tables are switched to the full "kernel" copy. When the system +switches back to user mode, the user copy is used again. + +The userspace page tables contain only a minimal amount of kernel +data: only what is needed to enter/exit the kernel such as the +entry/exit functions themselves and the interrupt descriptor table +(IDT). There are a few strictly unnecessary things that get mapped +such as the first C function when entering an interrupt (see +comments in pti.c). + +This approach helps to ensure that side-channel attacks leveraging +the paging structures do not function when PTI is enabled. It can be +enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time. +Once enabled at compile-time, it can be disabled at boot with the +'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt). + +Page Table Management +===================== + +When PTI is enabled, the kernel manages two sets of page tables. +The first set is very similar to the single set which is present in +kernels without PTI. This includes a complete mapping of userspace +that the kernel can use for things like copy_to_user(). + +Although _complete_, the user portion of the kernel page tables is +crippled by setting the NX bit in the top level. This ensures +that any missed kernel->user CR3 switch will immediately crash +userspace upon executing its first instruction. + +The userspace page tables map only the kernel data needed to enter +and exit the kernel. This data is entirely contained in the 'struct +cpu_entry_area' structure which is placed in the fixmap which gives +each CPU's copy of the area a compile-time-fixed virtual address. + +For new userspace mappings, the kernel makes the entries in its +page tables like normal. The only difference is when the kernel +makes entries in the top (PGD) level. In addition to setting the +entry in the main kernel PGD, a copy of the entry is made in the +userspace page tables' PGD. + +This sharing at the PGD level also inherently shares all the lower +layers of the page tables. This leaves a single, shared set of +userspace page tables to manage. One PTE to lock, one set of +accessed bits, dirty bits, etc... + +Overhead +======== + +Protection against side-channel attacks is important. But, +this protection comes at a cost: + +1. Increased Memory Use + a. Each process now needs an order-1 PGD instead of order-0. + (Consumes an additional 4k per process). + b. The 'cpu_entry_area' structure must be 2MB in size and 2MB + aligned so that it can be mapped by setting a single PMD + entry. This consumes nearly 2MB of RAM once the kernel + is decompressed, but no space in the kernel image itself. + +2. Runtime Cost + a. CR3 manipulation to switch between the page table copies + must be done at interrupt, syscall, and exception entry + and exit (it can be skipped when the kernel is interrupted, + though.) Moves to CR3 are on the order of a hundred + cycles, and are required at every entry and exit. + b. A "trampoline" must be used for SYSCALL entry. This + trampoline depends on a smaller set of resources than the + non-PTI SYSCALL entry code, so requires mapping fewer + things into the userspace page tables. The downside is + that stacks must be switched at entry time. + d. Global pages are disabled for all kernel structures not + mapped into both kernel and userspace page tables. This + feature of the MMU allows different processes to share TLB + entries mapping the kernel. Losing the feature means more + TLB misses after a context switch. The actual loss of + performance is very small, however, never exceeding 1%. + d. Process Context IDentifiers (PCID) is a CPU feature that + allows us to skip flushing the entire TLB when switching page + tables by setting a special bit in CR3 when the page tables + are changed. This makes switching the page tables (at context + switch, or kernel entry/exit) cheaper. But, on systems with + PCID support, the context switch code must flush both the user + and kernel entries out of the TLB. The user PCID TLB flush is + deferred until the exit to userspace, minimizing the cost. + See intel.com/sdm for the gory PCID/INVPCID details. + e. The userspace page tables must be populated for each new + process. Even without PTI, the shared kernel mappings + are created by copying top-level (PGD) entries into each + new process. But, with PTI, there are now *two* kernel + mappings: one in the kernel page tables that maps everything + and one for the entry/exit structures. At fork(), we need to + copy both. + f. In addition to the fork()-time copying, there must also + be an update to the userspace PGD any time a set_pgd() is done + on a PGD used to map userspace. This ensures that the kernel + and userspace copies always map the same userspace + memory. + g. On systems without PCID support, each CR3 write flushes + the entire TLB. That means that each syscall, interrupt + or exception flushes the TLB. + h. INVPCID is a TLB-flushing instruction which allows flushing + of TLB entries for non-current PCIDs. Some systems support + PCIDs, but do not support INVPCID. On these systems, addresses + can only be flushed from the TLB for the current PCID. When + flushing a kernel address, we need to flush all PCIDs, so a + single kernel address flush will require a TLB-flushing CR3 + write upon the next use of every PCID. + +Possible Future Work +==================== +1. We can be more careful about not actually writing to CR3 + unless its value is actually changed. +2. Allow PTI to be enabled/disabled at runtime in addition to the + boot-time switching. + +Testing +======== + +To test stability of PTI, the following test procedure is recommended, +ideally doing all of these in parallel: + +1. Set CONFIG_DEBUG_ENTRY=y +2. Run several copies of all of the tools/testing/selftests/x86/ tests + (excluding MPX and protection_keys) in a loop on multiple CPUs for + several minutes. These tests frequently uncover corner cases in the + kernel entry code. In general, old kernels might cause these tests + themselves to crash, but they should never crash the kernel. +3. Run the 'perf' tool in a mode (top or record) that generates many + frequent performance monitoring non-maskable interrupts (see "NMI" + in /proc/interrupts). This exercises the NMI entry/exit code which + is known to trigger bugs in code paths that did not expect to be + interrupted, including nested NMIs. Using "-c" boosts the rate of + NMIs, and using two -c with separate counters encourages nested NMIs + and less deterministic behavior. + + while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done + +4. Launch a KVM virtual machine. +5. Run 32-bit binaries on systems supporting the SYSCALL instruction. + This has been a lightly-tested code path and needs extra scrutiny. + +Debugging +========= + +Bugs in PTI cause a few different signatures of crashes +that are worth noting here. + + * Failures of the selftests/x86 code. Usually a bug in one of the + more obscure corners of entry_64.S + * Crashes in early boot, especially around CPU bringup. Bugs + in the trampoline code or mappings cause these. + * Crashes at the first interrupt. Caused by bugs in entry_64.S, + like screwing up a page table switch. Also caused by + incorrectly mapping the IRQ handler entry code. + * Crashes at the first NMI. The NMI code is separate from main + interrupt handlers and can have bugs that do not affect + normal interrupts. Also caused by incorrectly mapping NMI + code. NMIs that interrupt the entry code must be very + careful and can be the cause of crashes that show up when + running perf. + * Kernel crashes at the first exit to userspace. entry_64.S + bugs, or failing to map some of the exit code. + * Crashes at first interrupt that interrupts userspace. The paths + in entry_64.S that return to userspace are sometimes separate + from the ones that return to the kernel. + * Double faults: overflowing the kernel stack because of page + faults upon page faults. Caused by touching non-pti-mapped + data in the entry code, or forgetting to switch to kernel + CR3 before calling into C functions which are not pti-mapped. + * Userspace segfaults early in boot, sometimes manifesting + as mount(8) failing to mount the rootfs. These have + tended to be TLB invalidation issues. Usually invalidating + the wrong PCID, or otherwise missing an invalidation. + +1. https://gruss.cc/files/kaiser.pdf +2. https://meltdownattack.com/meltdown.pdf diff --git a/Makefile b/Makefile index 2b8f550bc8dbaa4fc53f95573a3df00df4b46168..cf9657ec0e1ff54ef5346f4d1b48566c192372d2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 25 +SUBLEVEL = 77 EXTRAVERSION = NAME = Roaring Lionus @@ -374,9 +374,6 @@ LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = LDFLAGS_vmlinux = -CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disable-warning,maybe-uninitialized,) -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) - # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE := \ @@ -397,21 +394,19 @@ LINUXINCLUDE := \ LINUXINCLUDE += $(filter-out $(LINUXINCLUDE),$(USERINCLUDE)) -KBUILD_CPPFLAGS := -D__KERNEL__ - +KBUILD_AFLAGS := -D__ASSEMBLY__ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common \ -Werror-implicit-function-declaration \ -Wno-format-security \ - -std=gnu89 $(call cc-option,-fno-PIE) - - + -std=gnu89 +KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_AFLAGS_KERNEL := KBUILD_CFLAGS_KERNEL := -KBUILD_AFLAGS := -D__ASSEMBLY__ $(call cc-option,-fno-PIE) KBUILD_AFLAGS_MODULE := -DMODULE KBUILD_CFLAGS_MODULE := -DMODULE KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds +GCC_PLUGINS_CFLAGS := # Read KERNELRELEASE from include/config/kernel.release (if it exists) KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) @@ -424,7 +419,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS -export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN +export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_KASAN CFLAGS_UBSAN export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL @@ -565,7 +560,7 @@ scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \ # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ -drivers-y := drivers/ sound/ firmware/ +drivers-y := drivers/ sound/ firmware/ techpack/ net-y := net/ libs-y := lib/ core-y := usr/ @@ -624,6 +619,12 @@ endif # Defaults to vmlinux, but the arch makefile usually adds further targets all: vmlinux +KBUILD_CFLAGS += $(call cc-option,-fno-PIE) +KBUILD_AFLAGS += $(call cc-option,-fno-PIE) +CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disable-warning,maybe-uninitialized,) +CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) +export CFLAGS_GCOV CFLAGS_KCOV + # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default # values of the respective KBUILD_* variables ARCH_CPPFLAGS := @@ -633,6 +634,9 @@ include arch/$(SRCARCH)/Makefile KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) +KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) +KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) +KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context) ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,) @@ -655,6 +659,12 @@ KBUILD_CFLAGS += $(call cc-ifversion, -lt, 0409, \ # Tell gcc to never replace conditional load with a non-conditional one KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) +# check for 'asm goto' +ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y) + KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO + KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO +endif + include scripts/Makefile.gcc-plugins ifdef CONFIG_READABLE_ASM @@ -782,6 +792,9 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) +# Make sure -fstack-check isn't enabled (like gentoo apparently did) +KBUILD_CFLAGS += $(call cc-option,-fno-stack-check,) + # conserve stack if available KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) @@ -800,12 +813,6 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types) # use the deterministic mode of AR if available KBUILD_ARFLAGS := $(call ar-option,D) -# check for 'asm goto' -ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) - KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO - KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO -endif - include scripts/Makefile.kasan include scripts/Makefile.extrawarn include scripts/Makefile.ubsan @@ -1152,6 +1159,7 @@ headers_install: __headers $(error Headers not exportable for the $(SRCARCH) architecture)) $(Q)$(MAKE) $(hdr-inst)=include/uapi $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) + $(Q)$(MAKE) $(hdr-inst)=techpack PHONY += headers_check_all headers_check_all: headers_install_all @@ -1161,6 +1169,7 @@ PHONY += headers_check headers_check: headers_install $(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1 $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) HDRCHECK=1 + $(Q)$(MAKE) $(hdr-inst)=techpack HDRCHECK=1 # --------------------------------------------------------------------------- # Kernel selftest diff --git a/arch/Kconfig b/arch/Kconfig index 659bdd079277ebdbec01f8a5c9dd38af1a19c888..a364ecec958e34d9cc56628e8b780bc2e6a46684 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -218,6 +218,20 @@ config GENERIC_SMP_IDLE_THREAD config GENERIC_IDLE_POLL_SETUP bool +config ARCH_HAS_FORTIFY_SOURCE + bool + help + An architecture should select this when it can successfully + build and run with CONFIG_FORTIFY_SOURCE. + +config FORTIFY_COMPILE_CHECK + depends on ARCH_HAS_FORTIFY_SOURCE + bool + help + Disable compile time size check for string routines as part + of fortify source. Selecting this option will not enforce compile + time size check for string functions. + # Select if arch init_task initializer is different to init/init_task.c config ARCH_INIT_TASK bool diff --git a/arch/alpha/include/asm/types.h b/arch/alpha/include/asm/types.h index 4cb4b6d3452c0b3439c3aa3c0f928f74de09fb3a..0bc66e1d3a7e9c81f1cca84943f60cd91d85a625 100644 --- a/arch/alpha/include/asm/types.h +++ b/arch/alpha/include/asm/types.h @@ -1,6 +1,6 @@ #ifndef _ALPHA_TYPES_H #define _ALPHA_TYPES_H -#include +#include #endif /* _ALPHA_TYPES_H */ diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index 9e46d6e656d978cd203abe4202f8b1ee353bea90..fa47df6a953aa82cde9f1718b6bff447c84dee6f 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -97,4 +97,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/alpha/include/uapi/asm/types.h b/arch/alpha/include/uapi/asm/types.h index 9fd3cd459777767e7c80c4c761ee88278f62b17d..8d1024d7be0546bc744adf163e87f9dc723539fe 100644 --- a/arch/alpha/include/uapi/asm/types.h +++ b/arch/alpha/include/uapi/asm/types.h @@ -9,8 +9,18 @@ * need to be careful to avoid a name clashes. */ -#ifndef __KERNEL__ +/* + * This is here because we used to use l64 for alpha + * and we don't want to impact user mode with our change to ll64 + * in the kernel. + * + * However, some user programs are fine with this. They can + * flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here. + */ +#if !defined(__SANE_USERSPACE_TYPES__) && !defined(__KERNEL__) #include +#else +#include #endif #endif /* _UAPI_ALPHA_TYPES_H */ diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index ffb93f499c834375237c0305760326fd32edf76d..4f95577b01804422d0c5e55ce2856cb6b856dbcc 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1188,8 +1188,10 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur))) return -EFAULT; - err = 0; - err |= put_user(status, ustatus); + err = put_user(status, ustatus); + if (ret < 0) + return err ? err : ret; + err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec); err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec); err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec); diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index b65930a4958959fb65891ac375a7637a0e5cb146..54b54da6384c197a93848e05ef292c224f5c0f91 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -17,10 +17,11 @@ #include #include +#define ATOMIC_INIT(i) { (i) } + #ifndef CONFIG_ARC_PLAT_EZNPS #define atomic_read(v) READ_ONCE((v)->counter) -#define ATOMIC_INIT(i) { (i) } #ifdef CONFIG_ARC_HAS_LLSC diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index b3410ff6a62dbcc589ffa411f326d6954c8ba80c..4fd6272e6c01b4d03a8b0e155f6ef80e67bbd6ee 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -89,7 +89,9 @@ extern unsigned long perip_base, perip_end; #define ARC_REG_SLC_FLUSH 0x904 #define ARC_REG_SLC_INVALIDATE 0x905 #define ARC_REG_SLC_RGN_START 0x914 +#define ARC_REG_SLC_RGN_START1 0x915 #define ARC_REG_SLC_RGN_END 0x916 +#define ARC_REG_SLC_RGN_END1 0x917 /* Bit val in SLC_CONTROL */ #define SLC_CTRL_IM 0x040 diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h index b5ff87e6f4b71352fc8990624114c025b6c5ccb0..aee1a77934cf694e37ae579347a37bc167e43762 100644 --- a/arch/arc/include/asm/entry-arcv2.h +++ b/arch/arc/include/asm/entry-arcv2.h @@ -16,6 +16,7 @@ ; ; Now manually save: r12, sp, fp, gp, r25 + PUSH r30 PUSH r12 ; Saving pt_regs->sp correctly requires some extra work due to the way @@ -72,6 +73,7 @@ POPAX AUX_USER_SP 1: POP r12 + POP r30 .endm diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 69095da1fcfd1e35f16234aaf473896194064d38..47111d565a959d117ab9e2c7c9eea3b852137971 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -84,7 +84,7 @@ struct pt_regs { unsigned long fp; unsigned long sp; /* user/kernel sp depending on where we came from */ - unsigned long r12; + unsigned long r12, r30; /*------- Below list auto saved by h/w -----------*/ unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; diff --git a/arch/arc/include/asm/uaccess.h b/arch/arc/include/asm/uaccess.h index 41faf17cd28d2ced7461f4e6860d2456fb49f8ae..0684fd2f42e8754df81eb5953084f8d45c5d65a1 100644 --- a/arch/arc/include/asm/uaccess.h +++ b/arch/arc/include/asm/uaccess.h @@ -673,6 +673,7 @@ __arc_strncpy_from_user(char *dst, const char __user *src, long count) return 0; __asm__ __volatile__( + " mov lp_count, %5 \n" " lp 3f \n" "1: ldb.ab %3, [%2, 1] \n" " breq.d %3, 0, 3f \n" @@ -689,8 +690,8 @@ __arc_strncpy_from_user(char *dst, const char __user *src, long count) " .word 1b, 4b \n" " .previous \n" : "+r"(res), "+r"(dst), "+r"(src), "=r"(val) - : "g"(-EFAULT), "l"(count) - : "memory"); + : "g"(-EFAULT), "r"(count) + : "lp_count", "lp_start", "lp_end", "memory"); return res; } diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S index 1eea99beecc3b016c0f9d13129da65c26d333c30..85d9ea4a0acccc937a1cf51b29fc0480afa4010d 100644 --- a/arch/arc/kernel/entry.S +++ b/arch/arc/kernel/entry.S @@ -92,6 +92,12 @@ ENTRY(EV_MachineCheck) lr r0, [efa] mov r1, sp + ; hardware auto-disables MMU, re-enable it to allow kernel vaddr + ; access for say stack unwinding of modules for crash dumps + lr r3, [ARC_REG_PID] + or r3, r3, MMU_ENABLE + sr r3, [ARC_REG_PID] + lsr r3, r2, 8 bmsk r3, r3, 7 brne r3, ECR_C_MCHK_DUP_TLB, 1f diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S index 689dd867fdff53eeafa0d01d980ecf425f66a759..8b90d25a15cca8ebd334402848d98aa22f07b8bf 100644 --- a/arch/arc/kernel/head.S +++ b/arch/arc/kernel/head.S @@ -71,14 +71,14 @@ ENTRY(stext) GET_CPU_ID r5 cmp r5, 0 mov.nz r0, r5 -#ifdef CONFIG_ARC_SMP_HALT_ON_RESET - ; Non-Master can proceed as system would be booted sufficiently - jnz first_lines_of_secondary -#else + bz .Lmaster_proceed + ; Non-Masters wait for Master to boot enough and bring them up - jnz arc_platform_smp_wait_to_boot -#endif - ; Master falls thru + ; when they resume, tail-call to entry point + mov blink, @first_lines_of_secondary + j arc_platform_smp_wait_to_boot + +.Lmaster_proceed: #endif ; Clear BSS before updating any globals diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f39142acc89e032627ef88431ac4775e71949ed2..be131b296a55f0556706e03365cca8f1b4ce0f8b 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -221,10 +222,13 @@ static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + struct irq_chip *core_chip = irq_desc_get_chip(desc); irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + chained_irq_enter(core_chip, desc); generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); + chained_irq_exit(core_chip, desc); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 88674d972c9d056f33f87205aa77049c11006129..2afbafadb6ab529ebaa7af4e367d733fc7837e1e 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -90,22 +90,37 @@ void __init smp_cpus_done(unsigned int max_cpus) */ static volatile int wake_flag; +#ifdef CONFIG_ISA_ARCOMPACT + +#define __boot_read(f) f +#define __boot_write(f, v) f = v + +#else + +#define __boot_read(f) arc_read_uncached_32(&f) +#define __boot_write(f, v) arc_write_uncached_32(&f, v) + +#endif + static void arc_default_smp_cpu_kick(int cpu, unsigned long pc) { BUG_ON(cpu == 0); - wake_flag = cpu; + + __boot_write(wake_flag, cpu); } void arc_platform_smp_wait_to_boot(int cpu) { - while (wake_flag != cpu) + /* for halt-on-reset, we've waited already */ + if (IS_ENABLED(CONFIG_ARC_SMP_HALT_ON_RESET)) + return; + + while (__boot_read(wake_flag) != cpu) ; - wake_flag = 0; - __asm__ __volatile__("j @first_lines_of_secondary \n"); + __boot_write(wake_flag, 0); } - const char *arc_platform_smp_cpuinfo(void) { return plat_smp_ops.info ? : ""; diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 8147583c44340f1a5d5be60ce70d77327a90dcff..bbdfeb31dee6acc73f700cc33de4ee8631cbe507 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -562,6 +562,7 @@ noinline void slc_op(phys_addr_t paddr, unsigned long sz, const int op) static DEFINE_SPINLOCK(lock); unsigned long flags; unsigned int ctrl; + phys_addr_t end; spin_lock_irqsave(&lock, flags); @@ -591,8 +592,16 @@ noinline void slc_op(phys_addr_t paddr, unsigned long sz, const int op) * END needs to be setup before START (latter triggers the operation) * END can't be same as START, so add (l2_line_sz - 1) to sz */ - write_aux_reg(ARC_REG_SLC_RGN_END, (paddr + sz + l2_line_sz - 1)); - write_aux_reg(ARC_REG_SLC_RGN_START, paddr); + end = paddr + sz + l2_line_sz - 1; + if (is_pae40_enabled()) + write_aux_reg(ARC_REG_SLC_RGN_END1, upper_32_bits(end)); + + write_aux_reg(ARC_REG_SLC_RGN_END, lower_32_bits(end)); + + if (is_pae40_enabled()) + write_aux_reg(ARC_REG_SLC_RGN_START1, upper_32_bits(paddr)); + + write_aux_reg(ARC_REG_SLC_RGN_START, lower_32_bits(paddr)); while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY); diff --git a/arch/arc/mm/mmap.c b/arch/arc/mm/mmap.c index 2e06d56e987bf84c773b01bbfa6a7b4af1ac6fc9..cf4ae6958240074d265b4f26cb6f0d4271105b92 100644 --- a/arch/arc/mm/mmap.c +++ b/arch/arc/mm/mmap.c @@ -64,7 +64,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index bdb295e09160b2037c9dd90058963800cbe78d08..a4dc881da27721d67a4a4fb830bf294b376fe734 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -896,9 +896,6 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address, local_irq_save(flags); - /* re-enable the MMU */ - write_aux_reg(ARC_REG_PID, MMU_ENABLE | read_aux_reg(ARC_REG_PID)); - /* loop thru all sets of TLB */ for (set = 0; set < mmu->sets; set++) { diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d04e168db9c4a08b97537543a675f79662c7d0a7..d8d8b829fc6ce1186da3e180a16cdd273a85d365 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -55,6 +55,7 @@ config ARM select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) + select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS select HAVE_GENERIC_DMA_COHERENT select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) @@ -117,7 +118,7 @@ if ARM_DMA_USE_IOMMU config ARM_DMA_IOMMU_ALIGNMENT int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers" range 4 9 - default 8 + default 9 help DMA mapping framework by default aligns all buffers to the smallest PAGE_SIZE order which is greater than or equal to the requested buffer @@ -230,6 +231,9 @@ config NEED_RET_TO_USER config ARCH_MTD_XIP bool +config ARCH_WANT_KMAP_ATOMIC_FLUSH + bool + config VECTORS_BASE hex default 0xffff0000 if MMU || CPU_HIGH_VECTOR @@ -567,6 +571,8 @@ config ARCH_QCOM select SPARSE_IRQ select USE_OF select PINCTRL + select ARCH_WANT_KMAP_ATOMIC_FLUSH + select SND_SOC_COMPRESS help Support for Qualcomm MSM/QSD based systems. This runs on the apps processor of the MSM/QSD and depends on a shared memory @@ -1482,6 +1488,7 @@ config NR_CPUS config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" + select GENERIC_IRQ_MIGRATION depends on SMP help Say Y here to experiment with turning CPUs off and on. CPUs @@ -1760,6 +1767,29 @@ config ARM_MODULE_PLTS source "mm/Kconfig" +choice + prompt "Virtual Memory Reclaim" + default NO_VM_RECLAIM + help + Select the method of reclaiming virtual memory + +config ENABLE_VMALLOC_SAVING + bool "Reclaim memory for each subsystem" + help + Enable this config to reclaim the virtual space belonging + to any subsystem which is expected to have a lifetime of + the entire system. This feature allows lowmem to be non- + contiguous. + +config NO_VM_RECLAIM + bool "Do not reclaim memory" + help + Do not reclaim any memory. This might result in less lowmem + and wasting virtual memory space which could otherwise be + reclaimed by using any of the other two config options. + +endchoice + config FORCE_MAX_ZONEORDER int "Maximum zone order" default "12" if SOC_AM33XX diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu index aed66d5df7f1546ac48cf93ee9c4f2aeb91d5b76..b7576349528c12a8ef7533b6b66bc9a68b8dc9f9 100644 --- a/arch/arm/Kconfig-nommu +++ b/arch/arm/Kconfig-nommu @@ -34,8 +34,7 @@ config PROCESSOR_ID used instead of the auto-probing which utilizes the register. config REMAP_VECTORS_TO_RAM - bool 'Install vectors to the beginning of RAM' if DRAM_BASE - depends on DRAM_BASE + bool 'Install vectors to the beginning of RAM' help The kernel needs to change the hardware exception vectors. In nommu mode, the hardware exception vectors are normally diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 771896fd25d5ecd50bff11f8505e0b5e9758964c..9ce6b7fda7312e0c4edc094a7ce84bc9406d2b08 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -62,6 +62,21 @@ config DEBUG_USER 8 - SIGSEGV faults 16 - SIGBUS faults +config ARCH_SUPPORTS_DEBUG_PAGEALLOC + def_bool y + depends on FORCE_PAGES + +config FORCE_PAGES + bool "Force lowmem to be mapped with 4K pages" + help + There are some advanced debug features that can only be done when + memory is mapped with pages instead of sections. Enable this option + to always map lowmem pages with pages. This may have a performance + cost due to increased TLB pressure. + + If unsure say N. + + # These options are only for real kernel hackers who want to get their hands dirty. config DEBUG_LL bool "Kernel low-level debugging functions (read help!)" diff --git a/arch/arm/boot/dts/am335x-chilisom.dtsi b/arch/arm/boot/dts/am335x-chilisom.dtsi index f9ee5859c154ade0b5858ad97373277389b2b31a..1b43ebd08b38106a92ccc088998ef9f3cf51bab7 100644 --- a/arch/arm/boot/dts/am335x-chilisom.dtsi +++ b/arch/arm/boot/dts/am335x-chilisom.dtsi @@ -124,6 +124,14 @@ &rtc { system-power-controller; + + pinctrl-0 = <&ext_wakeup>; + pinctrl-names = "default"; + + ext_wakeup: ext-wakeup { + pins = "ext_wakeup0"; + input-enable; + }; }; /* NAND Flash */ diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 975c36e332a2583e778d3dc41390ed67577693c8..8e6b3938bef9f6c135f63003f34ed9f26dbb2e5b 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -668,6 +668,7 @@ ti,non-removable; bus-width = <4>; cap-power-off-card; + keep-power-in-suspend; pinctrl-names = "default"; pinctrl-0 = <&mmc2_pins>; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 795c1467fa50311402fd7fb8d7dabda94081b022..a3277e6436d5959a86cbf8085663a176eba23558 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -143,10 +143,11 @@ }; scm_conf: scm_conf@0 { - compatible = "syscon"; + compatible = "syscon", "simple-bus"; reg = <0x0 0x800>; #address-cells = <1>; #size-cells = <1>; + ranges = <0 0 0x800>; scm_clocks: clocks { #address-cells = <1>; diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi index 03cec62260e17be7475b20e5206837813f57324a..db858fff4e180627c1549e16c0eed5218dd41a88 100644 --- a/arch/arm/boot/dts/am57xx-idk-common.dtsi +++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi @@ -294,7 +294,7 @@ }; &usb2 { - dr_mode = "otg"; + dr_mode = "peripheral"; }; &mmc2 { diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi index cc952cf8ec3003b6339629161b40e2410ece51d4..024f1b75b0a347e270d3a5b86c834acf179a5805 100644 --- a/arch/arm/boot/dts/armada-375.dtsi +++ b/arch/arm/boot/dts/armada-375.dtsi @@ -176,9 +176,9 @@ reg = <0x8000 0x1000>; cache-unified; cache-level = <2>; - arm,double-linefill-incr = <1>; + arm,double-linefill-incr = <0>; arm,double-linefill-wrap = <0>; - arm,double-linefill = <1>; + arm,double-linefill = <0>; prefetch-data = <1>; }; diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts index 895fa6cfa15a9ee1c56c5827f5f5fe2f8e512196..563901e0ec071f0c66a4590b17fe5c3f6cfcbd69 100644 --- a/arch/arm/boot/dts/armada-388-gp.dts +++ b/arch/arm/boot/dts/armada-388-gp.dts @@ -75,7 +75,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pca0_pins>; interrupt-parent = <&gpio0>; - interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -87,7 +87,7 @@ compatible = "nxp,pca9555"; pinctrl-names = "default"; interrupt-parent = <&gpio0>; - interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; interrupt-controller; diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index 2d7668848c5ac3eed69322006b2bcb4b5cb92aa4..c60cfe9fd03317129a2fa43034142cff6ca85b03 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -143,9 +143,9 @@ reg = <0x8000 0x1000>; cache-unified; cache-level = <2>; - arm,double-linefill-incr = <1>; + arm,double-linefill-incr = <0>; arm,double-linefill-wrap = <0>; - arm,double-linefill = <1>; + arm,double-linefill = <0>; prefetch-data = <1>; }; diff --git a/arch/arm/boot/dts/armada-39x.dtsi b/arch/arm/boot/dts/armada-39x.dtsi index 34cba87f920062185f6f230f2f038478b1959f1c..aeecfa7e5ea3eeb82a66948a510d8c6444298624 100644 --- a/arch/arm/boot/dts/armada-39x.dtsi +++ b/arch/arm/boot/dts/armada-39x.dtsi @@ -111,9 +111,9 @@ reg = <0x8000 0x1000>; cache-unified; cache-level = <2>; - arm,double-linefill-incr = <1>; + arm,double-linefill-incr = <0>; arm,double-linefill-wrap = <0>; - arm,double-linefill = <1>; + arm,double-linefill = <0>; prefetch-data = <1>; }; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index c51fc652f6c72639654150919ab7f03b3b7fecbc..5a53fcf542abb980d4cf18e0da4e9e790dddf0e2 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -162,9 +162,10 @@ }; adc0: adc@f8018000 { + atmel,adc-vref = <3300>; + atmel,adc-channels-used = <0xfe>; pinctrl-0 = < &pinctrl_adc0_adtrg - &pinctrl_adc0_ad0 &pinctrl_adc0_ad1 &pinctrl_adc0_ad2 &pinctrl_adc0_ad3 @@ -172,8 +173,6 @@ &pinctrl_adc0_ad5 &pinctrl_adc0_ad6 &pinctrl_adc0_ad7 - &pinctrl_adc0_ad8 - &pinctrl_adc0_ad9 >; status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm953012k.dts b/arch/arm/boot/dts/bcm953012k.dts index 05a985a203789c8cbaae5d7a3a55e8496749975b..6208e85acd9d218008ed87591c41c2a858341e14 100644 --- a/arch/arm/boot/dts/bcm953012k.dts +++ b/arch/arm/boot/dts/bcm953012k.dts @@ -48,7 +48,7 @@ }; memory { - reg = <0x00000000 0x10000000>; + reg = <0x80000000 0x10000000>; }; }; diff --git a/arch/arm/boot/dts/bcm958522er.dts b/arch/arm/boot/dts/bcm958522er.dts index a21b0fd21f4ef586223d8033b2bbb1f8b762076a..417f6573840272e29232946e595bbceee254c87e 100644 --- a/arch/arm/boot/dts/bcm958522er.dts +++ b/arch/arm/boot/dts/bcm958522er.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 15 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/bcm958525er.dts b/arch/arm/boot/dts/bcm958525er.dts index be7f2f8ecf39baabbe3a6276b17976fea14141d1..5279b769fdfc311f0d09e044a7fd7660e0c1271a 100644 --- a/arch/arm/boot/dts/bcm958525er.dts +++ b/arch/arm/boot/dts/bcm958525er.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 15 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/bcm958525xmc.dts b/arch/arm/boot/dts/bcm958525xmc.dts index 959cde911c3c5102c5b5db0f72cf6a6b86476934..872882bd01bcdf0b65c9492509a880155c91b22f 100644 --- a/arch/arm/boot/dts/bcm958525xmc.dts +++ b/arch/arm/boot/dts/bcm958525xmc.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 31 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/bcm958622hr.dts b/arch/arm/boot/dts/bcm958622hr.dts index ad2aa87dd15ac9fbd1d6dd831070eb687ca0fc15..a340e1d93a58f12b3876b75957a54877712cf208 100644 --- a/arch/arm/boot/dts/bcm958622hr.dts +++ b/arch/arm/boot/dts/bcm958622hr.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 15 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/bcm958623hr.dts b/arch/arm/boot/dts/bcm958623hr.dts index 4ceb8fef8041ef3176c9568b283ea0f7f6bf289b..226b652ccdc893dc14b6c80ad3115cf107e60a93 100644 --- a/arch/arm/boot/dts/bcm958623hr.dts +++ b/arch/arm/boot/dts/bcm958623hr.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 15 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/bcm958625hr.dts b/arch/arm/boot/dts/bcm958625hr.dts index 442002597063516f0fa060b3886ac5d11d802e89..a1658d0721b862120fa9b292f1a97a4343a83f55 100644 --- a/arch/arm/boot/dts/bcm958625hr.dts +++ b/arch/arm/boot/dts/bcm958625hr.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 15 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/bcm988312hr.dts b/arch/arm/boot/dts/bcm988312hr.dts index 104afe98a43b1d880d9073b69bfc9d27bac69a33..ed05e33d56de1ab1e8897821ae1b2f16b9131d5f 100644 --- a/arch/arm/boot/dts/bcm988312hr.dts +++ b/arch/arm/boot/dts/bcm988312hr.dts @@ -55,6 +55,7 @@ gpio-restart { compatible = "gpio-restart"; gpios = <&gpioa 15 GPIO_ACTIVE_LOW>; + open-source; priority = <200>; }; }; diff --git a/arch/arm/boot/dts/dm814x.dtsi b/arch/arm/boot/dts/dm814x.dtsi index d87efab24fa22452c259419ac831213bb10e7428..ff57a20af9cd23697a2192389d981d7cd8ad8a75 100644 --- a/arch/arm/boot/dts/dm814x.dtsi +++ b/arch/arm/boot/dts/dm814x.dtsi @@ -252,7 +252,7 @@ }; uart1: uart@20000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart1"; reg = <0x20000 0x2000>; clock-frequency = <48000000>; @@ -262,7 +262,7 @@ }; uart2: uart@22000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart2"; reg = <0x22000 0x2000>; clock-frequency = <48000000>; @@ -272,7 +272,7 @@ }; uart3: uart@24000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart3"; reg = <0x24000 0x2000>; clock-frequency = <48000000>; @@ -332,10 +332,11 @@ ranges = <0 0x140000 0x20000>; scm_conf: scm_conf@0 { - compatible = "syscon"; + compatible = "syscon", "simple-bus"; reg = <0x0 0x800>; #address-cells = <1>; #size-cells = <1>; + ranges = <0 0 0x800>; scm_clocks: clocks { #address-cells = <1>; diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index cbdfbc4e4a26dabf136406f69228ef1ff923ba51..62c0a6155360bec71ba96405253ea19c0d7ca86f 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -371,7 +371,7 @@ }; uart1: uart@48020000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart1"; reg = <0x48020000 0x2000>; clock-frequency = <48000000>; @@ -381,7 +381,7 @@ }; uart2: uart@48022000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart2"; reg = <0x48022000 0x2000>; clock-frequency = <48000000>; @@ -391,7 +391,7 @@ }; uart3: uart@48024000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart3"; reg = <0x48024000 0x2000>; clock-frequency = <48000000>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 064d84f87e45f76828dc571a6c4119fbe4cd6cd1..ce54a70b7695d16aa6bd0e8f12c83c81cea98e79 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -282,6 +282,7 @@ device_type = "pci"; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x20013000 0x13000 0 0xffed000>; + bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; linux,pci-domain = <0>; @@ -318,6 +319,7 @@ device_type = "pci"; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x30013000 0x13000 0 0xffed000>; + bus-range = <0x00 0xff>; #interrupt-cells = <1>; num-lanes = <1>; linux,pci-domain = <1>; diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 8aa19ba144361b7f0c9b8146d7b855776669d512..5282d69e55bdb45758dd4d08f15b769d82a68c7a 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -97,11 +97,11 @@ thermal-zones { cpu_thermal: cpu-thermal { cooling-maps { - map0 { + cooling_map0: map0 { /* Corresponds to 800MHz at freq_table */ cooling-device = <&cpu0 7 7>; }; - map1 { + cooling_map1: map1 { /* Corresponds to 200MHz at freq_table */ cooling-device = <&cpu0 13 13>; }; diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts index 99634c54dca919c39f350f69350edb5e239f810e..7504a5aa538e03e2bd2f125944baa317bc8c1415 100644 --- a/arch/arm/boot/dts/exynos4412-odroidu3.dts +++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts @@ -13,6 +13,7 @@ /dts-v1/; #include "exynos4412-odroid-common.dtsi" +#include "exynos4412-prime.dtsi" / { model = "Hardkernel ODROID-U3 board based on Exynos4412"; @@ -47,11 +48,11 @@ cooling-maps { map0 { trip = <&cpu_alert1>; - cooling-device = <&cpu0 7 7>; + cooling-device = <&cpu0 9 9>; }; map1 { trip = <&cpu_alert2>; - cooling-device = <&cpu0 13 13>; + cooling-device = <&cpu0 15 15>; }; map2 { trip = <&cpu_alert0>; diff --git a/arch/arm/boot/dts/exynos4412-odroidx2.dts b/arch/arm/boot/dts/exynos4412-odroidx2.dts index 4d228858f1727fbb24ccc625802b6598755f228f..d6e92ebc3874971fdceb784bd6f0b4cb733be6bd 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx2.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx2.dts @@ -12,6 +12,7 @@ */ #include "exynos4412-odroidx.dts" +#include "exynos4412-prime.dtsi" / { model = "Hardkernel ODROID-X2 board based on Exynos4412"; diff --git a/arch/arm/boot/dts/exynos4412-prime.dtsi b/arch/arm/boot/dts/exynos4412-prime.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e75bc170c89c89ecbfd001fa07904d823d745f04 --- /dev/null +++ b/arch/arm/boot/dts/exynos4412-prime.dtsi @@ -0,0 +1,41 @@ +/* + * Samsung's Exynos4412 Prime SoC device tree source + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Exynos4412 Prime SoC revision supports higher CPU frequencies than + * non-Prime version. Therefore we need to update OPPs table and + * thermal maps accordingly. + */ + +&cpu0_opp_1500 { + /delete-property/turbo-mode; +}; + +&cpu0_opp_table { + opp@1600000000 { + opp-hz = /bits/ 64 <1600000000>; + opp-microvolt = <1350000>; + clock-latency-ns = <200000>; + }; + opp@1704000000 { + opp-hz = /bits/ 64 <1704000000>; + opp-microvolt = <1350000>; + clock-latency-ns = <200000>; + }; +}; + +&cooling_map0 { + cooling-device = <&cpu0 9 9>; +}; + +&cooling_map1 { + cooling-device = <&cpu0 15 15>; +}; diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index 40beede46e55836898779fc503e5b5380a77551c..3ebdf01d814c9dde355c1caf53cac425ca716ba5 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -130,7 +130,7 @@ opp-microvolt = <1287500>; clock-latency-ns = <200000>; }; - opp@1500000000 { + cpu0_opp_1500: opp@1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1350000>; clock-latency-ns = <200000>; diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts index 5bb8fd57e7f5a83f6cbae6c2292f33c92446c4f7..d71da30c9cff2347900f9e68715b18d65597d47a 100644 --- a/arch/arm/boot/dts/imx6sx-sdb.dts +++ b/arch/arm/boot/dts/imx6sx-sdb.dts @@ -12,23 +12,6 @@ model = "Freescale i.MX6 SoloX SDB RevB Board"; }; -&cpu0 { - operating-points = < - /* kHz uV */ - 996000 1250000 - 792000 1175000 - 396000 1175000 - 198000 1175000 - >; - fsl,soc-operating-points = < - /* ARM kHz SOC uV */ - 996000 1250000 - 792000 1175000 - 396000 1175000 - 198000 1175000 - >; -}; - &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts index 08cce17a25a01f460fd199f5f380bb3c907e20ed..b4575bbaf0852a4cfff98f5bae93f8eb93c4d6ef 100644 --- a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts +++ b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts @@ -192,7 +192,7 @@ interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>; pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins &mmc1_cd>; - cd-gpios = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>; /* gpio127 */ + cd-gpios = <&gpio4 31 GPIO_ACTIVE_LOW>; /* gpio127 */ vmmc-supply = <&vmmc1>; bus-width = <4>; cap-power-off-card; @@ -249,9 +249,9 @@ OMAP3_CORE1_IOPAD(0x2110, PIN_INPUT | MUX_MODE0) /* cam_xclka.cam_xclka */ OMAP3_CORE1_IOPAD(0x2112, PIN_INPUT | MUX_MODE0) /* cam_pclk.cam_pclk */ - OMAP3_CORE1_IOPAD(0x2114, PIN_INPUT | MUX_MODE0) /* cam_d0.cam_d0 */ - OMAP3_CORE1_IOPAD(0x2116, PIN_INPUT | MUX_MODE0) /* cam_d1.cam_d1 */ - OMAP3_CORE1_IOPAD(0x2118, PIN_INPUT | MUX_MODE0) /* cam_d2.cam_d2 */ + OMAP3_CORE1_IOPAD(0x2116, PIN_INPUT | MUX_MODE0) /* cam_d0.cam_d0 */ + OMAP3_CORE1_IOPAD(0x2118, PIN_INPUT | MUX_MODE0) /* cam_d1.cam_d1 */ + OMAP3_CORE1_IOPAD(0x211a, PIN_INPUT | MUX_MODE0) /* cam_d2.cam_d2 */ OMAP3_CORE1_IOPAD(0x211c, PIN_INPUT | MUX_MODE0) /* cam_d3.cam_d3 */ OMAP3_CORE1_IOPAD(0x211e, PIN_INPUT | MUX_MODE0) /* cam_d4.cam_d4 */ OMAP3_CORE1_IOPAD(0x2120, PIN_INPUT | MUX_MODE0) /* cam_d5.cam_d5 */ diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi index 8f9a69ca818cecb759e71c1b6b97e4073c3e22e4..efe53998c961244fc0cd1ff32a5e53c885b6322f 100644 --- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi +++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi @@ -121,7 +121,7 @@ &i2c3 { clock-frequency = <400000>; at24@50 { - compatible = "at24,24c02"; + compatible = "atmel,24c64"; readonly; reg = <0x50>; }; diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi index 18596a2c58a15edc4d13b4fbb6503045690c763b..77c6b931dc243de88fe77a79da0651bab21e42dc 100644 --- a/arch/arm/boot/dts/mt2701.dtsi +++ b/arch/arm/boot/dts/mt2701.dtsi @@ -174,4 +174,40 @@ clocks = <&uart_clk>; status = "disabled"; }; + + mmsys: syscon@14000000 { + compatible = "mediatek,mt2701-mmsys", "syscon"; + reg = <0 0x14000000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys: syscon@15000000 { + compatible = "mediatek,mt2701-imgsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + }; + + vdecsys: syscon@16000000 { + compatible = "mediatek,mt2701-vdecsys", "syscon"; + reg = <0 0x16000000 0 0x1000>; + #clock-cells = <1>; + }; + + hifsys: syscon@1a000000 { + compatible = "mediatek,mt2701-hifsys", "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + }; + + ethsys: syscon@1b000000 { + compatible = "mediatek,mt2701-ethsys", "syscon"; + reg = <0 0x1b000000 0 0x1000>; + #clock-cells = <1>; + }; + + bdpsys: syscon@1c000000 { + compatible = "mediatek,mt2701-bdpsys", "syscon"; + reg = <0 0x1c000000 0 0x1000>; + #clock-cells = <1>; + }; }; diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index 87ca50b53002b9cf244b9dca24a0f2fbdca3dabc..4d448f145ed1c2941bda6d76e91d7573c0a37568 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -734,6 +734,8 @@ vmmc_aux-supply = <&vsim>; bus-width = <8>; non-removable; + no-sdio; + no-sd; }; &mmc3 { diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts index 53d31a87b44bd7386c1b50333f130c4d8c9e0ec8..f3a3e6be79fe8706e5250a43c23cb395c3ce4472 100644 --- a/arch/arm/boot/dts/omap5-uevm.dts +++ b/arch/arm/boot/dts/omap5-uevm.dts @@ -18,6 +18,10 @@ reg = <0 0x80000000 0 0x7f000000>; /* 2032 MB */ }; + aliases { + ethernet = ðernet; + }; + leds { compatible = "gpio-leds"; led1 { @@ -72,6 +76,23 @@ >; }; +&usbhsehci { + #address-cells = <1>; + #size-cells = <0>; + + hub@2 { + compatible = "usb424,3503"; + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + ethernet: usbether@3 { + compatible = "usb424,9730"; + reg = <3>; + }; +}; + &wlcore { compatible = "ti,wl1837"; }; diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi index 2e375576ffd06edc7c1f83863df13e6f17f571e4..76f4e8921d58f8a1a1c6bf2ab42edc9c839a8324 100644 --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi @@ -65,13 +65,13 @@ cxo_board { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <19200000>; + clock-frequency = <25000000>; }; pxo_board { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <27000000>; + clock-frequency = <25000000>; }; sleep_clk: sleep_clk { diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 7eb0c7f752168563c0d3bc94fd35e21eab94f78f..c51581d6b7d0dda93f2f7e92539ab0ef7539b506 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -1,17 +1,17 @@ -dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb +dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb \ + sdxpoorwills-cdp.dtb \ + sdxpoorwills-mtp.dtb - -ifeq ($(CONFIG_ARM64),y) -always := $(dtb-y) -subdir-y := $(dts-dirs) -else targets += dtbs targets += $(addprefix ../, $(dtb-y)) $(obj)/../%.dtb: $(src)/%.dts FORCE $(call if_changed_dep,dtc) +include $(srctree)/arch/arm64/boot/dts/qcom/Makefile +$(obj)/../%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE + $(call if_changed_dep,dtc) + dtbs: $(addprefix $(obj)/../,$(dtb-y)) -endif clean-files := *.dtb diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-sdxpoorwills.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..580df55b08cfcb47fcdbb9dbc3bdeff3b58fc81b --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-sdxpoorwills.dtsi @@ -0,0 +1,104 @@ +/* Copyright (c) 2017, 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 +#include + +&soc { + apps_smmu: apps-smmu@0x15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x20000>, + <0x15022000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + anoc_1_tbu: anoc_1_tbu@0x15025000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15025000 0x1000>, + <0x15022200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + anoc_2_tbu: anoc_2_tbu@0x15029000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15029000 0x1000>, + <0x15022208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to CRYPTO. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x1a0 0x0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8950.dtsi b/arch/arm/boot/dts/qcom/pm8950.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f47872a5ab74274e995eddcca364b84b3d0bac0e --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8950.dtsi @@ -0,0 +1,388 @@ +/* Copyright (c) 2015-2017, 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. + */ + +&spmi_bus { + qcom,pm8950@0 { + compatible ="qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8950_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pm8950_temp_alarm: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0>; + label = "pm8950_tz"; + qcom,channel-num = <8>; + qcom,threshold-set = <0>; + qcom,temp_alarm-vadc = <&pm8950_vadc>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0>, + <0x0 0x8 0x1>, + <0x0 0x8 0x4>, + <0x0 0x8 0x5>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,system-reset; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm8950_coincell: qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + }; + + pm8950_mpps: mpps { + compatible = "qcom,qpnp-pin"; + spmi-dev-container; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pm8950-mpp"; + + mpp@a000 { + reg = <0xa000 0x100>; + qcom,pin-num = <1>; + status = "disabled"; + }; + + mpp@a100 { + /* MPP2 - PA_THERM config */ + reg = <0xa100 0x100>; + qcom,pin-num = <2>; + qcom,mode = <4>; /* AIN input */ + qcom,invert = <1>; /* Enable MPP */ + qcom,ain-route = <1>; /* AMUX 6 */ + qcom,master-en = <1>; + qcom,src-sel = <0>; /* Function constant */ + }; + + mpp@a200 { + reg = <0xa200 0x100>; + qcom,pin-num = <3>; + status = "disabled"; + }; + + mpp@a300 { + /* MPP4 - CASE_THERM config */ + reg = <0xa300 0x100>; + qcom,pin-num = <4>; + qcom,mode = <4>; /* AIN input */ + qcom,invert = <1>; /* Enable MPP */ + qcom,ain-route = <3>; /* AMUX 8 */ + qcom,master-en = <1>; + qcom,src-sel = <0>; /* Function constant */ + }; + }; + + pm8950_gpios: gpios { + spmi-dev-container; + compatible = "qcom,qpnp-pin"; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pm8950-gpio"; + + gpio@c000 { + reg = <0xc000 0x100>; + qcom,pin-num = <1>; + status = "disabled"; + }; + + gpio@c100 { + reg = <0xc100 0x100>; + qcom,pin-num = <2>; + status = "disabled"; + }; + + gpio@c200 { + reg = <0xc200 0x100>; + qcom,pin-num = <3>; + status = "disabled"; + }; + + gpio@c300 { + reg = <0xc300 0x100>; + qcom,pin-num = <4>; + status = "disabled"; + }; + + gpio@c400 { + reg = <0xc400 0x100>; + qcom,pin-num = <5>; + status = "disabled"; + }; + + gpio@c500 { + reg = <0xc500 0x100>; + qcom,pin-num = <6>; + status = "disabled"; + }; + + gpio@c600 { + reg = <0xc600 0x100>; + qcom,pin-num = <7>; + status = "disabled"; + }; + + gpio@c700 { + reg = <0xc700 0x100>; + qcom,pin-num = <8>; + status = "disabled"; + }; + }; + + pm8950_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + qcom,pmic-revid = <&pm8950_revid>; + + chan@5 { + label = "vcoin"; + reg = <5>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@7 { + label = "vph_pwr"; + reg = <7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@8 { + label = "die_temp"; + reg = <8>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@c { + label = "ref_buf_625mv"; + reg = <0xc>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@11 { + label = "pa_therm1"; + reg = <0x11>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@32 { + label = "xo_therm"; + reg = <0x32>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@3c { + label = "xo_therm_buf"; + reg = <0x3c>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@13 { + label = "case_therm"; + reg = <0x13>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + }; + + pm8950_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0>, + <0x0 0x34 0x3>, + <0x0 0x34 0x4>; + interrupt-names = "eoc-int-en-set", + "high-thr-en-set", + "low-thr-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,adc_tm-vadc = <&pm8950_vadc>; + qcom,pmic-revid = <&pm8950_revid>; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,btm-channel-number = <0x48>; + qcom,thermal-node; + }; + + chan@7 { + label = "vph_pwr"; + reg = <0x7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,btm-channel-number = <0x68>; + }; + }; + + pm8950_rtc: qcom,pm8950_rtc { + spmi-dev-container; + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8950_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + + qcom,pm8950_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1>; + }; + }; + + qcom,leds@a300 { + compatible = "qcom,leds-qpnp"; + reg = <0xa300 0x100>; + label = "mpp"; + }; + }; + + pm8950_1: qcom,pm8950@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8950_pwm: pwm@bc00 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xbc00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pmi8950.dtsi b/arch/arm/boot/dts/qcom/pmi8950.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0ec1f0bdd5f687b4fdeceb5cad3a51b8b955dc8d --- /dev/null +++ b/arch/arm/boot/dts/qcom/pmi8950.dtsi @@ -0,0 +1,641 @@ +/* Copyright (c) 2015-2017, 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 + +&spmi_bus { + qcom,pmi8950@2 { + compatible ="qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmi8950_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = + ; + + pon_perph_reg: qcom,pon_perph_reg { + regulator-name = "pon_spare_reg"; + qcom,pon-spare-reg-addr = <0x8c>; + qcom,pon-spare-reg-bit = <1>; + }; + }; + + pmi8950_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + + chan@0 { + label = "usbin"; + reg = <0>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@1 { + label = "dcin"; + reg = <1>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@3 { + label = "vchg_sns"; + reg = <3>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@d { + label = "chg_temp"; + reg = <0xd>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <16>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@43 { + label = "usb_dp"; + reg = <0x43>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@44 { + label = "usb_dm"; + reg = <0x44>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + }; + + pmi8950_gpios: gpios { + spmi-dev-container; + compatible = "qcom,qpnp-pin"; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pmi8950-gpio"; + + gpio@c000 { + reg = <0xc000 0x100>; + qcom,pin-num = <1>; + status = "disabled"; + }; + + gpio@c100 { + reg = <0xc100 0x100>; + qcom,pin-num = <2>; + status = "disabled"; + }; + }; + + pmi8950_mpps: mpps { + spmi-dev-container; + compatible = "qcom,qpnp-pin"; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pmi8950-mpp"; + + mpp@a000 { + reg = <0xa000 0x100>; + qcom,pin-num = <1>; + status = "disabled"; + }; + + mpp@a100 { + reg = <0xa100 0x100>; + qcom,pin-num = <2>; + status = "disabled"; + }; + + mpp@a200 { + reg = <0xa200 0x100>; + qcom,pin-num = <3>; + status = "disabled"; + }; + + mpp@a300 { + reg = <0xa300 0x100>; + qcom,pin-num = <4>; + status = "disabled"; + }; + }; + + pmi8950_charger: qcom,qpnp-smbcharger { + spmi-dev-container; + compatible = "qcom,qpnp-smbcharger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,iterm-ma = <100>; + qcom,float-voltage-mv = <4200>; + qcom,resume-delta-mv = <200>; + qcom,chg-inhibit-fg; + qcom,rparasitic-uohm = <100000>; + qcom,bms-psy-name = "bms"; + qcom,thermal-mitigation = <1500 700 600 0>; + qcom,parallel-usb-min-current-ma = <1400>; + qcom,parallel-usb-9v-min-current-ma = <900>; + qcom,parallel-allowed-lowering-ma = <500>; + qcom,pmic-revid = <&pmi8950_revid>; + qcom,force-aicl-rerun; + qcom,aicl-rerun-period-s = <180>; + qcom,autoadjust-vfloat; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0>, + <0x2 0x10 0x1>, + <0x2 0x10 0x2>, + <0x2 0x10 0x3>, + <0x2 0x10 0x4>, + <0x2 0x10 0x5>, + <0x2 0x10 0x6>, + <0x2 0x10 0x7>; + + interrupt-names = "chg-error", + "chg-inhibit", + "chg-prechg-sft", + "chg-complete-chg-sft", + "chg-p2f-thr", + "chg-rechg-thr", + "chg-taper-thr", + "chg-tcc-thr"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0>, + <0x2 0x11 0x1>, + <0x2 0x11 0x3>; + interrupt-names = "otg-fail", + "otg-oc", + "usbid-change"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0>, + <0x2 0x12 0x1>, + <0x2 0x12 0x2>, + <0x2 0x12 0x3>, + <0x2 0x12 0x4>, + <0x2 0x12 0x5>, + <0x2 0x12 0x6>, + <0x2 0x12 0x7>; + + interrupt-names = "batt-hot", + "batt-warm", + "batt-cold", + "batt-cool", + "batt-ov", + "batt-low", + "batt-missing", + "batt-term-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0>, + <0x2 0x13 0x1>, + <0x2 0x13 0x2>, + <0x2 0x13 0x5>; + + interrupt-names = "usbin-uv", + "usbin-ov", + "usbin-src-det", + "aicl-done"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0>, + <0x2 0x14 0x1>; + interrupt-names = "dcin-uv", + "dcin-ov"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0>, + <0x2 0x16 0x1>, + <0x2 0x16 0x2>, + <0x2 0x16 0x3>, + <0x2 0x16 0x4>, + <0x2 0x16 0x5>; + + interrupt-names = "power-ok", + "temp-shutdown", + "wdog-timeout", + "flash-fail", + "otst2", + "otst3"; + }; + + smbcharger_charger_otg: qcom,smbcharger-boost-otg { + regulator-name = "smbcharger_charger_otg"; + }; + }; + + pmi8950_fg: qcom,fg { + spmi-dev-container; + compatible = "qcom,qpnp-fg"; + #address-cells = <1>; + #size-cells = <1>; + qcom,resume-soc = <95>; + status = "okay"; + qcom,bcl-lm-threshold-ma = <127>; + qcom,bcl-mh-threshold-ma = <405>; + qcom,fg-iterm-ma = <150>; + qcom,fg-chg-iterm-ma = <100>; + qcom,pmic-revid = <&pmi8950_revid>; + qcom,fg-cutoff-voltage-mv = <3500>; + qcom,cycle-counter-en; + qcom,capacity-learning-on; + + qcom,fg-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0>, + <0x2 0x40 0x1>, + <0x2 0x40 0x2>, + <0x2 0x40 0x3>, + <0x2 0x40 0x4>, + <0x2 0x40 0x5>, + <0x2 0x40 0x6>; + + interrupt-names = "high-soc", + "low-soc", + "full-soc", + "empty-soc", + "delta-soc", + "first-est-done", + "update-soc"; + }; + + qcom,fg-batt@4100 { + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0>, + <0x2 0x41 0x1>, + <0x2 0x41 0x2>, + <0x2 0x41 0x3>, + <0x2 0x41 0x4>, + <0x2 0x41 0x5>, + <0x2 0x41 0x6>, + <0x2 0x41 0x7>; + + interrupt-names = "soft-cold", + "soft-hot", + "vbatt-low", + "batt-ided", + "batt-id-req", + "batt-unknown", + "batt-missing", + "batt-match"; + }; + + qcom,revid-tp-rev@1f1 { + reg = <0x1f1 0x1>; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0>, + <0x2 0x44 0x2>; + + interrupt-names = "mem-avail", + "data-rcvry-sug"; + }; + }; + + bcl@4200 { + compatible = "qcom,msm-bcl"; + reg = <0x4200 0xFF 0x88E 0x2>; + reg-names = "fg_user_adc", "pon_spare"; + interrupts = <0x2 0x42 0x0>, + <0x2 0x42 0x1>; + interrupt-names = "bcl-high-ibat-int", + "bcl-low-vbat-int"; + qcom,vbat-scaling-factor = <39000>; + qcom,vbat-gain-numerator = <1>; + qcom,vbat-gain-denominator = <128>; + qcom,vbat-polling-delay-ms = <100>; + qcom,ibat-scaling-factor = <39000>; + qcom,ibat-gain-numerator = <1>; + qcom,ibat-gain-denominator = <128>; + qcom,ibat-offset-numerator = <1200>; + qcom,ibat-offset-denominator = <1>; + qcom,ibat-polling-delay-ms = <100>; + qcom,inhibit-derating-ua = <550000>; + }; + + qcom,leds@a100 { + compatible = "qcom,leds-qpnp"; + reg = <0xa100 0x100>; + label = "mpp"; + }; + }; + + qcom,pmi8950@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmi8950_pwm: pwm@b000 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xb000 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + + labibb: qpnp-labibb-regulator { + status = "disabled"; + spmi-dev-container; + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pmi8950_revid>; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-use-default-voltage; + qcom,qpnp-ibb-init-voltage = <5500000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + qcom,qpnp-ibb-init-lcd-voltage = <5500000>; + + qcom,qpnp-ibb-soft-start = <1000>; + + qcom,qpnp-ibb-discharge-resistor = <32>; + qcom,qpnp-ibb-lab-pwrup-delay = <8000>; + qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; + qcom,qpnp-ibb-en-discharge; + + qcom,qpnp-ibb-full-pull-down; + qcom,qpnp-ibb-pull-down-enable; + qcom,qpnp-ibb-switching-clock-frequency = + <1480>; + qcom,qpnp-ibb-limit-maximum-current = <1550>; + qcom,qpnp-ibb-debounce-cycle = <16>; + qcom,qpnp-ibb-limit-max-current-enable; + qcom,qpnp-ibb-ps-enable; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-use-default-voltage; + qcom,qpnp-lab-init-voltage = <5500000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + qcom,qpnp-lab-init-lcd-voltage = <5500000>; + + qcom,qpnp-lab-soft-start = <800>; + + qcom,qpnp-lab-full-pull-down; + qcom,qpnp-lab-pull-down-enable; + qcom,qpnp-lab-switching-clock-frequency = + <1600>; + qcom,qpnp-lab-limit-maximum-current = <800>; + qcom,qpnp-lab-limit-max-current-enable; + qcom,qpnp-lab-ps-threshold = <40>; + qcom,qpnp-lab-ps-enable; + qcom,qpnp-lab-nfet-size = <100>; + qcom,qpnp-lab-pfet-size = <100>; + qcom,qpnp-lab-max-precharge-time = <500>; + }; + + }; + + wled: qcom,leds@d800 { + compatible = "qcom,qpnp-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>, + <0xdc00 0x100>, + <0xde00 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base", + "qpnp-wled-ibb-base", + "qpnp-wled-lab-base"; + interrupts = <0x3 0xd8 0x2>; + interrupt-names = "sc-irq"; + status = "okay"; + linux,name = "wled"; + linux,default-trigger = "bkl-trigger"; + qcom,fdbk-output = "auto"; + qcom,vref-mv = <350>; + qcom,switch-freq-khz = <800>; + qcom,ovp-mv = <29500>; + qcom,ilim-ma = <980>; + qcom,boost-duty-ns = <26>; + qcom,mod-freq-khz = <9600>; + qcom,dim-mode = "hybrid"; + qcom,dim-method = "linear"; + qcom,hyb-thres = <625>; + qcom,sync-dly-us = <800>; + qcom,fs-curr-ua = <20000>; + qcom,led-strings-list = [00 01]; + qcom,en-ext-pfet-sc-pro; + qcom,cons-sync-write-delay-us = <1000>; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + qcom,headroom = <500>; + qcom,startup-dly = <128>; + qcom,clamp-curr = <200>; + qcom,pmic-charger-support; + qcom,self-check-enabled; + qcom,thermal-derate-enabled; + qcom,thermal-derate-threshold = <100>; + qcom,thermal-derate-rate = "5_PERCENT"; + qcom,current-ramp-enabled; + qcom,ramp_up_step = "6P7_US"; + qcom,ramp_dn_step = "6P7_US"; + qcom,vph-pwr-droop-enabled; + qcom,vph-pwr-droop-threshold = <3000>; + qcom,vph-pwr-droop-debounce-time = <10>; + qcom,headroom-sense-ch0-enabled; + qcom,headroom-sense-ch1-enabled; + qcom,pmic-revid = <&pmi8950_revid>; + + pmi8950_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,default-led-trigger = + "flash0_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <0>; + qcom,current = <625>; + }; + + pmi8950_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,default-led-trigger = + "flash1_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <1>; + qcom,current = <625>; + }; + + pmi8950_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,default-led-trigger = + "torch0_trigger"; + qcom,max-current = <200>; + qcom,id = <0>; + qcom,current = <120>; + }; + + pmi8950_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,default-led-trigger = + "torch1_trigger"; + qcom,max-current = <200>; + qcom,id = <1>; + qcom,current = <120>; + }; + + pmi8950_switch: qcom,switch { + label = "switch"; + qcom,led-name = "led:switch"; + qcom,default-led-trigger = + "switch_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <2>; + qcom,current = <625>; + reg0 { + regulator-name = "pon_spare_reg"; + }; + }; + }; + + pmi_haptic: qcom,haptic@c000 { + compatible = "qcom,qpnp-haptic"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0>, + <0x3 0xc0 0x1>; + interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pmi8950_revid>; + vcc_pon-supply = <&pon_perph_reg>; + qcom,play-mode = "direct"; + qcom,wave-play-rate-us = <5263>; + qcom,actuator-type = "erm"; + qcom,wave-shape = "square"; + qcom,vmax-mv = <2000>; + qcom,ilim-ma = <800>; + qcom,sc-deb-cycles = <8>; + qcom,int-pwm-freq-khz = <505>; + qcom,en-brake; + qcom,brake-pattern = [03 03 00 00]; + qcom,use-play-irq; + qcom,use-sc-irq; + qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wave-rep-cnt = <1>; + qcom,wave-samp-rep-cnt = <1>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi b/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8f7edab9b504ab3d8c0f09a59707c1e2c04fe43a --- /dev/null +++ b/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi @@ -0,0 +1,186 @@ +/* Copyright (c) 2017-2018, 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 +#include + +&spmi_bus { + qcom,pmxpoorwills@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmxpoorwills_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pmxpoorwills_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x900>; + interrupts = <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>; + interrupt-names = "pmxpoorwills_gpio2", + "pmxpoorwills_gpio3", + "pmxpoorwills_gpio4", + "pmxpoorwills_gpio5", + "pmxpoorwills_gpio6"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <1 7 8 9>; + }; + + pmxpoorwills_rtc: qcom,pmxpoorwills_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pmxpoorwills_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + qcom,pmxpoorwills_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + + pmxpoorwills_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc-hc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-full-scale-code = <0x70e4>; + qcom,adc-vdd-reference = <1875>; + pinctrl-names = "default"; + pinctrl-0 = <&ambient_therm_default>; + #thermal-sensor-cells = <1>; + + chan@6 { + label = "die_temp"; + reg = <6>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@0 { + label = "ref_gnd"; + reg = <0>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@1 { + label = "ref_1250v"; + reg = <1>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + }; + }; + + qcom,pmxpoorwills@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmxpoorwills_pwm_1: pwm@bc00 { + compatible = "qcom,qpnp-pwm"; + reg = <0xbc00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmxpoorwills_pwm_2: pwm@bd00 { + compatible = "qcom,qpnp-pwm"; + reg = <0xbd00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <1>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmxpoorwills_pwm_3: pwm@be00 { + compatible = "qcom,qpnp-pwm"; + reg = <0xbe00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <2>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmxpoorwills_pwm_4: pwm@bf00 { + compatible = "qcom,qpnp-pwm"; + reg = <0xbf00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <3>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0fd3b3473c612dfccdd62335ddf5ce43025f53c6 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2015-2017, 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 { + qcom,msm-adsp-loader { + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + qcom,proc-img-to-load = "modem"; + }; + + qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,scm-mp-enabled; + memory-region = <&audio_mem>; + }; + + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + + host_pcm: qcom,msm-voice-host-pcm { + compatible = "qcom,msm-voice-host-pcm"; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + qcom,adsp-version = "MDSP 1.2"; + }; + + qcom,msm-dai-stub { + compatible = "qcom,msm-dai-stub"; + dtmf_tx: qcom,msm-dai-stub-dtmf-tx { + compatible = "qcom,msm-dai-stub-dev"; + qcom,msm-dai-stub-dev-id = <4>; + }; + + rx_capture_tx: qcom,msm-dai-stub-host-rx-capture-tx { + compatible = "qcom,msm-dai-stub-dev"; + qcom,msm-dai-stub-dev-id = <5>; + }; + + rx_playback_rx: qcom,msm-dai-stub-host-rx-playback-rx { + compatible = "qcom,msm-dai-stub-dev"; + qcom,msm-dai-stub-dev-id = <6>; + }; + + tx_capture_tx: qcom,msm-dai-stub-host-tx-capture-tx { + compatible = "qcom,msm-dai-stub-dev"; + qcom,msm-dai-stub-dev-id = <7>; + }; + + tx_playback_rx: qcom,msm-dai-stub-host-tx-playback-rx { + compatible = "qcom,msm-dai-stub-dev"; + qcom,msm-dai-stub-dev-id = <8>; + }; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + }; + + pcm_dtmf: qcom,msm-pcm-dtmf { + compatible = "qcom,msm-pcm-dtmf"; + }; + + cpu-pmu { + compatible = "arm,cortex-a7-pmu"; + qcom,irq-is-percpu; + interrupts = <1 8 0x100>; + }; + + dai_pri_auxpcm: qcom,msm-pri-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_sec_auxpcm: qcom,msm-sec-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "secondary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + mi2s_prim: qcom,msm-dai-q6-mi2s-prim { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + }; + mi2s_sec: qcom,msm-dai-q6-mi2s-sec { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <1>; + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + }; + + }; + + prim_master: prim_master_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_ws_active_master + &pri_sck_active_master + &pri_dout_active + &pri_din_active>; + pinctrl-1 = <&pri_ws_sleep + &pri_sck_sleep + &pri_dout_sleep + &pri_din_sleep>; + qcom,mi2s-auxpcm-cdc-gpios; + }; + + prim_slave: prim_slave_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_ws_active_slave + &pri_sck_active_slave + &pri_dout_active + &pri_din_active>; + pinctrl-1 = <&pri_ws_sleep + &pri_sck_sleep + &pri_dout_sleep + &pri_din_sleep>; + qcom,mi2s-auxpcm-cdc-gpios; + }; + + sec_master: sec_master_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_ws_active_master + &sec_sck_active_master + &sec_dout_active + &sec_din_active>; + pinctrl-1 = <&sec_ws_sleep + &sec_sck_sleep + &sec_dout_sleep + &sec_din_sleep>; + qcom,mi2s-auxpcm-cdc-gpios; + }; + + sec_slave: sec_slave_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_ws_active_slave + &sec_sck_active_slave + &sec_dout_active + &sec_din_active>; + pinctrl-1 = <&sec_ws_sleep + &sec_sck_sleep + &sec_dout_sleep + &sec_din_sleep>; + qcom,mi2s-auxpcm-cdc-gpios; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdx-wsa881x.dtsi b/arch/arm/boot/dts/qcom/sdx-wsa881x.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a294e6c8f5e1c9fc4fafce36713dab8c383679bb --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdx-wsa881x.dtsi @@ -0,0 +1,45 @@ +/* Copyright (c) 2016-2017, 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. + */ + +&i2c_3 { + tavil_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-audio-overlay.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e51d54b3dad2b1eb0a49224ed795e51c7011e22a --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-audio-overlay.dtsi @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017, 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 "sdxpoorwills-wcd.dtsi" +#include "sdx-wsa881x.dtsi" +#include + +&snd_934x { + qcom,audio-routing = + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>; + qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>; + qcom,tavil-mclk-clk-freq = <9600000>; + + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&soc { + wcd9xxx_intc: wcd9xxx-irq { + status = "ok"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 90 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio_up: audio_ext_clk_up { + compatible = "qcom,audio-ref-clk"; + qcom,audio-ref-clk-gpio = <&tlmm 62 0>; + qcom,codec-mclk-clk-freq = <9600000>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&i2s_mclk_sleep>; + pinctrl-1 = <&i2s_mclk_active>; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@86 { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 86 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&i2c_3 { + wcd934x_cdc: tavil_codec { + compatible = "qcom,tavil-i2c"; + reg = <0x0d>; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_up AUDIO_LPASS_MCLK>; + + cdc-vdd-buck-supply = <&pmxpoorwills_l6>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmxpoorwills_l6>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmxpoorwills_l6>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmxpoorwills_l6>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmxpoorwills_l6>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-dmic-sample-rate = <4800000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-audio.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a3eba9a80957fadb8e2e6ea9bb0e94337d5a43bb --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-audio.dtsi @@ -0,0 +1,51 @@ +/* Copyright (c) 2015-2017, 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 "sdx-audio-lpass.dtsi" + +&soc { + snd_934x: sound-tavil { + compatible = "qcom,sdx-asoc-snd-tavil"; + qcom,model = "sdx-tavil-i2s-snd-card"; + qcom,prim_mi2s_aux_master = <&prim_master>; + qcom,prim_mi2s_aux_slave = <&prim_slave>; + qcom,sec_mi2s_aux_master = <&sec_master>; + qcom,sec_mi2s_aux_slave = <&sec_slave>; + + asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>, + <&loopback>, <&hostless>, <&afe>, <&routing>, + <&pcm_dtmf>, <&host_pcm>, <&compress>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-voip-dsp", "msm-pcm-voice", + "msm-pcm-loopback", "msm-pcm-hostless", + "msm-pcm-afe", "msm-pcm-routing", + "msm-pcm-dtmf", "msm-voice-host-pcm", + "msm-compress-dsp"; + asoc-cpu = <&dai_pri_auxpcm>, <&mi2s_prim>, <&mi2s_sec>, + <&dtmf_tx>, + <&rx_capture_tx>, <&rx_playback_rx>, + <&tx_capture_tx>, <&tx_playback_rx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&dai_sec_auxpcm>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", + "msm-dai-stub-dev.6", "msm-dai-stub-dev.7", + "msm-dai-stub-dev.8", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-auxpcm.2"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-blsp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-blsp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..13e1fc3d1db3ef3cd61058b4aee415496a11a6f1 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-blsp.dtsi @@ -0,0 +1,572 @@ +/* Copyright (c) 2017, 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 "sdxpoorwills-pinctrl.dtsi" + +/ { + aliases { + spi1 = &spi_1; + spi2 = &spi_2; + spi3 = &spi_3; + spi4 = &spi_4; + i2c1 = &i2c_1; + i2c2 = &i2c_2; + i2c3 = &i2c_3; + i2c4 = &i2c_4; + i2c5 = &i2c_5; + i2c6 = &i2c_6; + i2c7 = &i2c_7; + }; +}; + + +&soc { + dma_blsp1: qcom,sps-dma@804000 { /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0x804000 0x23000>; + interrupts = <0 58 0>; + qcom,summing-threshold = <0x10>; + }; + + i2c_1: i2c@835000 { /* BLSP1 QUP1: GPIO: 2,3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x835000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 31 0>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_1_active>; + pinctrl-1 = <&i2c_1_sleep>; + status = "disabled"; + }; + + i2c_2: i2c@836000 { /* BLSP1 QUP2: GPIO: 6,7 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x836000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 32 0>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_2_active>; + pinctrl-1 = <&i2c_2_sleep>; + status = "disabled"; + }; + + i2c_3: i2c@837000 { /* BLSP1 QUP3: GPIO: 10,11 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x837000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 33 0>; + dmas = <&dma_blsp1 12 64 0x20000020 0x20>, + <&dma_blsp1 13 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_3_active>; + pinctrl-1 = <&i2c_3_sleep>; + }; + + i2c_4: i2c@838000 { /* BLSP1 QUP4: GPIO: 76,77 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x838000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 34 0>; + dmas = <&dma_blsp1 14 64 0x20000020 0x20>, + <&dma_blsp1 15 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_4_active>; + pinctrl-1 = <&i2c_4_sleep>; + status = "disabled"; + }; + + i2c_5: i2c@835000 { /* BLSP1 QUP1: GPIO: 74,75 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x835000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 31 0>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_5_active>; + pinctrl-1 = <&i2c_5_sleep>; + status = "disabled"; + }; + + i2c_6: i2c@836000 { /* BLSP1 QUP2: GPIO: 65,66 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x836000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 32 0>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_6_active>; + pinctrl-1 = <&i2c_6_sleep>; + status = "disabled"; + }; + + i2c_7: i2c@838000 { /* BLSP1 QUP4: GPIO: 18,19 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x838000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 34 0>; + dmas = <&dma_blsp1 14 64 0x20000020 0x20>, + <&dma_blsp1 15 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_7_active>; + pinctrl-1 = <&i2c_7_sleep>; + status = "disabled"; + }; + + spi_1: spi@835000 { /* BLSP1 QUP1: GPIO: 72,73,74,75 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x835000 0x600>, + <0x804000 0x23000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 31 0>, <0 58 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <8>; + qcom,bam-producer-pipe-index = <9>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_1_active>; + pinctrl-1 = <&spi_1_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_2: spi@836000 { /* BLSP1 QUP2: GPIO: 4,5,6,7 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x836000 0x600>, + <0x804000 0x23000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 32 0>, <0 58 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <10>; + qcom,bam-producer-pipe-index = <11>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_2_active>; + pinctrl-1 = <&spi_2_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_3: spi@837000 { /* BLSP1 QUP3: GPIO: 8,9,10,11 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x837000 0x600>, + <0x804000 0x23000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 33 0>, <0 58 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <12>; + qcom,bam-producer-pipe-index = <13>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_3_active>; + pinctrl-1 = <&spi_3_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_4: spi@838000 { /* BLSP1 QUP4: GPIO: 16,17,18,19 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x838000 0x600>, + <0x804000 0x23000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 34 0>, <0 58 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <14>; + qcom,bam-producer-pipe-index = <15>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_4_active>; + pinctrl-1 = <&spi_4_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_SPI_APPS_CLK>; + status = "disabled"; + }; + + blsp1_uart1a_hs: uarta@82f000 { /* BLSP1 UART1: GPIO: 0,1,2,3 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x82f000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1a_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 24 0 + 1 &intc 0 58 0 + 2 &tlmm 1 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart1a_tx_sleep>, + <&blsp1_uart1a_rxcts_sleep>, <&blsp1_uart1a_rfr_sleep>; + pinctrl-1 = <&blsp1_uart1a_tx_active>, + <&blsp1_uart1a_rxcts_active>, <&blsp1_uart1a_rfr_active>; + + qcom,msm-bus,name = "buart1a"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart1b_hs: uartb@82f000 { /* BLSP1 UART1: GPIO: 20,21,22,23 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x82f000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1b_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 24 0 + 1 &intc 0 58 0 + 2 &tlmm 21 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart1b_tx_sleep>, + <&blsp1_uart1b_rxcts_sleep>, <&blsp1_uart1b_rfr_sleep>; + pinctrl-1 = <&blsp1_uart1b_tx_active>, + <&blsp1_uart1b_rxcts_active>, <&blsp1_uart1b_rfr_active>; + + qcom,msm-bus,name = "buart1b"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart2a_hs: uarta@830000 { /* BLSP1 UART2 : GPIO: 4,5,6,7 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x830000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2a_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 25 0 + 1 &intc 0 58 0 + 2 &tlmm 5 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart2a_tx_sleep>, + <&blsp1_uart2a_rxcts_sleep>, <&blsp1_uart2a_rfr_sleep>; + pinctrl-1 = <&blsp1_uart2b_tx_active>, + <&blsp1_uart2b_rxcts_active>, <&blsp1_uart2b_rfr_active>; + + qcom,msm-bus,name = "buart2a"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart2b_hs: uartb@830000 { /* BLSP1 UART2 : GPIO: 63,64,65,66 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x830000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2b_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 25 0 + 1 &intc 0 58 0 + 2 &tlmm 64 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart2b_tx_sleep>, + <&blsp1_uart2b_rxcts_sleep>, <&blsp1_uart2b_rfr_sleep>; + pinctrl-1 = <&blsp1_uart2b_tx_active>, + <&blsp1_uart2b_rxcts_active>, <&blsp1_uart2b_rfr_active>; + + qcom,msm-bus,name = "buart2b"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart3_hs: uart@831000 { /* BLSP1 UART3: GPIO: 8,9,10,11 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x831000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart3_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 26 0 + 1 &intc 0 58 0 + 2 &tlmm 9 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <4>; + qcom,bam-rx-ep-pipe-index = <5>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART3_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart3_tx_sleep>, + <&blsp1_uart3_rxcts_sleep>, <&blsp1_uart3_rfr_sleep>; + pinctrl-1 = <&blsp1_uart3_tx_active>, + <&blsp1_uart3_rxcts_active>, <&blsp1_uart3_rfr_active>; + + qcom,msm-bus,name = "buart3"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart4a_hs: uarta@832000 { /* BLSP1 UART4 : GPIO: 20,21,22,23 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x832000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart4a_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 27 0 + 1 &intc 0 58 0 + 2 &tlmm 21 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <6>; + qcom,bam-rx-ep-pipe-index = <7>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART4_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart4a_tx_active>, + <&blsp1_uart4a_rxcts_sleep>, <&blsp1_uart4a_rfr_sleep>; + pinctrl-1 = <&blsp1_uart4a_tx_active>, + <&blsp1_uart4a_rxcts_active>, <&blsp1_uart4a_rfr_active>; + + qcom,msm-bus,name = "buart4a"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart4b_hs: uartb@832000 { /* BLSP1 UART4 : GPIO: 16,17,18,19 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x832000 0x200>, + <0x804000 0x23000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart4b_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 27 0 + 1 &intc 0 58 0 + 2 &tlmm 17 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <6>; + qcom,bam-rx-ep-pipe-index = <7>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART4_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart4b_tx_sleep>, + <&blsp1_uart4b_rxcts_sleep>, <&blsp1_uart4b_rfr_sleep>; + pinctrl-1 = <&blsp1_uart4b_tx_active>, + <&blsp1_uart4b_rxcts_active>, <&blsp1_uart4b_rfr_active>; + + qcom,msm-bus,name = "buart4b"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e6dc45a705927d0a99171f24d863c76b6d84cce4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi @@ -0,0 +1,839 @@ +/* Copyright (c) 2017, 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 + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x1100000 0x400000>, + <0x1100000 0x400000>, + <0x1620000 0x400000>, + <0x1620000 0x400000>; + + reg-names = "mc_virt-base", "mem_noc-base", + "system_noc-base", "ipa_virt-base"; + + mbox-names = "apps_rsc"; + mboxes = <&apps_rsc 0>; + + /*RSCs*/ + rsc_apps: rsc-apps { + cell-id = ; + label = "apps_rsc"; + qcom,rsc-dev; + qcom,req-state = <2>; + }; + + /*BCMs*/ + bcm_alc: bcm-alc { + cell-id = ; + label = "ALC"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ce: bcm-ce { + cell-id = ; + label = "CE"; + qcom,bcm-name = "CE"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mc0: bcm-mc0 { + cell-id = ; + label = "MC0"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh0: bcm-sh0 { + cell-id = ; + label = "SH0"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_pn0: bcm-pn0 { + cell-id = ; + label = "PN0"; + qcom,bcm-name = "PN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh1: bcm-sh1 { + cell-id = ; + label = "SH1"; + qcom,bcm-name = "SH1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh3: bcm-sh3 { + cell-id = ; + label = "SH3"; + qcom,bcm-name = "SH3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh4: bcm-sh4 { + cell-id = ; + label = "SH4"; + qcom,bcm-name = "SH4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn0: bcm-sn0 { + cell-id = ; + label = "SN0"; + qcom,bcm-name = "SN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_pn1: bcm-pn1 { + cell-id = ; + label = "PN1"; + qcom,bcm-name = "PN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_pn2: bcm-pn2 { + cell-id = ; + label = "PN2"; + qcom,bcm-name = "PN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_pn3: bcm-pn3 { + cell-id = ; + label = "PN3"; + qcom,bcm-name = "PN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_pn5: bcm-pn5 { + cell-id = ; + label = "PN5"; + qcom,bcm-name = "PN5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn6: bcm-sn6 { + cell-id = ; + label = "SN6"; + qcom,bcm-name = "SN6"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn7: bcm-sn7 { + cell-id = ; + label = "SN7"; + qcom,bcm-name = "SN7"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn8: bcm-sn8 { + cell-id = ; + label = "SN8"; + qcom,bcm-name = "SN8"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn9: bcm-sn9 { + cell-id = ; + label = "SN9"; + qcom,bcm-name = "SN9"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn11: bcm-sn11 { + cell-id = ; + label = "SN11"; + qcom,bcm-name = "SN11"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + /*Buses*/ + fab_ipa_virt: fab-ipa_virt{ + cell-id = ; + label = "fab-ipa_virt"; + qcom,fab-dev; + qcom,base-name = "ipa_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mc_virt: fab-mc_virt{ + cell-id = ; + label = "fab-mc_virt"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mem_noc: fab-mem_noc { + cell-id = ; + label = "fab-mem_noc"; + qcom,fab-dev; + qcom,base-name = "mem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_system_noc: fab-system_noc { + cell-id = ; + label = "fab-system_noc"; + qcom,fab-dev; + qcom,base-name = "system_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <45056>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + /*Masters*/ + + mas_ipa_core_master: mas-ipa-core-master { + cell-id = ; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ipa_core_slave>; + qcom,bus-dev = <&fab_ipa_virt>; + }; + + mas_llcc_mc: mas-llcc-mc { + cell-id = ; + label = "mas-llcc-mc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_mc_virt>; + }; + + mas_acm_tcu: mas-acm-tcu { + cell-id = ; + label = "mas-acm-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh1>; + qcom,ap-owned; + qcom,prio = <6>; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_xm_apps_rdwr: mas-xm-apps-rdwr { + cell-id = ; + label = "mas-xm-apps-rdwr"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_llcc &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_qhm_audio: mas-qhm-audio { + cell-id = ; + label = "mas-qhm-audio"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <9>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn2>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_qhm_blsp1: mas-qhm-blsp1 { + cell-id = ; + label = "mas-qhm-blsp1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <10>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn3>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <11>; + qcom,connections = <&slv_qhs_crypto_cfg + &slv_qhs_pdm &slv_qhs_pcie_parf + &slv_qhs_tlmm &slv_qhs_spmi_fetcher + &slv_qhs_prng &slv_qhs_qpic + &slv_qxs_imem &slv_qhs_snoc_cfg + &slv_qhs_audio &slv_qhs_sdc1 + &slv_qhs_aoss &slv_qhs_ipa + &slv_qns_snoc_memnoc &slv_qhs_usb3_phy + &slv_qhs_aop &slv_qhs_tcsr + &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg + &slv_qhs_usb3 &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn8>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_qhm_qpic: mas-qhm-qpic { + cell-id = ; + label = "mas-qhm-qpic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn3>; + }; + + mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { + cell-id = ; + label = "mas-qhm-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qhm_spmi_fetcher1: mas-qhm-spmi-fetcher1 { + cell-id = ; + label = "mas-qhm-spmi-fetcher1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_aggre_noc &slv_qhs_aop>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn2>; + }; + + mas_qnm_aggre_noc: mas-qnm-aggre-noc { + cell-id = ; + label = "mas-qnm-aggre-noc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_crypto_cfg + &slv_qhs_snoc_cfg &slv_qhs_sdc1 + &slv_qhs_aoss &slv_qhs_spmi_fetcher + &slv_qhs_pdm &slv_qns_snoc_memnoc + &slv_qhs_tcsr &slv_xs_qdss_stm + &slv_qhs_qpic &slv_qxs_imem + &slv_qhs_ipa &slv_qhs_usb3_phy + &slv_qhs_aop &slv_qhs_blsp1 + &slv_qhs_pcie_parf &slv_qhs_audio + &slv_qxs_pcie &slv_qhs_tlmm + &slv_qhs_prng &slv_xs_sys_tcu_cfg + &slv_qhs_clk_ctl &slv_qhs_usb3>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn7>; + }; + + mas_qnm_aggre_noc_ipa: mas-qnm-aggre-noc-ipa { + cell-id = ; + label = "mas-qnm-aggre-noc-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_crypto_cfg + &slv_qhs_snoc_cfg &slv_qhs_sdc1 + &slv_qhs_aoss &slv_qhs_spmi_fetcher + &slv_qhs_pdm &slv_qns_snoc_memnoc + &slv_qhs_tcsr &slv_xs_qdss_stm + &slv_qhs_qpic &slv_qxs_imem + &slv_qhs_ipa &slv_qhs_usb3_phy + &slv_qhs_aop &slv_qhs_blsp1 + &slv_qhs_pcie_parf &slv_qhs_audio + &slv_qhs_tlmm &slv_qhs_prng + &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl + &slv_qhs_usb3>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qnm_memnoc: mas-qnm-memnoc { + cell-id = ; + label = "mas-qnm-memnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_crypto_cfg + &slv_qhs_pdm &slv_qhs_pcie_parf + &slv_qhs_tlmm &slv_qhs_spmi_fetcher + &slv_qhs_prng &slv_qhs_qpic + &slv_qxs_imem &slv_qhs_snoc_cfg + &slv_qhs_audio &slv_qhs_sdc1 + &slv_qhs_aoss &slv_qhs_ipa + &slv_qhs_usb3_phy &slv_qhs_aop + &slv_qhs_tcsr &slv_qhs_blsp1 + &slv_xs_sys_tcu_cfg &slv_qhs_usb3 + &slv_xs_qdss_stm &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn9>; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_ce>, <&bcm_pn5>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_aggre_noc_ipa>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn11>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_qxm_ipa2pcie_slv: mas-qxm-ipa2pcie-slv { + cell-id = ; + label = "mas-qxm-ipa2pcie-slv"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qxs_pcie>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_emac: mas-xm-emac { + cell-id = ; + label = "mas-xm-emac"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_xm_pcie: mas-xm-pcie { + cell-id = ; + label = "mas-xm-pcie"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qhs_crypto_cfg + &slv_qhs_pdm &slv_qhs_pcie_parf + &slv_qhs_tlmm &slv_qhs_spmi_fetcher + &slv_qhs_prng &slv_qhs_qpic + &slv_qxs_imem &slv_qhs_snoc_cfg + &slv_qhs_audio &slv_qhs_sdc1 + &slv_qhs_aoss &slv_qhs_ipa + &slv_qns_snoc_memnoc &slv_qhs_usb3_phy + &slv_qhs_aop &slv_qhs_tcsr + &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg + &slv_qhs_usb3 &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn8>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_xm_sdc1: mas-xm-sdc1 { + cell-id = ; + label = "mas-xm-sdc1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn1>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_xm_usb3: mas-xm-usb3 { + cell-id = ; + label = "mas-xm-usb3"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_aggre_noc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + /*Internal nodes*/ + + /*Slaves*/ + + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_ipa_virt>; + qcom,bcms = <&bcm_ip0>; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_mc0>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_qns_memnoc_snoc:slv-qns-memnoc-snoc { + cell-id = ; + label = "slv-qns-memnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,connections = <&mas_qnm_memnoc>; + qcom,bcms = <&bcm_sh4>; + }; + + slv_qhs_aop:slv-qhs-aop { + cell-id = ; + label = "slv-qhs-aop"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_aoss:slv-qhs-aoss { + cell-id = ; + label = "slv-qhs-aoss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_audio:slv-qhs-audio { + cell-id = ; + label = "slv-qhs-audio"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_blsp1:slv-qhs-blsp1 { + cell-id = ; + label = "slv-qhs-blsp1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_crypto_cfg:slv-qhs-crypto-cfg { + cell-id = ; + label = "slv-qhs-crypto-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_pcie_parf:slv-qhs-pcie-parf { + cell-id = ; + label = "slv-qhs-pcie-parf"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_qpic:slv-qhs-qpic { + cell-id = ; + label = "slv-qhs-qpic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_sdc1:slv-qhs-sdc1 { + cell-id = ; + label = "slv-qhs-sdc1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_snoc_cfg:slv-qhs-snoc-cfg { + cell-id = ; + label = "slv-qhs-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qhm_snoc_cfg>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_spmi_fetcher:slv-qhs-spmi-fetcher { + cell-id = ; + label = "slv-qhs-spmi-fetcher"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_tlmm:slv-qhs-tlmm { + cell-id = ; + label = "slv-qhs-tlmm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_usb3:slv-qhs-usb3 { + cell-id = ; + label = "slv-qhs-usb3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qhs_usb3_phy:slv-qhs-usb3-phy { + cell-id = ; + label = "slv-qhs-usb3-phy"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_pn0>; + }; + + slv_qns_aggre_noc:slv-qns-aggre-noc { + cell-id = ; + label = "slv-qns-aggre-noc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_aggre_noc>; + }; + + slv_qns_aggre_noc_ipa:slv-qns-aggre-noc-ipa { + cell-id = ; + label = "slv-qns-aggre-noc-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_aggre_noc_ipa>; + }; + + slv_qns_snoc_memnoc:slv-qns-snoc-memnoc { + cell-id = ; + label = "slv-qns-snoc-memnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_gc>; + qcom,bcms = <&bcm_sn0>; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn1>; + }; + + slv_qxs_pcie:slv-qxs-pcie { + cell-id = ; + label = "slv-qxs-pcie"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn6>; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-audio-overlay.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a7943cd1092165b31b3025dbf3d6e1523ada709c --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-audio-overlay.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017, 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 "sdxpoorwills-audio-overlay.dtsi" + +&soc { + sound-tavil { + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrRight"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..261829f058667d4aeb6736b5554b2d863cd0fccf --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts @@ -0,0 +1,154 @@ +/* Copyright (c) 2017, 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 "sdxpoorwills.dtsi" +#include "sdxpoorwills-pinctrl.dtsi" +#include "sdxpoorwills-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP"; + compatible = "qcom,sdxpoorwills-cdp", + "qcom,sdxpoorwills", "qcom,cdp"; + qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>; +}; + +&serial_uart { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_console_active>; + status = "ok"; +}; + +&qnand_1 { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&vreg_sd_mmc>; + + vdd-io-supply = <&pmxpoorwills_l7>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 10000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,devfreq,freq-table = <50000000 200000000>; + + cd-gpios = <&tlmm 93 0x1>; + + status = "ok"; +}; + +&pmxpoorwills_vadc { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4d { + label = "pa_therm1"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4e { + label = "pa_therm2"; + reg = <0x4e>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4f { + label = "mdm_case_therm"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@52 { + label = "ambient_therm"; + reg = <0x52>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; +}; + +&i2c_3 { + status = "okay"; + #include "smb138x.dtsi" +}; + +&smb138x { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + interrupt-parent = <&tlmm>; + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; + + smb1381_charger: qcom,smb1381-charger@1000 { + compatible = "qcom,smb138x-charger"; + qcom,use-extcon; + }; +}; + +&smb138x_vbus { + status = "okay"; +}; + +&usb { + status = "okay"; + extcon = <&smb1381_charger>; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-ion.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a09b14997ac30e79bd250166211a4f58ca02f6e0 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-ion.dtsi @@ -0,0 +1,30 @@ +/* Copyright (c) 2017, 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 { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@28 { /* AUDIO HEAP */ + reg = <28>; + memory-region = <&audio_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..575febe29e3a23ec3060568e7cc359198e30d959 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts @@ -0,0 +1,153 @@ +/* Copyright (c) 2017, 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 "sdxpoorwills.dtsi" +#include "sdxpoorwills-pinctrl.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP"; + compatible = "qcom,sdxpoorwills-mtp", + "qcom,sdxpoorwills", "qcom,mtp"; + qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>; +}; + +&serial_uart { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_console_active>; + status = "ok"; +}; + +&qnand_1 { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&vreg_sd_mmc>; + + vdd-io-supply = <&pmxpoorwills_l7>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 10000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,devfreq,freq-table = <50000000 200000000>; + + cd-gpios = <&tlmm 93 0x1>; + + status = "ok"; +}; + +&pmxpoorwills_vadc { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4d { + label = "pa_therm1"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4e { + label = "pa_therm2"; + reg = <0x4e>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4f { + label = "mdm_case_therm"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@52 { + label = "ambient_therm"; + reg = <0x52>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; +}; + +&i2c_3 { + status = "okay"; + #include "smb138x.dtsi" +}; + +&smb138x { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + interrupt-parent = <&tlmm>; + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; + + smb1381_charger: qcom,smb1381-charger@1000 { + compatible = "qcom,smb138x-charger"; + qcom,use-extcon; + }; +}; + +&smb138x_vbus { + status = "okay"; +}; + +&usb { + status = "okay"; + extcon = <&smb1381_charger>; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e939bd2edab04b1b1815e4b61356fe9ab2b48901 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018, 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 + +&soc { + pcie0: qcom,pcie@1c00000 { + compatible = "qcom,pci-msm"; + cell-index = <0>; + + reg = <0x01c00000 0x2000>, + <0x01c02000 0x1000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40001000 0x1000>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1d00000>, + <0x01fce008 0x4>; + + reg-names = "parf", "phy", "dm_core", "elbi", "iatu", + "conf", "io", "bars", "tcsr"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1d00000>; + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4 5>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 119 0 + 0 0 0 1 &intc 0 141 0 + 0 0 0 2 &intc 0 142 0 + 0 0 0 3 &intc 0 143 0 + 0 0 0 4 &intc 0 144 0 + 0 0 0 5 &intc 0 140 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int"; + + qcom,phy-sequence = <0x840 0x03 0x0 + 0x094 0x08 0x0 + 0x154 0x33 0x0 + 0x058 0x0f 0x0 + 0x0a4 0x42 0x0 + 0x1bc 0x11 0x0 + 0x0bc 0x82 0x0 + 0x0d4 0x03 0x0 + 0x0d0 0x55 0x0 + 0x0cc 0x55 0x0 + 0x0b0 0x1a 0x0 + 0x0ac 0x0a 0x0 + 0x158 0x01 0x0 + 0x074 0x06 0x0 + 0x07c 0x16 0x0 + 0x084 0x36 0x0 + 0x1b0 0x1e 0x0 + 0x1ac 0xb9 0x0 + 0x050 0x07 0x0 + 0x29c 0x12 0x0 + 0x284 0x05 0x0 + 0x234 0xd9 0x0 + 0x238 0xcc 0x0 + 0x51c 0x03 0x0 + 0x518 0x1c 0x0 + 0x524 0x14 0x0 + 0x4ec 0x0e 0x0 + 0x4f0 0x4a 0x0 + 0x4f4 0x0f 0x0 + 0x5b4 0x04 0x0 + 0x434 0x7f 0x0 + 0x444 0x70 0x0 + 0x510 0x17 0x0 + 0x4d8 0x01 0x0 + 0x598 0xe0 0x0 + 0x59c 0xc8 0x0 + 0x5a0 0xc8 0x0 + 0x5a4 0x09 0x0 + 0x5a8 0xb1 0x0 + 0x584 0x24 0x0 + 0x588 0xe4 0x0 + 0x58c 0xec 0x0 + 0x590 0x39 0x0 + 0x594 0x36 0x0 + 0x570 0xef 0x0 + 0x574 0xef 0x0 + 0x578 0x2f 0x0 + 0x57c 0xd3 0x0 + 0x580 0x40 0x0 + 0x4fc 0x00 0x0 + 0x4f8 0xc0 0x0 + 0x9a4 0x01 0x0 + 0xc90 0x00 0x0 + 0xc40 0x01 0x0 + 0xc48 0x01 0x0 + 0xca0 0x11 0x0 + 0x048 0x90 0x0 + 0xc1c 0xc1 0x0 + 0x988 0x88 0x0 + 0x998 0x08 0x0 + 0x8dc 0x0d 0x0 + 0x800 0x00 0x0 + 0x844 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 57 0>; + wake-gpio = <&tlmm 53 0>; + + gdsc-vdd-supply = <&gdsc_pcie>; + vreg-1.8-supply = <&pmxpoorwills_l1>; + vreg-0.9-supply = <&pmxpoorwills_l4>; + vreg-cx-supply = <&pmxpoorwills_s5_level>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <872000 872000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,l0s-supported; + qcom,l1-supported; + qcom,l1ss-supported; + qcom,aux-clk-sync; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x40000000>; + + qcom,phy-status-offset = <0x814>; + + qcom,cpl-timeout = <0x2>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <0>; + + qcom,use-19p2mhz-aux-clk; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_AUX_CLK>, + <&clock_gcc GCC_PCIE_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_PCIE_SLEEP_CLK>, + <&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_0_sleep_clk", "pcie_phy_refgen_clk"; + + max-clock-frequency-hz = <0>, <0>, <0>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>; + + resets = <&clock_gcc GCC_PCIE_BCR>, + <&clock_gcc GCC_PCIE_PHY_BCR>; + + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi index ac02429862dd834e89421dbc7c25052f55e9095c..1e212b71e70dc3cd433d2663ecee6e91d1957f3c 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -31,5 +31,1408 @@ bias-disable; }; }; + + uart3_console_active: uart3_console_active { + mux { + pins = "gpio8", "gpio9"; + function = "blsp_uart3"; + }; + config { + pins = "gpio8", "gpio9"; + drive-strength = <2>; + bias-disable; + }; + }; + + uart3_console_sleep: uart3_console_sleep { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + config { + pins = "gpio8", "gpio9"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* I2C CONFIGURATION */ + i2c_1 { + i2c_1_active: i2c_1_active { + mux { + pins = "gpio2", "gpio3"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_1_sleep: i2c_1_sleep { + mux { + pins = "gpio2", "gpio3"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_2 { + i2c_2_active: i2c_2_active { + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_2_sleep: i2c_2_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_3 { + i2c_3_active: i2c_3_active { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_3_sleep: i2c_3_sleep { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_4 { + i2c_4_active: i2c_4_active { + mux { + pins = "gpio76", "gpio77"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio76", "gpio77"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_4_sleep: i2c_4_sleep { + mux { + pins = "gpio76", "gpio77"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio76", "gpio77"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_5 { + i2c_5_active: i2c_5_active { + mux { + pins = "gpio74", "gpio75"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio74", "gpio75"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_5_sleep: i2c_5_sleep { + mux { + pins = "gpio74", "gpio75"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio74", "gpio75"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_6 { + i2c_6_active: i2c_6_active { + mux { + pins = "gpio65", "gpio66"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio65", "gpio66"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_6_sleep: i2c_6_sleep { + mux { + pins = "gpio65", "gpio66"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio65", "gpio66"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_7 { + i2c_7_active: i2c_7_active { + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_7_sleep: i2c_7_sleep { + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + /* SPI CONFIGURATION */ + spi_1 { + spi_1_active: spi_1_active { + mux { + pins = "gpio72", "gpio73", + "gpio74", "gpio75"; + function = "blsp_spi1"; + }; + + config { + pins = "gpio72", "gpio73", + "gpio74", "gpio75"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_1_sleep: spi_1_sleep { + mux { + pins = "gpio72", "gpio73", + "gpio74", "gpio75"; + function = "blsp_spi1"; + }; + + config { + pins = "gpio72", "gpio73", + "gpio74", "gpio75"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_2 { + spi_2_active: spi_2_active { + mux { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + function = "blsp_spi2"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_2_sleep: spi_2_sleep { + mux { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + function = "blsp_spi2"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_3 { + spi_3_active: spi_3_active { + mux { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_3_sleep: spi_3_sleep { + mux { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_4 { + spi_4_active: spi_4_active { + mux { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + function = "blsp_spi4"; + }; + + config { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_4_sleep: spi_4_sleep { + mux { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + function = "blsp_spi4"; + }; + + config { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + pcie0 { + pcie0_clkreq_default: pcie0_clkreq_default { + mux { + pins = "gpio56"; + function = "pcie_clkreq"; + }; + config { + pins = "gpio56"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_perst_default: pcie0_perst_default { + mux { + pins = "gpio57"; + function = "gpio"; + }; + config { + pins = "gpio57"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie0_wake_default: pcie0_wake_default { + mux { + pins = "gpio53"; + function = "gpio"; + }; + config { + pins = "gpio53"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + /* HS UART CONFIGURATION */ + + blsp1_uart1a: blsp1_uart1a { + blsp1_uart1a_tx_active: blsp1_uart1a_tx_active { + mux { + pins = "gpio0"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1a_tx_sleep: blsp1_uart1a_tx_sleep { + mux { + pins = "gpio0"; + function = "gpio"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart1a_rxcts_active: blsp1_uart1a_rxcts_active { + mux { + pins = "gpio1", "gpio2"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio1", "gpio2"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1a_rxcts_sleep: blsp1_uart1a_rxcts_sleep { + mux { + pins = "gpio1", "gpio2"; + function = "gpio"; + }; + + config { + pins = "gpio1", "gpio2"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart1a_rfr_active: blsp1_uart1a_rfr_active { + mux { + pins = "gpio3"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1a_rfr_sleep: blsp1_uart1a_rfr_sleep { + mux { + pins = "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp1_uart1b: blsp1_uart1b { + blsp1_uart1b_tx_active: blsp1_uart1b_tx_active { + mux { + pins = "gpio20"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1b_tx_sleep: blsp1_uart1b_tx_sleep { + mux { + pins = "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart1b_rxcts_active: blsp1_uart1b_rxcts_active { + mux { + pins = "gpio21", "gpio22"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio21", "gpio22"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1b_rxcts_sleep: blsp1_uart1b_rxcts_sleep { + mux { + pins = "gpio21", "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio22"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart1b_rfr_active: blsp1_uart1b_rfr_active { + mux { + pins = "gpio23"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1b_rfr_sleep: blsp1_uart1b_rfr_sleep { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp1_uart2a: blsp1_uart2a { + blsp1_uart2a_tx_active: blsp1_uart2a_tx_active { + mux { + pins = "gpio4"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2a_tx_sleep: blsp1_uart2a_tx_sleep { + mux { + pins = "gpio4"; + function = "gpio"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart2a_rxcts_active: blsp1_uart2a_rxcts_active { + mux { + pins = "gpio5", "gpio6"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio5", "gpio6"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2a_rxcts_sleep: blsp1_uart2a_rxcts_sleep { + mux { + pins = "gpio5", "gpio6"; + function = "gpio"; + }; + + config { + pins = "gpio1", "gpio2"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart2a_rfr_active: blsp1_uart2a_rfr_active { + mux { + pins = "gpio7"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2a_rfr_sleep: blsp1_uart2a_rfr_sleep { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp1_uart2b: blsp1_uart2b { + blsp1_uart2b_tx_active: blsp1_uart2b_tx_active { + mux { + pins = "gpio63"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2b_tx_sleep: blsp1_uart2b_tx_sleep { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart2b_rxcts_active: blsp1_uart2b_rxcts_active { + mux { + pins = "gpio64", "gpio65"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio64", "gpio65"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2b_rxcts_sleep: blsp1_uart2b_rxcts_sleep { + mux { + pins = "gpio64", "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio64", "gpio65"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart2b_rfr_active: blsp1_uart2b_rfr_active { + mux { + pins = "gpio66"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2b_rfr_sleep: blsp1_uart2b_rfr_sleep { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp1_uart3: blsp1_uart3 { + blsp1_uart3_tx_active: blsp1_uart3_tx_active { + mux { + pins = "gpio8"; + function = "blsp_uart3"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart3_tx_sleep: blsp1_uart3_tx_sleep { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart3_rxcts_active: blsp1_uart3_rxcts_active { + mux { + pins = "gpio9", "gpio10"; + function = "blsp_uart3"; + }; + + config { + pins = "gpio9", "gpio10"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart3_rxcts_sleep: blsp1_uart3_rxcts_sleep { + mux { + pins = "gpio9", "gpio10"; + function = "gpio"; + }; + + config { + pins = "gpio9", "gpio10"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart3_rfr_active: blsp1_uart3_rfr_active { + mux { + pins = "gpio11"; + function = "blsp_uart3"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart3_rfr_sleep: blsp1_uart3_rfr_sleep { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp1_uart4a: blsp1_uart4a { + blsp1_uart4a_tx_active: blsp1_uart4a_tx_active { + mux { + pins = "gpio20"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4a_tx_sleep: blsp1_uart4a_tx_sleep { + mux { + pins = "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart4a_rxcts_active: blsp1_uart4a_rxcts_active { + mux { + pins = "gpio21", "gpio22"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio21", "gpio22"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4a_rxcts_sleep: blsp1_uart4a_rxcts_sleep { + mux { + pins = "gpio21", "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio22"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart4a_rfr_active: blsp1_uart4a_rfr_active { + mux { + pins = "gpio23"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4a_rfr_sleep: blsp1_uart4a_rfr_sleep { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp1_uart4b: blsp1_uart4b { + blsp1_uart4b_tx_active: blsp1_uart4b_tx_active { + mux { + pins = "gpio16"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4b_tx_sleep: blsp1_uart4b_tx_sleep { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart4b_rxcts_active: blsp1_uart4b_rxcts_active { + mux { + pins = "gpio17", "gpio18"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4b_rxcts_sleep: blsp1_uart4b_rxcts_sleep { + mux { + pins = "gpio17", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart4b_rfr_active: blsp1_uart4b_rfr_active { + mux { + pins = "gpio19"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4b_rfr_sleep: blsp1_uart4b_rfr_sleep { + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + wcd9xxx_intr { + wcd_intr_default: wcd_intr_default{ + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-enable; + }; + }; + }; + + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio86"; + function = "gpio"; + }; + config { + pins = "gpio86"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio86"; + function = "gpio"; + }; + config { + pins = "gpio86"; + drive-strength = <8>; + bias-pull-down; + output-high; + }; + }; + }; + + i2s_mclk { + i2s_mclk_sleep: i2s_mclk_sleep { + mux { + pins = "gpio62"; + function = "i2s_mclk"; + }; + + config { + pins = "gpio62"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + i2s_mclk_active: i2s_mclk_active { + mux { + pins = "gpio62"; + function = "i2s_mclk"; + }; + + config { + pins = "gpio62"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + }; + + pmx_pri_mi2s_aux { + pri_ws_sleep: pri_ws_sleep { + mux { + pins = "gpio12"; + function = "gpio"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_sck_sleep: pri_sck_sleep { + mux { + pins = "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_dout_sleep: pri_dout_sleep { + mux { + pins = "gpio14"; + function = "gpio"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_ws_active_master: pri_ws_active_master { + mux { + pins = "gpio12"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + + pri_sck_active_master: pri_sck_active_master { + mux { + pins = "gpio15"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + + pri_ws_active_slave: pri_ws_active_slave { + mux { + pins = "gpio12"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + }; + }; + + pri_sck_active_slave: pri_sck_active_slave { + mux { + pins = "gpio15"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + }; + }; + + pri_dout_active: pri_dout_active { + mux { + pins = "gpio14"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + }; + + pmx_pri_mi2s_aux_din { + pri_din_sleep: pri_din_sleep { + mux { + pins = "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_din_active: pri_din_active { + mux { + pins = "gpio13"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pmx_sec_mi2s_aux { + sec_ws_sleep: sec_ws_sleep { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_sck_sleep: sec_sck_sleep { + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_dout_sleep: sec_dout_sleep { + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_ws_active_master: sec_ws_active_master { + mux { + pins = "gpio16"; + function = "sec_mi2s_ws_a"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + + sec_sck_active_master: sec_sck_active_master { + mux { + pins = "gpio19"; + function = "sec_mi2s_sck_a"; + }; + + config { + pins = "gpio19"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + + sec_ws_active_slave: sec_ws_active_slave { + mux { + pins = "gpio16"; + function = "sec_mi2s_ws_a"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + }; + }; + + sec_sck_active_slave: sec_sck_active_slave { + mux { + pins = "gpio19"; + function = "sec_mi2s_sck_a"; + }; + + config { + pins = "gpio19"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + }; + }; + + sec_dout_active: sec_dout_active { + mux { + pins = "gpio18"; + function = "sec_mi2s_data1_a"; + }; + + config { + pins = "gpio18"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL*/ + output-high; + }; + }; + }; + + pmx_sec_mi2s_aux_din { + sec_din_sleep: sec_din_sleep { + mux { + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_din_active: sec_din_active { + mux { + pins = "gpio17"; + function = "sec_mi2s_data0_a"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cd_on: cd_on { + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc1_cd_off: cd_off { + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + drive-strength = <2>; + bias-disable; + }; + }; + + smb_int_default: smb_int_default { + mux { + pins = "gpio42"; + function = "gpio"; + }; + config { + pins = "gpio42"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + }; +}; + +&pmxpoorwills_gpios { + ambient_therm { + ambient_therm_default: ambient_therm_default { + pins = "gpio2"; + bias-high-impedance; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..37903b9c4ffe2f83654dd8fa6b61f8548b8c3259 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi @@ -0,0 +1,404 @@ +/* Copyright (c) 2017-2018, 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 +#include + +&soc { + /* RPMh regulators */ + + /* pmxpoorwills S1 - VDD_MODEM supply */ + rpmh-regulator-modemlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mss.lvl"; + pmxpoorwills_s1_level: regualtor-pmxpoorwills-s1 { + regulator-name = "pmxpoorwills_s1_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa4"; + pmxpoorwills_s4: regulator-pmxpoorwills-s4 { + regulator-name = "pmxpoorwills_s4"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; + + /* pmxpoorwills S5 - VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pmxpoorwills_s5_level-parent-supply = <&pmxpoorwills_l9_level>; + pmxpoorwills_s5_level_ao-parent-supply = + <&pmxpoorwills_l9_level_ao>; + pmxpoorwills_s5_level: regualtor-pmxpoorwills-s5-level { + regulator-name = "pmxpoorwills_s5_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + pmxpoorwills_s5_level_ao: regualtor-pmxpoorwills-s5-level-ao { + regulator-name = "pmxpoorwills_s5_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l1: regualtor-pmxpoorwills-11 { + regulator-name = "pmxpoorwills_l1"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l2: regualtor-pmxpoorwills-12 { + regulator-name = "pmxpoorwills_l2"; + qcom,set = ; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <1128000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l3: regualtor-pmxpoorwills-l3 { + regulator-name = "pmxpoorwills_l3"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l4: regualtor-pmxpoorwills-l4 { + regulator-name = "pmxpoorwills_l4"; + qcom,set = ; + regulator-min-microvolt = <872000>; + regulator-max-microvolt = <872000>; + qcom,init-voltage = <872000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l5: regualtor-pmxpoorwills-l5 { + regulator-name = "pmxpoorwills_l5"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l7: regualtor-pmxpoorwills-l7 { + regulator-name = "pmxpoorwills_l7"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2952000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l8: regualtor-pmxpoorwills-l8 { + regulator-name = "pmxpoorwills_l8"; + qcom,set = ; + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + qcom,init-voltage = <480000>; + qcom,init-mode = ; + }; + }; + + /* pmxpoorwills L9 - VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + pmxpoorwills_l9_level: regualtor-pmxpoorwills-l9-level { + regulator-name = "pmxpoorwills_l9_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pmxpoorwills_l9_level_ao: regualtor-pmxpoorwills-l9-level-ao { + regulator-name = "pmxpoorwills_l9_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pmxpoorwills_l9_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l10: regualtor-pmxpoorwills-l10 { + regulator-name = "pmxpoorwills_l10"; + qcom,set = ; + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + qcom,init-voltage = <3088000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l11: regualtor-pmxpoorwills-l11 { + regulator-name = "pmxpoorwills_l11"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l12: regualtor-pmxpoorwills-l12 { + regulator-name = "pmxpoorwills_l12"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l13: regualtor-pmxpoorwills-l13 { + regulator-name = "pmxpoorwills_l13"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l14: regualtor-pmxpoorwills-l14 { + regulator-name = "pmxpoorwills_l14"; + qcom,set = ; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <600000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pmxpoorwills_l16: regualtor-pmxpoorwills-l16 { + regulator-name = "pmxpoorwills_l16"; + qcom,set = ; + regulator-min-microvolt = <304000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <304000>; + qcom,init-mode = ; + }; + }; + + /* VREF_RGMII */ + rpmh-regulator-rgmii { + compatible = "qcom,rpmh-xob-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "vrefa2"; + vreg_rgmii: regulator-rgmii { + regulator-name = "vreg_rgmii"; + qcom,set = ; + }; + }; + + /* Stub regulators */ + + /* + * RPMh does not provide support for PMXPOORWILLS L6 because it is + * always on at 1.8 V. Therefore, use a fixed regulator for L6. + */ + pmxpoorwills_l6: regulator-pmxpoorwills-l6 { + compatible = "regulator-fixed"; + regulator-name = "pmxpoorwills_l6"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vreg_sd_mmc: vreg_sd_mmc { + compatible = "regulator-fixed"; + regulator-name = "vreg_sd_mmc"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&tlmm 92 GPIO_ACTIVE_HIGH>; + }; + + vreg_emac_phy: emac_phy_regulator { + compatible = "regulator-fixed"; + regulator-name = "emac_phy"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <100>; + gpio = <&tlmm 96 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vreg_rgmii_io_pads: rgmii_io_pads_regulator { + compatible = "regulator-fixed"; + regulator-name = "rgmii_io_pads"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <100>; + gpio = <&tlmm 83 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts index 78a26c2f5ac9c8ecb7612cd37e2f5d602e9014ed..b73d3aa958420573948d9f1cc606159c56675f60 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts @@ -23,8 +23,82 @@ qcom,board-id = <15 0>; }; -&blsp1_uart2 { +&soc { + /* Delete rpmh regulators */ + /delete-node/ rpmh-regulator-modemlvl; + /delete-node/ rpmh-regulator-smpa4; + /delete-node/ rpmh-regulator-cxlvl; + /delete-node/ rpmh-regulator-ldoa1; + /delete-node/ rpmh-regulator-ldoa2; + /delete-node/ rpmh-regulator-ldoa3; + /delete-node/ rpmh-regulator-ldoa4; + /delete-node/ rpmh-regulator-ldoa5; + /delete-node/ rpmh-regulator-ldoa7; + /delete-node/ rpmh-regulator-ldoa8; + /delete-node/ rpmh-regulator-mxlvl; + /delete-node/ rpmh-regulator-ldoa10; + /delete-node/ rpmh-regulator-ldoa11; + /delete-node/ rpmh-regulator-ldoa12; + /delete-node/ rpmh-regulator-ldoa13; + /delete-node/ rpmh-regulator-ldoa14; + /delete-node/ rpmh-regulator-ldoa16; + /delete-node/ rpmh-regulator-rgmii; + + /delete-node/ thermal-zones; +}; + +#include "sdxpoorwills-stub-regulator.dtsi" + +&serial_uart { pinctrl-names = "default"; pinctrl-0 = <&uart2_console_active>; status = "ok"; }; + +&gdsc_usb30 { + compatible = "regulator-fixed"; +}; + +&gdsc_pcie { + compatible = "regulator-fixed"; +}; + +&ipa_hw { + qcom,ipa-hw-mode = <1>; /* IPA hw type = Virtual */ +}; + +&usb { + /delete-property/ qcom,usb-dbm; + qcom,charging-disabled; + dwc3@a600000 { + usb-phy = <&usb2_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&usb2_phy { + reg = <0xff1000 0x1000>, + <0x0a60cd00 0x40>; + reg-names = "hsusb_phy_base", + "emu_phy_base"; + qcom,emu-init-seq = <0x19 0x404 + 0x20 0x414 + 0x79 0x410 + 0x00 0x418 + 0x99 0x404 + 0x04 0x408 + 0xd9 0x404>; + + qcom,emu-dcm-reset-seq = <0x100000 0x20 + 0x0 0x20 + 0x1e0 0x20 + 0x5 0x14>; +}; + +&usb3_qmp_phy { + status = "disabled"; +}; + +&qnand_1 { + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fbfaa0d082af7808a8c39f940ed5519b92abb48b --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi @@ -0,0 +1,132 @@ +/* Copyright (c) 2017, 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 + +&soc { + qcom,smp2p-modem@17811008 { + compatible = "qcom,smp2p"; + reg = <0x17811008 0x4>; + qcom,remote-pid = <1>; + qcom,irq-bitmask = <0x4000>; + interrupts = ; + }; + + smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_in { + compatible = "qcom,smp2pgpio_test_smp2p_15_in"; + gpios = <&smp2pgpio_smp2p_15_in 0 0>; + }; + + smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_out { + compatible = "qcom,smp2pgpio_test_smp2p_15_out"; + gpios = <&smp2pgpio_smp2p_15_out 0 0>; + }; + + smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_in { + compatible = "qcom,smp2pgpio_test_smp2p_1_in"; + gpios = <&smp2pgpio_smp2p_1_in 0 0>; + }; + + smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_out { + compatible = "qcom,smp2pgpio_test_smp2p_1_out"; + gpios = <&smp2pgpio_smp2p_1_out 0 0>; + }; + + /* ssr - inbound entry from mss */ + smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to mss */ + smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - outbound entry to mss */ + smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - inbound entry from mss */ + smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-stub-regulator.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-stub-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7c6b7b074dcbd65ff7db94fb7e5c6a7ca4df2137 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-stub-regulator.dtsi @@ -0,0 +1,176 @@ +/* Copyright (c) 2017, 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 + +/* Stub regulators */ +/ { + pmxpoorwills_s1: regualtor-pmxpoorwills-s1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_s1"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + }; + + pmxpoorwills_s4: regualtor-pmxpoorwills-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_s4"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + /* VDD CX supply */ + pmxpoorwills_s5_level: regualtor-pmxpoorwills-s5-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_s5_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pmxpoorwills_s5_level_ao: regualtor-pmxpoorwills-s5-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_s5_level_ao"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pmxpoorwills_l1: regualtor-pmxpoorwills-11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pmxpoorwills_l2: regualtor-pmxpoorwills-12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + }; + + pmxpoorwills_l3: regualtor-pmxpoorwills-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + }; + + pmxpoorwills_l4: regualtor-pmxpoorwills-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <872000>; + regulator-max-microvolt = <872000>; + }; + + pmxpoorwills_l5: regualtor-pmxpoorwills-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pmxpoorwills_l7: regualtor-pmxpoorwills-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pmxpoorwills_l8: regualtor-pmxpoorwills-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + }; + + /* VDD MX supply */ + pmxpoorwills_l9_level: regualtor-pmxpoorwills-l9-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l9_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pmxpoorwills_l9_level_ao: regualtor-pmxpoorwills-l9-level_ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l9_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pmxpoorwills_l10: regualtor-pmxpoorwills-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + }; + + pmxpoorwills_l11: regualtor-pmxpoorwills-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <2848000>; + }; + + pmxpoorwills_l12: regualtor-pmxpoorwills-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l12"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + }; + + pmxpoorwills_l13: regualtor-pmxpoorwills-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l13"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <2848000>; + }; + + pmxpoorwills_l14: regualtor-pmxpoorwills-l14 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l14"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <620000>; + regulator-max-microvolt = <752000>; + }; + + pmxpoorwills_l16: regualtor-pmxpoorwills-l16 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxpoorwills_l16"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + }; + + /* VREF_RGMII */ + vreg_rgmii: rgmii-regulator { + compatible = "regulator-fixed"; + regulator-name = "vreg_rgmii"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..65467f9d40f460c9febab973efcbfc0b22cf7f71 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi @@ -0,0 +1,376 @@ +/* Copyright (c) 2017, 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 + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi_cooling_devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + aoss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-q6-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + ddrss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 4>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-vpe-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 5>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + aoss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + tracks-low; + trips { + aoss_trip: aoss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + modem_vdd_cdev { + trip = <&aoss_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cx_vdd_cdev { + trip = <&aoss_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + }; + }; + + mdm-q6-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 1>; + tracks-low; + trips { + mdm_q6_trip: mdm-q6-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + modem_vdd_cdev { + trip = <&mdm_q6_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mdm_q6_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cx_vdd_cdev { + trip = <&mdm_q6_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mdm_q6_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + }; + }; + + ddrss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 2>; + tracks-low; + trips { + ddrss_trip: ddrss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + modem_vdd_cdev { + trip = <&ddrss_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&ddrss_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cx_vdd_cdev { + trip = <&ddrss_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&ddrss_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + }; + }; + + cpu-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 3>; + tracks-low; + trips { + cpu_trip: cpu-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + modem_vdd_cdev { + trip = <&cpu_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cx_vdd_cdev { + trip = <&cpu_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + }; + }; + + mdm-core-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 4>; + tracks-low; + trips { + mdm_trip: mdm-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + modem_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cx_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + }; + }; + + mdm-vpe-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 5>; + tracks-low; + trips { + mdm_vpe_trip: mdm-vpe-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + modem_vdd_cdev { + trip = <&mdm_vpe_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mdm_vpe_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cx_vdd_cdev { + trip = <&mdm_vpe_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mdm_vpe_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + }; + }; + + xo-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmxpoorwills_vadc 0x4c>; + thermal-governor = "user_space"; + }; + + pa-therm1-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmxpoorwills_vadc 0x4d>; + thermal-governor = "user_space"; + }; + + pa-therm2-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmxpoorwills_vadc 0x4e>; + thermal-governor = "user_space"; + }; + + mdm-case-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmxpoorwills_vadc 0x4f>; + thermal-governor = "user_space"; + }; + + ambient-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmxpoorwills_vadc 0x52>; + thermal-governor = "user_space"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..77e176312d01d7fdb9d3affa2ff17d021390b7c7 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2017-2018, 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 +#include +#include + +&soc { + /* USB port for DWC3 controller */ + usb: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0xf8c00>; + reg-names = "core_base"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 131 0>, <0 130 0>, <0 59 0>; + interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq"; + + USB3_GDSC-supply = <&gdsc_usb30>; + qcom,usb-dbm = <&dbm_1p5>; + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,num-gsi-evt-buffs = <0x3>; + + clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, + <&clock_gcc GCC_SYS_NOC_USB3_CLK>, + <&clock_gcc GCC_USB30_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_SLEEP_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>; + + clock-names = "core_clk", "iface_clk", "utmi_clk", "sleep_clk", + "cfg_ahb_clk", "xo"; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + + resets = <&clock_gcc GCC_USB30_BCR>; + reset-names = "core_reset"; + status = "disabled"; + + qcom,msm-bus,name = "usb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + ; + + dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xcd00>; + interrupt-parent = <&intc>; + interrupts = <0 133 0>; + usb-phy = <&usb2_phy>, <&usb3_qmp_phy>; + tx-fifo-resize; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + }; + + qcom,usbbam@a704000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xa704000 0x17000>; + interrupts = <0 132 0>; + + qcom,bam-type = <0>; + qcom,usb-bam-fifo-baseaddr = <0x14689000>; + qcom,usb-bam-num-pipes = <8>; + qcom,ignore-core-reset-ack; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x6064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + }; + + /* USB port for High Speed PHY */ + usb2_phy: hsphy@ff1000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0xff1000 0x400>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pmxpoorwills_l4>; + vdda18-supply = <&pmxpoorwills_l5>; + vdda33-supply = <&pmxpoorwills_l10>; + qcom,vdd-voltage-level = <0 872000 872000>; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "ref_clk_src", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_QUSB2PHY_BCR>; + reset-names = "phy_reset"; + }; + + dbm_1p5: dbm@a6f8000 { + compatible = "qcom,usb-dbm-1p5"; + reg = <0xa6f8000 0x400>; + qcom,reset-ep-after-lpm-resume; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + /* USB port for Super Speed PHY */ + usb3_qmp_phy: ssphy@ff0000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0xff0000 0x1000>, + <0x01fcb244 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; + + vdd-supply = <&pmxpoorwills_l4>; + core-supply = <&pmxpoorwills_l1>; + qcom,vdd-voltage-level = <0 872000 872000>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + <0x058 0x07 0x00 /* QSERDES_COM_PLL_IVCO */ + 0x094 0x1a 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */ + 0x044 0x14 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */ + 0x154 0x31 0x00 /* QSERDES_COM_CLK_SELECT */ + 0x04c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */ + 0x0a0 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */ + 0x17c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */ + 0x184 0x05 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */ + 0x1bc 0x11 0x00 /* QSERDES_COM_BIN_VCOCAL_HSCLK_SEL*/ + 0x158 0x01 0x00 /* QSERDES_COM_HSCLK_SEL */ + 0x0bc 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */ + 0x0cc 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */ + 0x0d0 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */ + 0x0d4 0x02 0x00 /* COM_DIV_FRAC_START3_MODE0 */ + 0x1ac 0xca 0x00 /* COM_BIN_VCOCAL_CMP_CODE1_MODE0 */ + 0x1b0 0x1e 0x00 /* COM_BIN_VCOCAL_CMP_CODE2_MODE0 */ + 0x074 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */ + 0x07c 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */ + 0x084 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */ + 0x0f0 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */ + 0x0ec 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */ + 0x114 0x02 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */ + 0x110 0x24 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */ + 0x168 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */ + 0x0b0 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */ + 0x0ac 0x14 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */ + 0x0a4 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */ + 0x174 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */ + 0x0a8 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */ + 0x10c 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */ + 0x050 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */ + 0x00c 0x0a 0x00 /* QSERDES_COM_BG_TIMER */ + 0x010 0x01 0x00 /* QSERDES_COM_SSC_EN_CENTER */ + 0x01c 0x31 0x00 /* QSERDES_COM_SSC_PER1 */ + 0x020 0x01 0x00 /* QSERDES_COM_SSC_PER2 */ + 0x014 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER1 */ + 0x018 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER2 */ + 0x030 0xde 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE1 */ + 0x034 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2_MODE1 */ + 0x024 0xde 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE0 */ + 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE0 */ + 0x4a4 0x3f 0x00 /* QSERDES_RX_RX_IDAC_ENABLES */ + 0x594 0xbf 0x00 /* QSERDES_RX_RX_MODE_01_HIGH4 */ + 0x590 0x09 0x00 /* QSERDES_RX_RX_MODE_01_HIGH3 */ + 0x58c 0xc8 0x00 /* QSERDES_RX_RX_MODE_01_HIGH2 */ + 0x588 0xc8 0x00 /* QSERDES_RX_RX_MODE_01_HIGH */ + 0x584 0xe0 0x00 /* QSERDES_RX_RX_MODE_01_LOW */ + 0x444 0x01 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */ + 0x408 0x0a 0x00 /* QSERDES_RX_UCDR_FO_GAIN */ + 0x414 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */ + 0x430 0x2f 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */ + 0x43c 0xff 0x00 /* RX_UCDR_FASTLOCK_COUNT_LOW */ + 0x440 0x0f 0x00 /* RX_UCDR_FASTLOCK_COUNT_HIGH */ + 0x420 0x0a 0x00 /* QSERDES_RX_UCDR_SVS_FO_GAIN */ + 0x42c 0x06 0x00 /* QSERDES_RX_UCDR_SVS_SO_GAIN */ + 0x434 0x7f 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */ + 0x4d8 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */ + 0x4ec 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */ + 0x4f0 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */ + 0x4f4 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */ + 0x5b4 0x04 0x00 /* QSERDES_RX_DFE_EN_TIMER */ + 0x510 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */ + 0x514 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */ + 0x51c 0x04 0x00 /* QSERDES_RX_SIGDET_CNTRL */ + 0x524 0x1a 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */ + 0x4fc 0x00 0x00 /* QSERDES_RX_RX_IDAC_TSETTLE_HIGH */ + 0x4f8 0xc0 0x00 /* QSERDES_RX_RX_IDAC_TSETTLE_LOW */ + 0x258 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */ + 0x29c 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */ + 0x284 0x05 0x00 /* QSERDES_TX_LANE_MODE_1 */ + 0x288 0x02 0x00 /* QSERDES_TX_LANE_MODE_2 */ + 0x28c 0x00 0x00 /* QSERDES_TX_LANE_MODE_3*/ + 0x89c 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */ + 0x8a0 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */ + 0x8a4 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */ + 0x8a8 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */ + 0x898 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */ + 0x8c4 0xd0 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */ + 0x8c8 0x17 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */ + 0x8cc 0x20 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */ + 0x890 0x4f 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG1 */ + 0x990 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */ + 0x994 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */ + 0x988 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */ + 0xe2c 0x75 0x00 /* USB3_RXEQTRAINING_WAIT_TIME */ + 0xe38 0x07 0x00 /* USB3_RXEQTRAINING_DFE_TIME_S2 */ + 0xe18 0x64 0x00 /* USB3_LFPS_DET_HIGH_COUNT_VAL */ + 0x9c0 0x88 0x00 /* USB3_UNI_PCS_ALIGN_DETECT_CONFIG1 */ + 0x9c4 0x13 0x00 /* USB3_UNI_PCS_ALIGN_DETECT_CONFIG2 */ + 0x9dc 0x0d 0x00 /* USB3_UNI_PCS_EQ_CONFIG1 */ + 0x9e0 0x0d 0x00 /* USB3_UNI_PCS_EQ_CONFIG2 */ + 0x8dc 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */ + 0x8e0 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */ + 0xffffffff 0xffffffff 0x00>; + + qcom,qmp-phy-reg-offset = + <0x814 /* USB3_UNI_PCS_PCS_STATUS */ + 0xe08 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */ + 0xe14 /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */ + 0x840 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */ + 0x800 /* USB3_UNI_PCS_SW_RESET */ + 0x844>; /* USB3_UNI_PCS_START_CONTROL */ + + clocks = <&clock_gcc GCC_USB3_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_PHY_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "cfg_ahb_clk"; + resets = <&clock_gcc GCC_USB3_PHY_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-wcd.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-wcd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9303ed163e91f3f91af8f6187fbc94b9d2b713c9 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-wcd.dtsi @@ -0,0 +1,80 @@ +/* Copyright (c) 2016-2017, 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. + */ + +&i2c_3 { + tavil_codec { + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctrl"; + qcom,num-gpios = <5>; + gpio-controller; + #gpio-cells = <2>; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + + spkr_2_wcd_en_active: spkr_2_sd_n_active { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + output-high; + }; + }; + + spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + input-enable; + }; + }; + }; + + wsa_spkr_wcd_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_wcd_en_active>; + pinctrl-1 = <&spkr_1_wcd_en_sleep>; + }; + + wsa_spkr_wcd_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_wcd_en_active>; + pinctrl-1 = <&spkr_2_wcd_en_sleep>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 0078617a50547302662459e1f46cde07e688e1b2..5829942932fe2eacf6cfe68a6ed1298108786449 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,14 +10,19 @@ * GNU General Public License for more details. */ - +#include #include "skeleton.dtsi" +#include +#include #include +#include +#include +#include / { model = "Qualcomm Technologies, Inc. SDX POORWILLS"; compatible = "qcom,sdxpoorwills"; - qcom,msm-id = <334 0x0>; + qcom,msm-id = <334 0x0>, <335 0x0>; interrupt-parent = <&intc>; reserved-memory { @@ -25,12 +30,37 @@ #size-cells = <1>; ranges; - peripheral2_mem: peripheral2_region@8fd00000 { + peripheral2_mem: peripheral2_region@8fe00000 { compatible = "removed-dma-pool"; no-map; - reg = <0x8fd00000 0x300000>; + reg = <0x8fe00000 0x200000>; label = "peripheral2_mem"; }; + + sbl_region: sbl_region@8fd00000 { + no-map; + reg = <0x8fd00000 0x100000>; + label = "sbl_mem"; + }; + + hyp_region: hyp_region@8fc00000 { + no-map; + reg = <0x8fc00000 0x80000>; + label = "hyp_mem"; + }; + + mss_mem: mss_region@87400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x87400000 0x8300000>; + label = "mss_mem"; + }; + + audio_mem: audio_region@0 { + compatible = "shared-dma-pool"; + reusable; + size = <0x400000>; + }; }; cpus { @@ -38,12 +68,19 @@ #address-cells = <1>; CPU0: cpu@0 { - device-type = "cpu"; + device_type = "cpu"; compatible = "arm,cortex-a7"; reg = <0x0>; + #cooling-cells = <2>; }; }; + aliases { + qpic_nand1 = &qnand_1; + pci-domain0 = &pcie0; + sdhc1 = &sdhc_1; /* SDC1 eMMC/SD/SDIO slot */ + }; + soc: soc { }; }; @@ -136,25 +173,639 @@ }; }; + msm_cpufreq: qcom,msm-cpufreq { + compatible = "qcom,msm-cpufreq"; + clocks = <&clock_cpu APCS_CLK>; + clock-names = "cpu0_clk"; + + qcom,cpufreq-table-0 = + < 153600 >, + < 300000 >, + < 345600 >, + < 576000 >, + < 1094400 >, + < 1497600 >; + }; + clock_gcc: qcom,gcc@100000 { - compatible = "qcom,dummycc"; - clock-output-names = "gcc_clocks"; + compatible = "qcom,gcc-sdxpoorwills"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pmxpoorwills_s5_level>; + vdd_cx_ao-supply = <&pmxpoorwills_s5_level_ao>; #clock-cells = <1>; + #reset-cells = <1>; }; - clock_cpu: qcom,clock-a7@17810008 { - compatible = "qcom,dummycc"; - clock-output-names = "cpu_clocks"; + clock_cpu: qcom,clock-a7@17808100 { + compatible = "qcom,cpu-sdxpoorwills"; + clocks = <&clock_rpmh RPMH_CXO_CLK_A>; + clock-names = "xo_ao"; + qcom,a7cc-init-rate = <1497600000>; + reg = <0x17808100 0x7F10>; + reg-names = "apcs_pll"; + qcom,rcg-reg-offset = <0x7F08>; + + vdd_dig_ao-supply = <&pmxpoorwills_s5_level_ao>; + cpu-vdd-supply = <&pmxpoorwills_s5_level_ao>; + qcom,speed0-bin-v0 = + < 0 RPMH_REGULATOR_LEVEL_OFF>, + < 345600000 RPMH_REGULATOR_LEVEL_LOW_SVS>, + < 576000000 RPMH_REGULATOR_LEVEL_SVS>, + < 1094400000 RPMH_REGULATOR_LEVEL_NOM>, + < 1497600000 RPMH_REGULATOR_LEVEL_TURBO>; #clock-cells = <1>; }; - blsp1_uart2: serial@831000 { + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sdxpoorwills"; + #clock-cells = <1>; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + }; + + clock_aop: qcom,aopclk { + compatible = "qcom,aop-qmp-clk-v1"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <53 747>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = + < 1 >; + }; + + serial_uart: serial@831000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x831000 0x200>; interrupts = <0 26 0>; status = "disabled"; - clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + clocks = <&clock_gcc GCC_BLSP1_UART3_APPS_CLK>, <&clock_gcc GCC_BLSP1_AHB_CLK>; clock-names = "core", "iface"; }; + + gdsc_usb30: qcom,gdsc@10b004 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_usb30"; + reg = <0x0010b004 0x4>; + }; + + qcom,sps { + compatible = "qcom,msm_sps_4k"; + qcom,pipe-attr-ee; + }; + + gdsc_pcie: qcom,gdsc@137004 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_pcie"; + reg = <0x00137004 0x4>; + }; + + gdsc_emac: qcom,gdsc@147004 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_emac"; + reg = <0x00147004 0x4>; + }; + + qnand_1: nand@1b00000 { + compatible = "qcom,msm-nand"; + reg = < 0x01b00000 0x10000>, + <0x01b04000 0x1a000>; + reg-names = "nand_phys", + "bam_phys"; + qcom,reg-adjustment-offset = <0x4000>; + qcom,qpic-clk-rpmh; + + interrupts = <0 135 0>; + interrupt-names = "bam_irq"; + + qcom,msm-bus,name = "qpic_nand"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + + qcom,msm-bus,vectors-KBps = + <91 512 0 0>, + /* Voting for max b/w on PNOC bus for now */ + <91 512 400000 400000>; + + status = "disabled"; + }; + + sdhc_1: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 210 0>, <0 227 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */ + <78 512 1600 3200>, /* 400 KB/s*/ + <78 512 80000 160000>, /* 20 MB/s */ + <78 512 100000 200000>, /* 25 MB/s */ + <78 512 200000 400000>, /* 50 MB/s */ + <78 512 400000 800000>, /* 100 MB/s */ + <78 512 400000 800000>, /* 200 MB/s */ + <78 512 2048000 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x0>; + qcom,pm-qos-cmdq-latency-us = <70>; + qcom,pm-qos-legacy-latency-us = <70>; + qcom,pm-qos-irq-type = "affine_cores"; + qcom,pm-qos-irq-cpu = <0>; + qcom,pm-qos-irq-latency = <70>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + status = "disabled"; + }; + + qcom,msm-imem@1468B000 { + compatible = "qcom,msm-imem"; + reg = <0x1468B000 0x1000>; /* Address and size of IMEM */ + ranges = <0x0 0x1468B000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; +}; + + restart@c264000 { + compatible = "qcom,pshold"; + reg = <0x0c264000 0x4>, + <0x01fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + tsens0: tsens@c222000 { + compatible = "qcom,tsens24xx"; + reg = <0xc222000 0x4>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 163 0>, <0 165 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + thermal_zones: thermal-zones { }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + }; + + spmi_bus: qcom,spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0x1100>, + <0xc600000 0x2000000>, + <0xe600000 0x100000>, + <0xe700000 0xa0000>, + <0xc40a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + qcom,ipc-spinlock@1f40000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1f40000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,smem@8fe40000 { + compatible = "qcom,smem"; + reg = <0x8fe40000 0xc0000>, + <0x17811008 0x4>, + <0x1fd4000 0x8>; + reg-names = "smem", "irq-reg-base", + "smem_targ_info_reg"; + qcom,mpu-enabled; + }; + + qcom,glink-smem-native-xprt-modem@8fe40000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x8fe40000 0xc0000>, + <0x17811008 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x8000>; + interrupts = ; + label = "mpss"; + }; + + qcom,ipc_router { + compatible = "qcom,ipc_router"; + qcom,node-id = <1>; + }; + + qcom,ipc_router_modem_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "mpss"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-loopback_cntl { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl"; + }; + + qcom,glinkpkt-loopback_data { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x4080000 0x100>; + interrupts = <0 250 1>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + vdd_cx-supply = <&pmxpoorwills_s5_level>; + qcom,proxy-reg-names = "vdd_cx"; + + qcom,pas-id = <4>; + qcom,smem-id = <421>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,firmware-name = "modem"; + memory-region = <&mss_mem>; + status = "ok"; + + /* GPIO inputs from mss */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>; + + /* GPIO output to mss */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + }; + + apps_rsc: mailbox@17840000 { + compatible = "qcom,tcs-drv"; + label = "apps_rsc"; + reg = <0x17840000 0x100>, <0x17840d00 0x3000>; + interrupts = <0 17 0>; + #mbox-cells = <1>; + qcom,drv-id = <1>; + qcom,tcs-config = , + , + , + ; + }; + + cmd_db: qcom,cmd-db@c37000c { + compatible = "qcom,cmd-db"; + reg = <0xc37000c 8>; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-loaduC; + qcom,ipa-advertise-sg-support; + }; + + system_pm { + compatible = "qcom,system-pm"; + mboxes = <&apps_rsc 0>; + }; + + ipa_hw: qcom,ipa@01e00000 { + compatible = "qcom,ipa"; + reg = <0x1e00000 0x34000>, + <0x1e04000 0x28000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = + <0 241 0>, + <0 47 0>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <14>; /* IPA core version = IPAv4.0 */ + qcom,ipa-hw-mode = <0>; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,mhi-event-ring-id-limits = <9 10>; /* start and end */ + qcom,modem-cfg-emb-pipe-flt; + qcom,use-ipa-pm; + qcom,bandwidth-vote-for-ipa; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <4>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <90 512 0 0>, + <90 585 0 0>, + <1 676 0 0>, + <143 777 0 0>, + /* SVS2 */ + <90 512 3616000 7232000>, + <90 585 300000 600000>, + <1 676 90000 180000>, /*gcc_config_noc_clk_src */ + <143 777 0 120>, /* IB defined for IPA2X_clk in MHz*/ + /* SVS */ + <90 512 6640000 13280000>, + <90 585 400000 800000>, + <1 676 100000 200000>, + <143 777 0 250>, /* IB defined for IPA2X_clk in MHz*/ + /* NOMINAL */ + <90 512 10400000 20800000>, + <90 585 800000 1600000>, + <1 676 200000 400000>, + <143 777 0 440>, /* IB defined for IPA2X_clk in MHz*/ + /* TURBO */ + <90 512 10400000 20800000>, + <90 585 960000 1920000>, + <1 676 266000 532000>, + <143 777 0 500>; /* IB defined for IPA clk in MHz*/ + qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", + "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + + + /* IPA RAM mmap */ + qcom,ipa-ram-mmap = < + 0x280 /* ofst_start; */ + 0x0 /* nat_ofst; */ + 0x0 /* nat_size; */ + 0x288 /* v4_flt_hash_ofst; */ + 0x78 /* v4_flt_hash_size; */ + 0x4000 /* v4_flt_hash_size_ddr; */ + 0x308 /* v4_flt_nhash_ofst; */ + 0x78 /* v4_flt_nhash_size; */ + 0x4000 /* v4_flt_nhash_size_ddr; */ + 0x388 /* v6_flt_hash_ofst; */ + 0x78 /* v6_flt_hash_size; */ + 0x4000 /* v6_flt_hash_size_ddr; */ + 0x408 /* v6_flt_nhash_ofst; */ + 0x78 /* v6_flt_nhash_size; */ + 0x4000 /* v6_flt_nhash_size_ddr; */ + 0xf /* v4_rt_num_index; */ + 0x0 /* v4_modem_rt_index_lo; */ + 0x7 /* v4_modem_rt_index_hi; */ + 0x8 /* v4_apps_rt_index_lo; */ + 0xe /* v4_apps_rt_index_hi; */ + 0x488 /* v4_rt_hash_ofst; */ + 0x78 /* v4_rt_hash_size; */ + 0x4000 /* v4_rt_hash_size_ddr; */ + 0x508 /* v4_rt_nhash_ofst; */ + 0x78 /* v4_rt_nhash_size; */ + 0x4000 /* v4_rt_nhash_size_ddr; */ + 0xf /* v6_rt_num_index; */ + 0x0 /* v6_modem_rt_index_lo; */ + 0x7 /* v6_modem_rt_index_hi; */ + 0x8 /* v6_apps_rt_index_lo; */ + 0xe /* v6_apps_rt_index_hi; */ + 0x588 /* v6_rt_hash_ofst; */ + 0x78 /* v6_rt_hash_size; */ + 0x4000 /* v6_rt_hash_size_ddr; */ + 0x608 /* v6_rt_nhash_ofst; */ + 0x78 /* v6_rt_nhash_size; */ + 0x4000 /* v6_rt_nhash_size_ddr; */ + 0x688 /* modem_hdr_ofst; */ + 0x140 /* modem_hdr_size; */ + 0x7c8 /* apps_hdr_ofst; */ + 0x0 /* apps_hdr_size; */ + 0x800 /* apps_hdr_size_ddr; */ + 0x7d0 /* modem_hdr_proc_ctx_ofst; */ + 0x200 /* modem_hdr_proc_ctx_size; */ + 0x9d0 /* apps_hdr_proc_ctx_ofst; */ + 0x200 /* apps_hdr_proc_ctx_size; */ + 0x0 /* apps_hdr_proc_ctx_size_ddr; */ + 0x0 /* modem_comp_decomp_ofst; diff */ + 0x0 /* modem_comp_decomp_size; diff */ + 0x13f0 /* modem_ofst; */ + 0x100c /* modem_size; */ + 0x23fc /* apps_v4_flt_hash_ofst; */ + 0x0 /* apps_v4_flt_hash_size; */ + 0x23fc /* apps_v4_flt_nhash_ofst; */ + 0x0 /* apps_v4_flt_nhash_size; */ + 0x23fc /* apps_v6_flt_hash_ofst; */ + 0x0 /* apps_v6_flt_hash_size; */ + 0x23fc /* apps_v6_flt_nhash_ofst; */ + 0x0 /* apps_v6_flt_nhash_size; */ + 0x80 /* uc_info_ofst; */ + 0x200 /* uc_info_size; */ + 0x2800 /* end_ofst; */ + 0x23fc /* apps_v4_rt_hash_ofst; */ + 0x0 /* apps_v4_rt_hash_size; */ + 0x23fc /* apps_v4_rt_nhash_ofst; */ + 0x0 /* apps_v4_rt_nhash_size; */ + 0x23fc /* apps_v6_rt_hash_ofst; */ + 0x0 /* apps_v6_rt_hash_size; */ + 0x23fc /* apps_v6_rt_nhash_ofst; */ + 0x0 /* apps_v6_rt_nhash_size; */ + 0x2400 /* uc_event_ring_ofst; */ + 0x400 /* uc_event_ring_size;*/ + 0xbd8 /* pdn_config_ofst; */ + 0x50 /* pdn_config_size; */ + 0xc30 /* stats_quota_ofst */ + 0x60 /* stats_quota_size */ + 0xc90 /* stats_tethering_ofst */ + 0x140 /* stats_tethering_size */ + 0xdd0 /* stats_flt_v4_ofst */ + 0x180 /* stats_flt_v4_size */ + 0xf50 /* stats_flt_v6_ofst */ + 0x180 /* stats_flt_v6_size */ + 0x10d0 /* stats_rt_v4_ofst */ + 0x180 /* stats_rt_v4_size */ + 0x1250 /* stats_rt_v6_ofst */ + 0x180 /* stats_rt_v6_size */ + 0x13d0 /* stats_drop_ofst */ + 0x20 /* stats_drop_size */ + >; + + /* smp2p gpio information */ + qcom,smp2pgpio_map_ipa_1_out { + compatible = "qcom,smp2pgpio-map-ipa-1-out"; + gpios = <&smp2pgpio_ipa_1_out 0 0>; + }; + + qcom,smp2pgpio_map_ipa_1_in { + compatible = "qcom,smp2pgpio-map-ipa-1-in"; + gpios = <&smp2pgpio_ipa_1_in 0 0>; + }; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + label = "aop"; + reg = <0xc300000 0x400>, + <0x17811008 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x2>; + interrupts = ; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0x0d 0x0 IRQ_TYPE_NONE>; + interrupt-names = "vbus_det_irq"; + status = "disabled"; + }; +}; + +#include "pmxpoorwills.dtsi" +#include "sdxpoorwills-blsp.dtsi" +#include "sdxpoorwills-regulator.dtsi" +#include "sdxpoorwills-smp2p.dtsi" +#include "sdxpoorwills-usb.dtsi" +#include "sdxpoorwills-pcie.dtsi" +#include "sdxpoorwills-bus.dtsi" +#include "sdxpoorwills-thermal.dtsi" +#include "sdxpoorwills-audio.dtsi" +#include "sdxpoorwills-ion.dtsi" +#include "msm-arm-smmu-sdxpoorwills.dtsi" + +&soc { + emac_hw: qcom,emac@00020000 { + compatible = "qcom,emac-dwc-eqos"; + reg = <0x20000 0x10000>, + <0x36000 0x100>; + reg-names = "emac-base", "rgmii-base"; + interrupts = <0 62 4>, <0 60 4>, + <0 45 4>, <0 49 4>, + <0 50 4>, <0 51 4>, + <0 52 4>, <0 53 4>, + <0 54 4>, <0 55 4>, + <0 56 4>, <0 57 4>; + interrupt-names = "sbd-intr", "lpi-intr", + "wol-intr", "tx-ch0-intr", + "tx-ch1-intr", "tx-ch2-intr", + "tx-ch3-intr", "tx-ch4-intr", + "rx-ch0-intr", "rx-ch1-intr", + "rx-ch2-intr", "rx-ch3-intr"; + qcom,msm-bus,name = "emac"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + qcom,bus-vector-names = "10", "100", "1000"; + clocks = <&clock_gcc GCC_ETH_AXI_CLK>, + <&clock_gcc GCC_ETH_PTP_CLK>, + <&clock_gcc GCC_ETH_RGMII_CLK>, + <&clock_gcc GCC_ETH_SLAVE_AHB_CLK>; + clock-names = "eth_axi_clk", "eth_ptp_clk", + "eth_rgmii_clk", "eth_slave_ahb_clk"; + qcom,phy-intr-redirect = <&tlmm 84 GPIO_ACTIVE_LOW>; + qcom,phy-reset = <&tlmm 85 GPIO_ACTIVE_LOW>; + vreg_rgmii-supply = <&vreg_rgmii>; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + gdsc_emac-supply = <&gdsc_emac>; + io-macro-info { + io-macro-bypass-mode = <0>; + io-interface = "rgmii"; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/smb138x.dtsi b/arch/arm/boot/dts/qcom/smb138x.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..218cd6c350d9c7022b02c891f3300bdd630f795c --- /dev/null +++ b/arch/arm/boot/dts/qcom/smb138x.dtsi @@ -0,0 +1,166 @@ +/* Copyright (c) 2016-2017, 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 + +smb138x: qcom,smb138x@44 { + compatible = "qcom,i2c-pmic"; + reg = <0x44>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb138x"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + + smb138x_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + reg = <0x3600 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupt-parent = <&smb138x>; + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_temp@0 { + reg = <0>; + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp@1 { + reg = <1>; + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp@2 { + reg = <2>; + qcom,scale = <(-1306)>; + qcom,offset = <397904>; + }; + + batt_i@3 { + reg = <3>; + qcom,channel = <3>; + qcom,scale = <(-20000000)>; + }; + + batt_v@4 { + reg = <4>; + qcom,scale = <5000000>; + }; + + input_i@5 { + reg = <5>; + qcom,scale = <14285714>; + }; + + input_v@6 { + reg = <6>; + qcom,scale = <25000000>; + }; + + otg_i@7 { + reg = <7>; + qcom,scale = <5714286>; + }; + }; + + smb1381_charger: qcom,smb1381-charger@1000 { + compatible = "qcom,smb138x-charger"; + qcom,pmic-revid = <&smb138x_revid>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb138x>; + io-channels = + <&smb138x_tadc 1>, + <&smb138x_tadc 2>, + <&smb138x_tadc 3>, + <&smb138x_tadc 14>, + <&smb138x_tadc 15>, + <&smb138x_tadc 16>, + <&smb138x_tadc 17>; + io-channel-names = + "connector_temp", + "charger_temp", + "batt_i", + "connector_temp_thr1", + "connector_temp_thr2", + "connector_temp_thr3", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x11 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x11 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x11 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x11 0x3 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x5 IRQ_TYPE_EDGE_RISING>, + <0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x13 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + + smb138x_vbus: qcom,smb138x-vbus { + status = "disabled"; + regulator-name = "smb138x-vbus"; + }; + }; +}; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 351fcc2f87df6b28b83e29f14e52b95a9dd6b553..b6c6410ca384f8ea1c87c788bd3d32d53e908620 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -1493,7 +1493,8 @@ }; msiof0: spi@e6e20000 { - compatible = "renesas,msiof-r8a7790"; + compatible = "renesas,msiof-r8a7790", + "renesas,rcar-gen2-msiof"; reg = <0 0xe6e20000 0 0x0064>; interrupts = ; clocks = <&mstp0_clks R8A7790_CLK_MSIOF0>; @@ -1507,7 +1508,8 @@ }; msiof1: spi@e6e10000 { - compatible = "renesas,msiof-r8a7790"; + compatible = "renesas,msiof-r8a7790", + "renesas,rcar-gen2-msiof"; reg = <0 0xe6e10000 0 0x0064>; interrupts = ; clocks = <&mstp2_clks R8A7790_CLK_MSIOF1>; @@ -1521,7 +1523,8 @@ }; msiof2: spi@e6e00000 { - compatible = "renesas,msiof-r8a7790"; + compatible = "renesas,msiof-r8a7790", + "renesas,rcar-gen2-msiof"; reg = <0 0xe6e00000 0 0x0064>; interrupts = ; clocks = <&mstp2_clks R8A7790_CLK_MSIOF2>; @@ -1535,7 +1538,8 @@ }; msiof3: spi@e6c90000 { - compatible = "renesas,msiof-r8a7790"; + compatible = "renesas,msiof-r8a7790", + "renesas,rcar-gen2-msiof"; reg = <0 0xe6c90000 0 0x0064>; interrupts = ; clocks = <&mstp2_clks R8A7790_CLK_MSIOF3>; diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi index a3ef7341c051c267d15b31cdae104ba43e6bd1de..4d329b2908beeb5c2c307156a7c3b0784e615992 100644 --- a/arch/arm/boot/dts/stih410.dtsi +++ b/arch/arm/boot/dts/stih410.dtsi @@ -131,7 +131,7 @@ <&clk_s_d2_quadfs 0>; assigned-clock-rates = <297000000>, - <108000000>, + <297000000>, <0>, <400000000>, <400000000>; diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts index 73c05dab0a693e8331093babdd30f94b5ff3bae9..e00539ae1b8a4c0c1bc9b6826794d16166abb25f 100644 --- a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts +++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts @@ -167,7 +167,7 @@ reg = <8>; label = "cpu"; ethernet = <&gmac>; - phy-mode = "rgmii"; + phy-mode = "rgmii-txid"; fixed-link { speed = <1000>; full-duplex; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts index 5ea4915f6d75b93eb06c974ab1b6abd009f7f769..10d307408f237f21d15fdbe2bf84de5b4db40f0a 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts @@ -56,7 +56,7 @@ }; &pio { - mmc2_pins_nrst: mmc2@0 { + mmc2_pins_nrst: mmc2-rst-pin { allwinner,pins = "PC16"; allwinner,function = "gpio_out"; allwinner,drive = ; diff --git a/arch/arm/boot/dts/tango4-vantage-1172.dts b/arch/arm/boot/dts/tango4-vantage-1172.dts index 4cab64cb581e9d09dc9771cd5226adc63eeca76a..e3a51e3538b7dc715b9866246defd25c71be41ad 100644 --- a/arch/arm/boot/dts/tango4-vantage-1172.dts +++ b/arch/arm/boot/dts/tango4-vantage-1172.dts @@ -21,7 +21,7 @@ }; ð0 { - phy-connection-type = "rgmii"; + phy-connection-type = "rgmii-id"; phy-handle = <ð0_phy>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 4e361a8c167e35ce24673317690a1370697b164d..b4bfa5586c233a48b3aeba14b53c3187e245b753 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -569,6 +569,7 @@ regulator-name = "+3VS,vdd_pnl"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; + regulator-boot-on; gpio = <&gpio TEGRA_GPIO(A, 4) GPIO_ACTIVE_HIGH>; enable-active-high; }; diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig index ea316c4b890efadb31df9f90df5ae382c94d4228..d3f1768840e28aa6a4e1ccba8cb3313bfbe78324 100644 --- a/arch/arm/configs/ezx_defconfig +++ b/arch/arm/configs/ezx_defconfig @@ -64,8 +64,8 @@ CONFIG_NETFILTER=y CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_SCTP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig index 18e59feaa3071593936ca4f0ff3d3b021eea9b08..7f479cdb34797c36219fe37bf8cdac79e94c3b8b 100644 --- a/arch/arm/configs/imote2_defconfig +++ b/arch/arm/configs/imote2_defconfig @@ -56,8 +56,8 @@ CONFIG_NETFILTER=y CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_SCTP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..9d710e3c7992564baf18b0ba4e50b35637c74428 --- /dev/null +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -0,0 +1,493 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_AIO is not set +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8953=y +CONFIG_ARCH_SDM450=y +# CONFIG_VDSO is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8953=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_QPNP_PIN_DEBUG=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_QPNP_FG=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_TYPEC=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_CPR4_APSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FB=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_DWC3=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=2048 +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..03f297f69c37fa9a0e342a8862c72ad62de8d779 --- /dev/null +++ b/arch/arm/configs/msm8953_defconfig @@ -0,0 +1,553 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_AIO is not set +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=m +CONFIG_KPROBES=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8953=y +CONFIG_ARCH_SDM450=y +# CONFIG_VDSO is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8953=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_QPNP_PIN_DEBUG=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_QPNP_FG=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_TYPEC=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_CPR4_APSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_DWC3=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_MSM_EXT_DISPLAY=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_TRACER_PKT=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=2048 +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y +CONFIG_MEMTEST=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_DEBUG_USER=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 53e1a884a1eae03c97f0941975ed7c3cf3211a3e..66d71963761dbc46e055c7d86705182f4edcbb98 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -216,6 +216,7 @@ CONFIG_SERIO=m CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=6 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index bc4bfe02e611a199407a058ee79e2c7ed1ef59e3..60d3fecd7a22db7ad87fa9559e66da4447ba261d 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -86,9 +86,9 @@ CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_SCTP=m -CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_H323=m diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 1f6d2ccd0bb8904b2c09495bbc2f56f0ff7d7b2c..d3500ae8d685db19a8b4602703f89cb3e9aaaecf 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -25,11 +25,14 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_SDXPOORWILLS=y +CONFIG_PCI_MSM=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_CMA=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_MSM=y CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y @@ -42,9 +45,13 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPGRE=y CONFIG_IP_MROUTE=y CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_IP_PIMSM_V2=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_GRE=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_IPV6_MROUTE=y @@ -68,6 +75,8 @@ CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y CONFIG_NF_CT_NETLINK_TIMEOUT=y +CONFIG_NF_CT_NETLINK_HELPER=y +CONFIG_NETFILTER_NETLINK_GLUE_CT=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -75,6 +84,7 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y @@ -98,6 +108,7 @@ CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y CONFIG_IP_NF_NAT=y CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NATTYPE_MODULE=y CONFIG_IP_NF_TARGET_NETMAP=y CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_MANGLE=y @@ -133,6 +144,9 @@ CONFIG_BRIDGE_EBT_SNAT=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y @@ -156,6 +170,7 @@ CONFIG_MTD=y CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -190,26 +205,53 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM_HS=y +CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y -CONFIG_SOUNDWIRE=y +CONFIG_I2C_MSM_V2=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=m +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PINCTRL_SDXPOORWILLS=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB138X_CHARGER=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPMH=y CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y @@ -221,7 +263,6 @@ CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_MSM=y CONFIG_USB_ACM=y CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_DEBUG=y @@ -237,11 +278,22 @@ CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 @@ -250,22 +302,56 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y CONFIG_UIO=y CONFIG_STAGING=y +CONFIG_ION=y +CONFIG_ION_MSM=y CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_ECM_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_REVID=y +CONFIG_GPIO_USB_DETECT=y CONFIG_USB_BAM=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MDM_GCC_SDXPOORWILLS=y +CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_SMEM=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y CONFIG_TRACER_PKT=y +CONFIG_QTI_RPMH_API=y CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_MSM_PM=y +CONFIG_IIO=y CONFIG_PWM=y +CONFIG_PWM_QPNP=y CONFIG_QCOM_SHOW_RESUME_IRQ=y CONFIG_ANDROID=y CONFIG_EXT3_FS=y @@ -283,7 +369,16 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 # CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index 5d61163337c9c443324eeb1ee28f362a5b876fdd..af75d1e23c276b570e50250d02fa7347b83d4c27 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -27,11 +27,14 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_SDXPOORWILLS=y # CONFIG_VDSO is not set +CONFIG_PCI_MSM=y CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_CMA=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_MSM=y CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y @@ -44,9 +47,13 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPGRE=y CONFIG_IP_MROUTE=y CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_IP_PIMSM_V2=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_GRE=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_IPV6_MROUTE=y @@ -70,6 +77,8 @@ CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y CONFIG_NF_CT_NETLINK_TIMEOUT=y +CONFIG_NF_CT_NETLINK_HELPER=y +CONFIG_NETFILTER_NETLINK_GLUE_CT=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -77,6 +86,7 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y @@ -100,6 +110,7 @@ CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y CONFIG_IP_NF_NAT=y CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NATTYPE_MODULE=y CONFIG_IP_NF_TARGET_NETMAP=y CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_MANGLE=y @@ -135,6 +146,13 @@ CONFIG_BRIDGE_EBT_SNAT=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_CFG80211=y +CONFIG_CFG80211_DEBUGFS=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_CFG80211_WEXT=y CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y @@ -144,6 +162,7 @@ CONFIG_MTD=y CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y +CONFIG_MTD_MSM_QPIC_NAND=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -178,30 +197,59 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y -CONFIG_HVC_DCC=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y -CONFIG_SOUNDWIRE=y +CONFIG_I2C_MSM_V2=y CONFIG_SPI=y +CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=m CONFIG_SLIMBUS=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PINCTRL_SDXPOORWILLS=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB138X_CHARGER=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_SYSCON=y CONFIG_MSM_CDC_PINCTRL=y CONFIG_MSM_CDC_SUPPLY=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y CONFIG_FB=y CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y @@ -228,35 +276,86 @@ CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_TEST=m CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y CONFIG_UIO=y CONFIG_STAGING=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_ECM_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_HWSPINLOCK_QCOM=y -CONFIG_QCOM_SMEM=y -CONFIG_QCOM_SMD=y +CONFIG_QPNP_REVID=y +CONFIG_GPIO_USB_DETECT=y +CONFIG_USB_BAM=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MDM_GCC_SDXPOORWILLS=y +CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y CONFIG_TRACER_PKT=y +CONFIG_QTI_RPMH_API=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_MSM_PM=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_IIO=y CONFIG_PWM=y +CONFIG_PWM_QPNP=y CONFIG_QCOM_SHOW_RESUME_IRQ=y CONFIG_ANDROID=y -CONFIG_STM=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_VFAT_FS=y @@ -277,7 +376,6 @@ CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y @@ -289,7 +387,21 @@ CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_DEBUG_USER=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_TGU=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_SHA256=y CONFIG_XZ_DEC=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/crypto/aesbs-glue.c b/arch/arm/crypto/aesbs-glue.c index 0511a6cafe24cb7e7d05735f8a1c2b9a7a68f116..5d934a0039d76d22cda3c6f702238819960ba50a 100644 --- a/arch/arm/crypto/aesbs-glue.c +++ b/arch/arm/crypto/aesbs-glue.c @@ -363,7 +363,7 @@ static struct crypto_alg aesbs_algs[] = { { }, { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-neonbs", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct async_helper_ctx), @@ -383,7 +383,7 @@ static struct crypto_alg aesbs_algs[] = { { }, { .cra_name = "ctr(aes)", .cra_driver_name = "ctr-aes-neonbs", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct async_helper_ctx), @@ -403,7 +403,7 @@ static struct crypto_alg aesbs_algs[] = { { }, { .cra_name = "xts(aes)", .cra_driver_name = "xts-aes-neonbs", - .cra_priority = 300, + .cra_priority = 250, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct async_helper_ctx), diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 55e0e3ea9cb6bdeb19ff5c47385a571799dd71e6..bd12b98e258965e2ecaab33e2fbf14769391dcbd 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -37,4 +37,3 @@ generic-y += termbits.h generic-y += termios.h generic-y += timex.h generic-y += trace_clock.h -generic-y += unaligned.h diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 68b06f9c65ded6c810421a79b345e16f77e3d527..12f99fd2e3b2edff01a72194ec28987f219c99e8 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -516,4 +516,22 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm + .macro bug, msg, line +#ifdef CONFIG_THUMB2_KERNEL +1: .inst 0xde02 +#else +1: .inst 0xe7f001f2 +#endif +#ifdef CONFIG_DEBUG_BUGVERBOSE + .pushsection .rodata.str, "aMS", %progbits, 1 +2: .asciz "\msg" + .popsection + .pushsection __bug_table, "aw" + .align 2 + .word 1b, 2b + .hword \line + .popsection +#endif + .endm + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 58c6398b3828535ff2494b1d896976ea8de00c07..8e349ce8230c7973136f6f41d0f234a339efddb2 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -178,10 +178,26 @@ extern void __cpuc_flush_dcache_area(void *, size_t); * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */ +extern void __dma_map_area(const void *addr, size_t size, int dir); +extern void __dma_unmap_area(const void *addr, size_t size, int dir); extern void dmac_inv_range(const void *, const void *); extern void dmac_clean_range(const void *, const void *); extern void dmac_flush_range(const void *, const void *); +static inline void __dma_inv_area(const void *start, size_t len) +{ + dmac_inv_range(start, start + len); +} + +static inline void __dma_clean_area(const void *start, size_t len) +{ + dmac_clean_range(start, start + len); +} + +static inline void __dma_flush_area(const void *start, size_t len) +{ + dmac_flush_range(start, start + len); +} #endif /* diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h index b4e74af0abb7ee184fa6cca8fbe3b2749ac9bc6c..a1b5d1909df997ff87398fc8786c89afc2d68253 100644 --- a/arch/arm/include/asm/dma-iommu.h +++ b/arch/arm/include/asm/dma-iommu.h @@ -8,11 +8,13 @@ #include #include #include +#include struct dma_iommu_mapping { /* iommu specific data */ struct iommu_domain *domain; - + bool init; + const struct dma_map_ops *ops; unsigned long **bitmaps; /* array of bitmaps */ unsigned int nr_bitmaps; /* nr of elements in array */ unsigned int extensions; @@ -22,6 +24,8 @@ struct dma_iommu_mapping { spinlock_t lock; struct kref kref; + + struct dma_fast_smmu_mapping *fast; }; #ifdef CONFIG_ARM_DMA_USE_IOMMU diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index bfe2a2f5a644e80a9f80f71b49d727604c41e728..22b73112b75f2070e440068184f9655cff781afe 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -54,6 +54,24 @@ static inline void *return_address(unsigned int level) #define ftrace_return_address(n) return_address(n) +#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME + +static inline bool arch_syscall_match_sym_name(const char *sym, + const char *name) +{ + if (!strcmp(sym, "sys_mmap2")) + sym = "sys_mmap_pgoff"; + else if (!strcmp(sym, "sys_statfs64_wrapper")) + sym = "sys_statfs64"; + else if (!strcmp(sym, "sys_fstatfs64_wrapper")) + sym = "sys_fstatfs64"; + else if (!strcmp(sym, "sys_arm_fadvise64_64")) + sym = "sys_fadvise64_64"; + + /* Ignore case since sym may start with "SyS" instead of "sys" */ + return !strcasecmp(sym, name); +} + #endif /* ifndef __ASSEMBLY__ */ #endif /* _ASM_ARM_FTRACE */ diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index d14f31047a5c75442c69a238b21b4e714c15ddb2..f7c75dcae829a0087da799a4b97414205c578169 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -157,6 +157,11 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { } #define dmac_flush_range __glue(_CACHE,_dma_flush_range) #define dmac_inv_range __glue(_CACHE, _dma_inv_range) #define dmac_clean_range __glue(_CACHE, _dma_clean_range) +#define dmac_map_area __glue(_CACHE, _dma_map_area) +#define dmac_unmap_area __glue(_CACHE, _dma_unmap_area) + +#define __dma_map_area dmac_map_area +#define __dma_unmap_area dmac_unmap_area #endif #endif diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 66003a80db86b974de2c9a2af759f994cb995f70..d1df9cc2a2598a7047904a9cedcbdc4fe884872e 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -363,6 +363,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define writel_relaxed(v, c) __raw_writel((__force u32) cpu_to_le32(v), c) #define writeq_relaxed(v, c) __raw_writeq((__force u64) cpu_to_le64(v), c) #define writeb_relaxed_no_log(v, c) ((void)__raw_writeb_no_log((v), (c))) +#define writew_relaxed_no_log(v, c) __raw_writew_no_log((__force u16) cpu_to_le16(v), c) #define writel_relaxed_no_log(v, c) __raw_writel_no_log((__force u32) cpu_to_le32(v), c) #define writeq_relaxed_no_log(v, c) __raw_writeq_no_log((__force u64) cpu_to_le64(v), c) diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index e22089fb44dc86b7ed2fdb175bc6ec7b47ee4001..98d6de177b7a31b71994e75fc925fca609c439a8 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h @@ -161,8 +161,7 @@ #else #define VTTBR_X (5 - KVM_T0SZ) #endif -#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_BADDR_MASK (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT _AC(48, ULL) #define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT) @@ -209,6 +208,7 @@ #define HSR_EC_IABT_HYP (0x21) #define HSR_EC_DABT (0x24) #define HSR_EC_DABT_HYP (0x25) +#define HSR_EC_MAX (0x3f) #define HSR_WFI_IS_WFE (_AC(1, UL) << 0) diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h index 4917c2f7e45955919509727640b9e54edd940b01..e74ab0fbab79091105dd1e5026c1e3e1e1347ead 100644 --- a/arch/arm/include/asm/kvm_coproc.h +++ b/arch/arm/include/asm/kvm_coproc.h @@ -31,7 +31,8 @@ void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table); int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run); +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index a58bbaa3ec603603302fd375caa4fc86ae91a14b..d10e36235438943cc68841fb5a88d512916b897d 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -223,6 +223,16 @@ static inline unsigned int kvm_get_vmid_bits(void) return 8; } +static inline void *kvm_get_hyp_vector(void) +{ + return kvm_ksym_ref(__kvm_hyp_vector); +} + +static inline int kvm_map_vectors(void) +{ + return 0; +} + #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index 464748b9fd7d22ec3add804ae80068e5c679aa63..ed2319663a1ecc6f04e860bac4069bf0370da5fb 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h @@ -18,13 +18,18 @@ enum { }; #endif +struct mod_plt_sec { + struct elf32_shdr *plt; + int plt_count; +}; + struct mod_arch_specific { #ifdef CONFIG_ARM_UNWIND struct unwind_table *unwind[ARM_SEC_MAX]; #endif #ifdef CONFIG_ARM_MODULE_PLTS - struct elf32_shdr *plt; - int plt_count; + struct mod_plt_sec core; + struct mod_plt_sec init; #endif }; diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h index 062c4845214819b64b25d099ebc2bc462df4aecb..906623e0cca6ada1d6aff0321fa61f1bba5e1d40 100644 --- a/arch/arm/include/asm/system_misc.h +++ b/arch/arm/include/asm/system_misc.h @@ -22,6 +22,7 @@ extern void (*arm_pm_idle)(void); extern unsigned int user_debug; extern char* (*arch_read_hardware_id)(void); +const char * __init arch_read_machine_name(void); #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 776757d1604ab3901996bb24bb02748e54c2aee7..f23454db246fe2e9315d8c9aaa8b18fd70571f4a 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -148,6 +148,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20 +#define TIF_MM_RELEASED 21 /* task MM has been released */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index d0606412069492767c5f62158e4f9b24ee073570..41e9107bcc728d024db8a9d7cd6cf8168a290521 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -24,6 +24,7 @@ extern struct cputopo_arm cpu_topology[NR_CPUS]; void init_cpu_topology(void); void store_cpu_topology(unsigned int cpuid); const struct cpumask *cpu_coregroup_mask(int cpu); +unsigned long arch_get_cpu_efficiency(int cpu); #ifdef CONFIG_CPU_FREQ #define arch_scale_freq_capacity cpufreq_scale_freq_capacity @@ -31,6 +32,9 @@ const struct cpumask *cpu_coregroup_mask(int cpu); #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); +#define arch_update_cpu_capacity update_cpu_power_capacity +extern void update_cpu_power_capacity(int cpu); + #else static inline void init_cpu_topology(void) { } diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 1f59ea051bab814132074b09f55d3a57c800a471..b7e0125c0bbf2014a447800a383426b62d5147b8 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -478,11 +478,10 @@ extern unsigned long __must_check arm_copy_from_user(void *to, const void __user *from, unsigned long n); static inline unsigned long __must_check -__copy_from_user(void *to, const void __user *from, unsigned long n) +__arch_copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned int __ua_flags; - check_object_size(to, n, false); __ua_flags = uaccess_save_and_enable(); n = arm_copy_from_user(to, from, n); uaccess_restore(__ua_flags); @@ -495,18 +494,15 @@ extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n); static inline unsigned long __must_check -__copy_to_user(void __user *to, const void *from, unsigned long n) +__arch_copy_to_user(void __user *to, const void *from, unsigned long n) { #ifndef CONFIG_UACCESS_WITH_MEMCPY unsigned int __ua_flags; - - check_object_size(from, n, true); __ua_flags = uaccess_save_and_enable(); n = arm_copy_to_user(to, from, n); uaccess_restore(__ua_flags); return n; #else - check_object_size(from, n, true); return arm_copy_to_user(to, from, n); #endif } @@ -526,25 +522,49 @@ __clear_user(void __user *addr, unsigned long n) } #else -#define __copy_from_user(to, from, n) (memcpy(to, (void __force *)from, n), 0) -#define __copy_to_user(to, from, n) (memcpy((void __force *)to, from, n), 0) +#define __arch_copy_from_user(to, from, n) \ + (memcpy(to, (void __force *)from, n), 0) +#define __arch_copy_to_user(to, from, n) \ + (memcpy((void __force *)to, from, n), 0) #define __clear_user(addr, n) (memset((void __force *)addr, 0, n), 0) #endif -static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) +static inline unsigned long __must_check +__copy_from_user(void *to, const void __user *from, unsigned long n) +{ + check_object_size(to, n, false); + return __arch_copy_from_user(to, from, n); +} + +static inline unsigned long __must_check +copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long res = n; + + check_object_size(to, n, false); + if (likely(access_ok(VERIFY_READ, from, n))) - res = __copy_from_user(to, from, n); + res = __arch_copy_from_user(to, from, n); if (unlikely(res)) memset(to + (n - res), 0, res); return res; } -static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) +static inline unsigned long __must_check +__copy_to_user(void __user *to, const void *from, unsigned long n) { + check_object_size(from, n, true); + + return __arch_copy_to_user(to, from, n); +} + +static inline unsigned long __must_check +copy_to_user(void __user *to, const void *from, unsigned long n) +{ + check_object_size(from, n, true); + if (access_ok(VERIFY_WRITE, to, n)) - n = __copy_to_user(to, from, n); + n = __arch_copy_to_user(to, from, n); return n; } diff --git a/arch/arm/include/asm/unaligned.h b/arch/arm/include/asm/unaligned.h new file mode 100644 index 0000000000000000000000000000000000000000..ab905ffcf1930dd456601b21af4b9cd3b21c9ff6 --- /dev/null +++ b/arch/arm/include/asm/unaligned.h @@ -0,0 +1,27 @@ +#ifndef __ASM_ARM_UNALIGNED_H +#define __ASM_ARM_UNALIGNED_H + +/* + * We generally want to set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS on ARMv6+, + * but we don't want to use linux/unaligned/access_ok.h since that can lead + * to traps on unaligned stm/ldm or strd/ldrd. + */ +#include + +#if defined(__LITTLE_ENDIAN) +# include +# include +# include +# define get_unaligned __get_unaligned_le +# define put_unaligned __put_unaligned_le +#elif defined(__BIG_ENDIAN) +# include +# include +# include +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +#else +# error need to define endianess +#endif + +#endif /* __ASM_ARM_UNALIGNED_H */ diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 6391728c8f0377019404c6a6744df1e24697b3a8..e056c9a9aa9db178ba47ec421f2e8d1f53d3cab4 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -299,6 +299,8 @@ mov r2, sp ldr r1, [r2, #\offset + S_PSR] @ get calling cpsr ldr lr, [r2, #\offset + S_PC]! @ get pc + tst r1, #PSR_I_BIT | 0x0f + bne 1f msr spsr_cxsf, r1 @ save in spsr_svc #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K) @ We must avoid clrex due to Cortex-A15 erratum #830321 @@ -313,6 +315,7 @@ @ after ldm {}^ add sp, sp, #\offset + PT_REGS_SIZE movs pc, lr @ return & move spsr_svc into cpsr +1: bug "Returning to usermode but unexpected PSR bits set?", \@ #elif defined(CONFIG_CPU_V7M) @ V7M restore. @ Note that we don't need to do clrex here as clearing the local @@ -328,6 +331,8 @@ ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr ldr lr, [sp, #\offset + S_PC] @ get pc add sp, sp, #\offset + S_SP + tst r1, #PSR_I_BIT | 0x0f + bne 1f msr spsr_cxsf, r1 @ save in spsr_svc @ We must avoid clrex due to Cortex-A15 erratum #830321 @@ -340,6 +345,7 @@ .endif add sp, sp, #PT_REGS_SIZE - S_SP movs pc, lr @ return & move spsr_svc into cpsr +1: bug "Returning to usermode but unexpected PSR bits set?", \@ #endif /* !CONFIG_THUMB2_KERNEL */ .endm diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 3a5cba90c971e8523b9d148adf9e2d1cde4b1f52..3d0c2e4dda1d23ae92ca40d4b40441d45bd02616 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Linaro Ltd. + * Copyright (C) 2014-2017 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -31,9 +31,17 @@ struct plt_entries { u32 lit[PLT_ENT_COUNT]; }; +static bool in_init(const struct module *mod, unsigned long loc) +{ + return loc - (u32)mod->init_layout.base < mod->init_layout.size; +} + u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) { - struct plt_entries *plt = (struct plt_entries *)mod->arch.plt->sh_addr; + struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : + &mod->arch.init; + + struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr; int idx = 0; /* @@ -41,9 +49,9 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) * relocations are sorted, this will be the last entry we allocated. * (if one exists). */ - if (mod->arch.plt_count > 0) { - plt += (mod->arch.plt_count - 1) / PLT_ENT_COUNT; - idx = (mod->arch.plt_count - 1) % PLT_ENT_COUNT; + if (pltsec->plt_count > 0) { + plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT; + idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT; if (plt->lit[idx] == val) return (u32)&plt->ldr[idx]; @@ -53,8 +61,8 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) plt++; } - mod->arch.plt_count++; - BUG_ON(mod->arch.plt_count * PLT_ENT_SIZE > mod->arch.plt->sh_size); + pltsec->plt_count++; + BUG_ON(pltsec->plt_count * PLT_ENT_SIZE > pltsec->plt->sh_size); if (!idx) /* Populate a new set of entries */ @@ -129,7 +137,7 @@ static bool duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num) /* Count how many PLT entries we may need */ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, - const Elf32_Rel *rel, int num) + const Elf32_Rel *rel, int num, Elf32_Word dstidx) { unsigned int ret = 0; const Elf32_Sym *s; @@ -144,13 +152,17 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, case R_ARM_THM_JUMP24: /* * We only have to consider branch targets that resolve - * to undefined symbols. This is not simply a heuristic, - * it is a fundamental limitation, since the PLT itself - * is part of the module, and needs to be within range - * as well, so modules can never grow beyond that limit. + * to symbols that are defined in a different section. + * This is not simply a heuristic, it is a fundamental + * limitation, since there is no guaranteed way to emit + * PLT entries sufficiently close to the branch if the + * section size exceeds the range of a branch + * instruction. So ignore relocations against defined + * symbols if they live in the same section as the + * relocation target. */ s = syms + ELF32_R_SYM(rel[i].r_info); - if (s->st_shndx != SHN_UNDEF) + if (s->st_shndx == dstidx) break; /* @@ -161,7 +173,12 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, * So we need to support them, but there is no need to * take them into consideration when trying to optimize * this code. So let's only check for duplicates when - * the addend is zero. + * the addend is zero. (Note that calls into the core + * module via init PLT entries could involve section + * relative symbol references with non-zero addends, for + * which we may end up emitting duplicates, but the init + * PLT is released along with the rest of the .init + * region as soon as module loading completes.) */ if (!is_zero_addend_relocation(base, rel + i) || !duplicate_rel(base, rel, i)) @@ -174,7 +191,8 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { - unsigned long plts = 0; + unsigned long core_plts = 0; + unsigned long init_plts = 0; Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; Elf32_Sym *syms = NULL; @@ -184,13 +202,15 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, */ for (s = sechdrs; s < sechdrs_end; ++s) { if (strcmp(".plt", secstrings + s->sh_name) == 0) - mod->arch.plt = s; + mod->arch.core.plt = s; + else if (strcmp(".init.plt", secstrings + s->sh_name) == 0) + mod->arch.init.plt = s; else if (s->sh_type == SHT_SYMTAB) syms = (Elf32_Sym *)s->sh_addr; } - if (!mod->arch.plt) { - pr_err("%s: module PLT section missing\n", mod->name); + if (!mod->arch.core.plt || !mod->arch.init.plt) { + pr_err("%s: module PLT section(s) missing\n", mod->name); return -ENOEXEC; } if (!syms) { @@ -213,16 +233,29 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, /* sort by type and symbol index */ sort(rels, numrels, sizeof(Elf32_Rel), cmp_rel, NULL); - plts += count_plts(syms, dstsec->sh_addr, rels, numrels); + if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0) + core_plts += count_plts(syms, dstsec->sh_addr, rels, + numrels, s->sh_info); + else + init_plts += count_plts(syms, dstsec->sh_addr, rels, + numrels, s->sh_info); } - mod->arch.plt->sh_type = SHT_NOBITS; - mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; - mod->arch.plt->sh_addralign = L1_CACHE_BYTES; - mod->arch.plt->sh_size = round_up(plts * PLT_ENT_SIZE, - sizeof(struct plt_entries)); - mod->arch.plt_count = 0; - - pr_debug("%s: plt=%x\n", __func__, mod->arch.plt->sh_size); + mod->arch.core.plt->sh_type = SHT_NOBITS; + mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES; + mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE, + sizeof(struct plt_entries)); + mod->arch.core.plt_count = 0; + + mod->arch.init.plt->sh_type = SHT_NOBITS; + mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES; + mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE, + sizeof(struct plt_entries)); + mod->arch.init.plt_count = 0; + + pr_debug("%s: plt=%x, init.plt=%x\n", __func__, + mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size); return 0; } diff --git a/arch/arm/kernel/module.lds b/arch/arm/kernel/module.lds index 05881e2b414c5ac63e4660dd7ccdf779fd71f9bb..eacb5c67f61e97d318631d0a129bb7150fa021a9 100644 --- a/arch/arm/kernel/module.lds +++ b/arch/arm/kernel/module.lds @@ -1,3 +1,4 @@ SECTIONS { .plt : { BYTE(0) } + .init.plt : { BYTE(0) } } diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index fab57d36a451cde7e6e3bc8089ea9ab3fe26fb7f..09dd8ff379cb83e3311c45cd990627aee5928f45 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -81,7 +81,7 @@ __setup("fpe=", fpe_setup); extern void init_default_cache_policy(unsigned long); extern void paging_init(const struct machine_desc *desc); extern void early_paging_init(const struct machine_desc *); -extern void sanity_check_meminfo(void); +extern void adjust_lowmem_bounds(void); extern enum reboot_mode reboot_mode; extern void setup_dma_zone(const struct machine_desc *desc); @@ -1104,8 +1104,14 @@ void __init setup_arch(char **cmdline_p) setup_dma_zone(mdesc); xen_early_init(); efi_init(); - sanity_check_meminfo(); + /* + * Make sure the calculation for lowmem/highmem is set appropriately + * before reserving/allocating any mmeory + */ + adjust_lowmem_bounds(); arm_memblock_init(mdesc); + /* Memory may have been removed so recalculate the bounds. */ + adjust_lowmem_bounds(); early_ioremap_reset(); @@ -1168,7 +1174,7 @@ static int __init topology_init(void) return 0; } -subsys_initcall(topology_init); +postcore_initcall(topology_init); #ifdef CONFIG_HAVE_PROC_CPU static int __init proc_cpu_init(void) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index bbf60e34502195f2438d52abdf1be723caf8c46e..ab509d6cc6ca0fbed7bd07720c69043b9503c3fb 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -466,17 +466,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) } static void (*__smp_cross_call)(const struct cpumask *, unsigned int); -DEFINE_PER_CPU(bool, pending_ipi); -static void smp_cross_call_common(const struct cpumask *cpumask, - unsigned int func) -{ - unsigned int cpu; - - for_each_cpu(cpu, cpumask) - per_cpu(pending_ipi, cpu) = true; - - __smp_cross_call(cpumask, func); -} void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) { @@ -501,6 +490,18 @@ static void smp_cross_call(const struct cpumask *target, unsigned int ipinr) __smp_cross_call(target, ipinr); } +DEFINE_PER_CPU(bool, pending_ipi); +static void smp_cross_call_common(const struct cpumask *cpumask, + unsigned int func) +{ + unsigned int cpu; + + for_each_cpu(cpu, cpumask) + per_cpu(pending_ipi, cpu) = true; + + smp_cross_call(cpumask, func); +} + void show_ipi_list(struct seq_file *p, int prec) { unsigned int cpu, i; @@ -539,7 +540,7 @@ void arch_send_wakeup_ipi_mask(const struct cpumask *mask) void arch_send_call_function_single_ipi(int cpu) { - smp_cross_call_common(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); + smp_cross_call_common(cpumask_of(cpu), IPI_CALL_FUNC); } #ifdef CONFIG_IRQ_WORK diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 92b72375c4c72ab3ffb561246581d0b5abf56aad..fe76010f75cf9a46bf343dec8c4702620311665f 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -170,6 +170,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { __save_stack_trace(tsk, trace, 1); } +EXPORT_SYMBOL(save_stack_trace_tsk); void save_stack_trace(struct stack_trace *trace) { diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index bd884da498bac32b522fa726aeae965c11210773..28dcd443a012760dc382074d3f31ad12a2d1b347 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -42,6 +42,16 @@ */ static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE; +unsigned long arch_scale_freq_power(struct sched_domain *sd, int cpu) +{ + return per_cpu(cpu_scale, cpu); +} + +static void set_power_scale(unsigned int cpu, unsigned long power) +{ + per_cpu(cpu_scale, cpu) = power; +} + unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu) { #ifdef CONFIG_CPU_FREQ @@ -196,6 +206,14 @@ static int __init parse_cluster(struct device_node *cluster, int depth) return 0; } +static DEFINE_PER_CPU(unsigned long, cpu_efficiency) = SCHED_CAPACITY_SCALE; + +unsigned long arch_get_cpu_efficiency(int cpu) +{ + return per_cpu(cpu_efficiency, cpu); +} +EXPORT_SYMBOL(arch_get_cpu_efficiency); + #ifdef CONFIG_OF struct cpu_efficiency { const char *compatible; @@ -272,6 +290,7 @@ static int __init parse_dt_topology(void) for_each_possible_cpu(cpu) { const u32 *rate; int len; + u32 efficiency; /* too early to use cpu->of_node */ cn = of_get_cpu_node(cpu, NULL); @@ -280,12 +299,26 @@ static int __init parse_dt_topology(void) continue; } - for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++) - if (of_device_is_compatible(cn, cpu_eff->compatible)) - break; + /* + * The CPU efficiency value passed from the device tree + * overrides the value defined in the table_efficiency[] + */ + if (of_property_read_u32(cn, "efficiency", &efficiency) < 0) { - if (cpu_eff->compatible == NULL) - continue; + for (cpu_eff = table_efficiency; + cpu_eff->compatible; cpu_eff++) + + if (of_device_is_compatible(cn, + cpu_eff->compatible)) + break; + + if (cpu_eff->compatible == NULL) + continue; + + efficiency = cpu_eff->efficiency; + } + + per_cpu(cpu_efficiency, cpu) = efficiency; rate = of_get_property(cn, "clock-frequency", &len); if (!rate || len != 4) { @@ -294,7 +327,7 @@ static int __init parse_dt_topology(void) continue; } - capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency; + capacity = ((be32_to_cpup(rate)) >> 20) * efficiency; /* Save min capacity of the system */ if (capacity < min_capacity) @@ -374,6 +407,23 @@ const struct cpumask *cpu_corepower_mask(int cpu) return &cpu_topology[cpu].thread_sibling; } +static void update_cpu_power(unsigned int cpu) +{ + if (!cpu_capacity(cpu)) + return; + + set_power_scale(cpu, cpu_capacity(cpu) / middle_capacity); + + pr_info("CPU%u: update cpu_power %lu\n", + cpu, arch_scale_freq_power(NULL, cpu)); +} + +void update_cpu_power_capacity(int cpu) +{ + update_cpu_power(cpu); + update_cpu_capacity(cpu); +} + static void update_siblings_masks(unsigned int cpuid) { struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 9688ec0c6ef43f621d029c680fcd7876d120a53c..1b304897aa1227788105b1d1e6883c2d99f445b7 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -152,30 +152,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, set_fs(fs); } -static void dump_instr(const char *lvl, struct pt_regs *regs) +static void __dump_instr(const char *lvl, struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); const int thumb = thumb_mode(regs); const int width = thumb ? 4 : 8; - mm_segment_t fs; char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; int i; /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. Note that we now dump the - * code first, just in case the backtrace kills us. + * Note that we now dump the code first, just in case the backtrace + * kills us. */ - fs = get_fs(); - set_fs(KERNEL_DS); for (i = -4; i < 1 + !!thumb; i++) { unsigned int val, bad; if (thumb) - bad = __get_user(val, &((u16 *)addr)[i]); + bad = get_user(val, &((u16 *)addr)[i]); else - bad = __get_user(val, &((u32 *)addr)[i]); + bad = get_user(val, &((u32 *)addr)[i]); if (!bad) p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", @@ -186,8 +182,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) } } printk("%sCode: %s\n", lvl, str); +} - set_fs(fs); +static void dump_instr(const char *lvl, struct pt_regs *regs) +{ + mm_segment_t fs; + + if (!user_mode(regs)) { + fs = get_fs(); + set_fs(KERNEL_DS); + __dump_instr(lvl, regs); + set_fs(fs); + } else { + __dump_instr(lvl, regs); + } } #ifdef CONFIG_ARM_UNWIND diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 3e5e4194ef86967d3fae8c32ecd6bd2e99b85f78..c3ed6bd5ddf35aeb558f1129f06fff333dc6552c 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -93,12 +93,6 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } -int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) -{ - kvm_inject_undefined(vcpu); - return 1; -} - static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) { /* @@ -514,12 +508,7 @@ static int emulate_cp15(struct kvm_vcpu *vcpu, return 1; } -/** - * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - */ -int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +static struct coproc_params decode_64bit_hsr(struct kvm_vcpu *vcpu) { struct coproc_params params; @@ -533,9 +522,38 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf; params.CRm = 0; + return params; +} + +/** + * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params = decode_64bit_hsr(vcpu); + return emulate_cp15(vcpu, ¶ms); } +/** + * kvm_handle_cp14_64 -- handles a mrrc/mcrr trap on a guest CP14 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params = decode_64bit_hsr(vcpu); + + /* raz_wi cp14 */ + pm_fake(vcpu, ¶ms, NULL); + + /* handled */ + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + return 1; +} + static void reset_coproc_regs(struct kvm_vcpu *vcpu, const struct coproc_reg *table, size_t num) { @@ -546,12 +564,7 @@ static void reset_coproc_regs(struct kvm_vcpu *vcpu, table[i].reset(vcpu, &table[i]); } -/** - * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access - * @vcpu: The VCPU pointer - * @run: The kvm_run struct - */ -int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) +static struct coproc_params decode_32bit_hsr(struct kvm_vcpu *vcpu) { struct coproc_params params; @@ -565,9 +578,37 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) params.Op2 = (kvm_vcpu_get_hsr(vcpu) >> 17) & 0x7; params.Rt2 = 0; + return params; +} + +/** + * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params = decode_32bit_hsr(vcpu); return emulate_cp15(vcpu, ¶ms); } +/** + * kvm_handle_cp14_32 -- handles a mrc/mcr trap on a guest CP14 access + * @vcpu: The VCPU pointer + * @run: The kvm_run struct + */ +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + struct coproc_params params = decode_32bit_hsr(vcpu); + + /* raz_wi cp14 */ + pm_fake(vcpu, ¶ms, NULL); + + /* handled */ + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); + return 1; +} + /****************************************************************************** * Userspace API *****************************************************************************/ diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c index 0064b86a2c87936ccc69cb3d413ce151e85f5933..30a13647c54c6ef3bcf01b3db27892e929cd8e4e 100644 --- a/arch/arm/kvm/emulate.c +++ b/arch/arm/kvm/emulate.c @@ -227,7 +227,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu) u32 return_offset = (is_thumb) ? 2 : 4; kvm_update_psr(vcpu, UND_MODE); - *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset; + *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset; /* Branch to exception vector */ *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset; @@ -239,10 +239,8 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu) */ static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr) { - unsigned long cpsr = *vcpu_cpsr(vcpu); - bool is_thumb = (cpsr & PSR_T_BIT); u32 vect_offset; - u32 return_offset = (is_thumb) ? 4 : 0; + u32 return_offset = (is_pabt) ? 4 : 8; bool is_lpae; kvm_update_psr(vcpu, ABT_MODE); diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index 4e40d1955e35341b7756efe72f2da6bf2360b224..42f5daf715d02897fa6589df06142d077d3ccf87 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -79,13 +79,25 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + + kvm_pr_unimpl("Unknown exception class: hsr: %#08x\n", + hsr); + + kvm_inject_undefined(vcpu); + return 1; +} + static exit_handle_fn arm_exit_handlers[] = { + [0 ... HSR_EC_MAX] = kvm_handle_unknown_ec, [HSR_EC_WFI] = kvm_handle_wfx, [HSR_EC_CP15_32] = kvm_handle_cp15_32, [HSR_EC_CP15_64] = kvm_handle_cp15_64, - [HSR_EC_CP14_MR] = kvm_handle_cp14_access, + [HSR_EC_CP14_MR] = kvm_handle_cp14_32, [HSR_EC_CP14_LS] = kvm_handle_cp14_load_store, - [HSR_EC_CP14_64] = kvm_handle_cp14_access, + [HSR_EC_CP14_64] = kvm_handle_cp14_64, [HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access, [HSR_EC_CP10_ID] = kvm_handle_cp10_id, [HSR_EC_HVC] = handle_hvc, @@ -98,13 +110,6 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) { u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu); - if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) || - !arm_exit_handlers[hsr_ec]) { - kvm_err("Unknown exception class: hsr: %#08x\n", - (unsigned int)kvm_vcpu_get_hsr(vcpu)); - BUG(); - } - return arm_exit_handlers[hsr_ec]; } diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile index 3023bb530edf160ddbbe974e820227950a06ac31..92eab1d51785b9078cce5084270251a1ab517809 100644 --- a/arch/arm/kvm/hyp/Makefile +++ b/arch/arm/kvm/hyp/Makefile @@ -2,6 +2,8 @@ # Makefile for Kernel-based Virtual Machine module, HYP part # +ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING + KVM=../../../../virt/kvm obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c index 92678b7bd046d74b2cb0ad6df34978c3a9e1c112..624a510d31df4095701387da09b4b9a27bd09a17 100644 --- a/arch/arm/kvm/hyp/switch.c +++ b/arch/arm/kvm/hyp/switch.c @@ -48,7 +48,9 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu, u32 *fpexc_host) write_sysreg(HSTR_T(15), HSTR); write_sysreg(HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11), HCPTR); val = read_sysreg(HDCR); - write_sysreg(val | HDCR_TPM | HDCR_TPMCR, HDCR); + val |= HDCR_TPM | HDCR_TPMCR; /* trap performance monitors */ + val |= HDCR_TDRA | HDCR_TDOSA | HDCR_TDA; /* trap debug regs */ + write_sysreg(val, HDCR); } static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu) diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index bf89c919efc1a2254b3b0cc37eef53d0a0efd912..bd0ee7fc304c9025e87ab1e2bd491f73aa4ebc0a 100644 --- a/arch/arm/kvm/init.S +++ b/arch/arm/kvm/init.S @@ -95,7 +95,6 @@ __do_hyp_init: @ - Write permission implies XN: disabled @ - Instruction cache: enabled @ - Data/Unified cache: enabled - @ - Memory alignment checks: enabled @ - MMU: enabled (this code must be run from an identity mapping) mrc p15, 4, r0, c1, c0, 0 @ HSCR ldr r2, =HSCTLR_MASK @@ -103,8 +102,8 @@ __do_hyp_init: mrc p15, 0, r1, c1, c0, 0 @ SCTLR ldr r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C) and r1, r1, r2 - ARM( ldr r2, =(HSCTLR_M | HSCTLR_A) ) - THUMB( ldr r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) ) + ARM( ldr r2, =(HSCTLR_M) ) + THUMB( ldr r2, =(HSCTLR_M | HSCTLR_TE) ) orr r1, r1, r2 orr r0, r0, r1 mcr p15, 4, r0, c1, c0, 0 @ HSCR diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c index b6e715fd3c90af8c74408b72652f9974a3fb894d..dac7ceb1a677746cadb086a2cf8a07d8e560373c 100644 --- a/arch/arm/kvm/mmio.c +++ b/arch/arm/kvm/mmio.c @@ -112,7 +112,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) } trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, - data); + &data); data = vcpu_data_host_to_guest(vcpu, data, len); vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); } @@ -182,14 +182,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt), len); - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, &data); kvm_mmio_write_buf(data_buf, len, data); ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len, data_buf); } else { trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len, - fault_ipa, 0); + fault_ipa, NULL); ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len, data_buf); diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 2fd5c135e8a4c07959dc096d24cd1edfa8e20222..2206e0e00934cb2c4c5819f0c2d35f0b6944b5da 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -829,22 +829,22 @@ void stage2_unmap_vm(struct kvm *kvm) * Walks the level-1 page table pointed to by kvm->arch.pgd and frees all * underlying level-2 and level-3 tables before freeing the actual level-1 table * and setting the struct pointer to NULL. - * - * Note we don't need locking here as this is only called when the VM is - * destroyed, which can only be done once. */ void kvm_free_stage2_pgd(struct kvm *kvm) { - if (kvm->arch.pgd == NULL) - return; + void *pgd = NULL; spin_lock(&kvm->mmu_lock); - unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE); + if (kvm->arch.pgd) { + unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE); + pgd = READ_ONCE(kvm->arch.pgd); + kvm->arch.pgd = NULL; + } spin_unlock(&kvm->mmu_lock); /* Free the HW pgd, one page at a time */ - free_pages_exact(kvm->arch.pgd, S2_PGD_SIZE); - kvm->arch.pgd = NULL; + if (pgd) + free_pages_exact(pgd, S2_PGD_SIZE); } static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, @@ -872,6 +872,9 @@ static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache pmd_t *pmd; pud = stage2_get_pud(kvm, cache, addr); + if (!pud) + return NULL; + if (stage2_pud_none(*pud)) { if (!cache) return NULL; @@ -1661,12 +1664,16 @@ static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data) int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end) { + if (!kvm->arch.pgd) + return 0; trace_kvm_age_hva(start, end); return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL); } int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) { + if (!kvm->arch.pgd) + return 0; trace_kvm_test_age_hva(hva); return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL); } diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index c2b131527a643f6e6808b78f8c53e9751d0f71a9..a08d7a93aebbece7777f042ec3881ad088104a4d 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -208,9 +208,10 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) { - int ret = 1; + struct kvm *kvm = vcpu->kvm; unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); unsigned long val; + int ret = 1; switch (psci_fn) { case PSCI_0_2_FN_PSCI_VERSION: @@ -230,7 +231,9 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) break; case PSCI_0_2_FN_CPU_ON: case PSCI_0_2_FN64_CPU_ON: + mutex_lock(&kvm->lock); val = kvm_psci_vcpu_on(vcpu); + mutex_unlock(&kvm->lock); break; case PSCI_0_2_FN_AFFINITY_INFO: case PSCI_0_2_FN64_AFFINITY_INFO: @@ -279,6 +282,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) { + struct kvm *kvm = vcpu->kvm; unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); unsigned long val; @@ -288,7 +292,9 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) val = PSCI_RET_SUCCESS; break; case KVM_PSCI_FN_CPU_ON: + mutex_lock(&kvm->lock); val = kvm_psci_vcpu_on(vcpu); + mutex_unlock(&kvm->lock); break; default: val = PSCI_RET_NOT_SUPPORTED; diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 31dde8b6f2ea122cfda899960f5628169de5dd35..8ba0e2e5ad97ca1f3e532b8a90dd783eea8d4db0 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -335,7 +335,7 @@ static void at91sam9_sdram_standby(void) at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); } -static const struct of_device_id const ramc_ids[] __initconst = { +static const struct of_device_id ramc_ids[] __initconst = { { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, diff --git a/arch/arm/mach-bcm/bcm_kona_smc.c b/arch/arm/mach-bcm/bcm_kona_smc.c index cf3f8658f0e5e9849f866e2135f76aa81c11b1cc..a55a7ecf146a277df8c55603837b67d6fdc30a03 100644 --- a/arch/arm/mach-bcm/bcm_kona_smc.c +++ b/arch/arm/mach-bcm/bcm_kona_smc.c @@ -33,7 +33,7 @@ struct bcm_kona_smc_data { unsigned result; }; -static const struct of_device_id const bcm_kona_smc_ids[] __initconst = { +static const struct of_device_id bcm_kona_smc_ids[] __initconst = { {.compatible = "brcm,kona-smc"}, {.compatible = "bcm,kona-smc"}, /* deprecated name */ {}, diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c index 03da3813f1ab631a0f97be7a1d893176820f9b29..7d5a44a06648de2fd8e5e15beef19762d6925e81 100644 --- a/arch/arm/mach-cns3xxx/core.c +++ b/arch/arm/mach-cns3xxx/core.c @@ -346,7 +346,7 @@ static struct usb_ohci_pdata cns3xxx_usb_ohci_pdata = { .power_off = csn3xxx_usb_power_off, }; -static const struct of_dev_auxdata const cns3xxx_auxdata[] __initconst = { +static const struct of_dev_auxdata cns3xxx_auxdata[] __initconst = { { "intel,usb-ehci", CNS3XXX_USB_BASE, "ehci-platform", &cns3xxx_usb_ehci_pdata }, { "intel,usb-ohci", CNS3XXX_USB_OHCI_BASE, "ohci-platform", &cns3xxx_usb_ohci_pdata }, { "cavium,cns3420-ahci", CNS3XXX_SATA2_BASE, "ahci", NULL }, diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c index f6ba589cd312ecb257829d81f7f04c967b60e216..c821c1d5610ef25c56e1c0873452a019a602380d 100644 --- a/arch/arm/mach-omap1/dma.c +++ b/arch/arm/mach-omap1/dma.c @@ -32,7 +32,6 @@ #include "soc.h" #define OMAP1_DMA_BASE (0xfffed800) -#define OMAP1_LOGICAL_DMA_CH_COUNT 17 static u32 enable_1510_mode; @@ -348,8 +347,6 @@ static int __init omap1_system_dma_init(void) goto exit_iounmap; } - d->lch_count = OMAP1_LOGICAL_DMA_CH_COUNT; - /* Valid attributes for omap1 plus processors */ if (cpu_is_omap15xx()) d->dev_caps = ENABLE_1510_MODE; @@ -366,13 +363,14 @@ static int __init omap1_system_dma_init(void) d->dev_caps |= CLEAR_CSR_ON_READ; d->dev_caps |= IS_WORD_16; - if (cpu_is_omap15xx()) - d->chan_count = 9; - else if (cpu_is_omap16xx() || cpu_is_omap7xx()) { - if (!(d->dev_caps & ENABLE_1510_MODE)) - d->chan_count = 16; + /* available logical channels */ + if (cpu_is_omap15xx()) { + d->lch_count = 9; + } else { + if (d->dev_caps & ENABLE_1510_MODE) + d->lch_count = 9; else - d->chan_count = 9; + d->lch_count = 16; } p = dma_plat_info; diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 8633c703546a65c2e5b0071ffca0d5a12b664884..2944af82055847935462da4035a73b513c5795a6 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -367,7 +367,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) return ret; } -void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) +int gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) { int err; struct device *dev = &gpmc_onenand_device.dev; @@ -393,15 +393,17 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) if (err < 0) { dev_err(dev, "Cannot request GPMC CS %d, error %d\n", gpmc_onenand_data->cs, err); - return; + return err; } gpmc_onenand_resource.end = gpmc_onenand_resource.start + ONENAND_IO_SIZE - 1; - if (platform_device_register(&gpmc_onenand_device) < 0) { + err = platform_device_register(&gpmc_onenand_device); + if (err) { dev_err(dev, "Unable to register OneNAND device\n"); gpmc_cs_free(gpmc_onenand_data->cs); - return; } + + return err; } diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S index fe36ce2734d47a81f8dd5cbfdf72e9f6717df903..4c6f14cf92a82e3dbf8d7ceeb985686feb79e924 100644 --- a/arch/arm/mach-omap2/omap-headsmp.S +++ b/arch/arm/mach-omap2/omap-headsmp.S @@ -17,6 +17,7 @@ #include #include +#include #include "omap44xx.h" @@ -66,7 +67,7 @@ wait_2: ldr r2, =AUX_CORE_BOOT0_PA @ read from AuxCoreBoot0 cmp r0, r4 bne wait_2 ldr r12, =API_HYP_ENTRY - adr r0, hyp_boot + badr r0, hyp_boot smc #0 hyp_boot: b omap_secondary_startup diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index e920dd83e443753ccced325ce19c48c6bca398c6..f989145480c8fcd0c947beaadeefe6955896a434 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -222,6 +222,14 @@ static int _omap_device_notifier_call(struct notifier_block *nb, dev_err(dev, "failed to idle\n"); } break; + case BUS_NOTIFY_BIND_DRIVER: + od = to_omap_device(pdev); + if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED) && + pm_runtime_status_suspended(dev)) { + od->_driver_status = BUS_NOTIFY_BIND_DRIVER; + pm_runtime_set_active(dev); + } + break; case BUS_NOTIFY_ADD_DEVICE: if (pdev->dev.of_node) omap_device_build_from_dt(pdev); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 1052b29697b8946a5407e919369e2aaf5efba409..b5c1714ebfddc0451dfb1eb4cf5e5b8a4157150c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -790,14 +790,14 @@ static int _init_main_clk(struct omap_hwmod *oh) int ret = 0; char name[MOD_CLK_MAX_NAME_LEN]; struct clk *clk; + static const char modck[] = "_mod_ck"; - /* +7 magic comes from '_mod_ck' suffix */ - if (strlen(oh->name) + 7 > MOD_CLK_MAX_NAME_LEN) + if (strlen(oh->name) >= MOD_CLK_MAX_NAME_LEN - strlen(modck)) pr_warn("%s: warning: cropping name for %s\n", __func__, oh->name); - strncpy(name, oh->name, MOD_CLK_MAX_NAME_LEN - 7); - strcat(name, "_mod_ck"); + strlcpy(name, oh->name, MOD_CLK_MAX_NAME_LEN - strlen(modck)); + strlcat(name, modck, MOD_CLK_MAX_NAME_LEN); clk = clk_get(NULL, name); if (!IS_ERR(clk)) { diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 1cc4a6f3954e1936c30005a9b61bcda65bbccd69..bca54154e14f7c57f931b9068646853c7d1aa45e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -3828,16 +3828,20 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_hwmod_ocp_ifs[] __initdata = { * Return: 0 if device named @dev_name is not likely to be accessible, * or 1 if it is likely to be accessible. */ -static int __init omap3xxx_hwmod_is_hs_ip_block_usable(struct device_node *bus, - const char *dev_name) +static bool __init omap3xxx_hwmod_is_hs_ip_block_usable(struct device_node *bus, + const char *dev_name) { + struct device_node *node; + bool available; + if (!bus) - return (omap_type() == OMAP2_DEVICE_TYPE_GP) ? 1 : 0; + return omap_type() == OMAP2_DEVICE_TYPE_GP; - if (of_device_is_available(of_find_node_by_name(bus, dev_name))) - return 1; + node = of_get_child_by_name(bus, dev_name); + available = of_device_is_available(node); + of_node_put(node); - return 0; + return available; } int __init omap3xxx_hwmod_init(void) @@ -3906,15 +3910,20 @@ int __init omap3xxx_hwmod_init(void) if (h_sham && omap3xxx_hwmod_is_hs_ip_block_usable(bus, "sham")) { r = omap_hwmod_register_links(h_sham); - if (r < 0) + if (r < 0) { + of_node_put(bus); return r; + } } if (h_aes && omap3xxx_hwmod_is_hs_ip_block_usable(bus, "aes")) { r = omap_hwmod_register_links(h_aes); - if (r < 0) + if (r < 0) { + of_node_put(bus); return r; + } } + of_node_put(bus); /* * Register hwmod links specific to certain ES levels of a diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 05e20aaf68dd0461b23acfcf1c6aef78adb5a8c7..88676fe9b11941f29b5415063851b6457b501b89 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -147,7 +147,7 @@ static struct ti_st_plat_data wilink_pdata = { .nshutdown_gpio = 137, .dev_name = "/dev/ttyO1", .flow_cntrl = 1, - .baud_rate = 300000, + .baud_rate = 3000000, }; static struct platform_device wl18xx_device = { @@ -162,7 +162,7 @@ static struct ti_st_plat_data wilink7_pdata = { .nshutdown_gpio = 162, .dev_name = "/dev/ttyO1", .flow_cntrl = 1, - .baud_rate = 300000, + .baud_rate = 3000000, }; static struct platform_device wl128x_device = { @@ -600,7 +600,6 @@ static void pdata_quirks_check(struct pdata_init *quirks) if (of_machine_is_compatible(quirks->compatible)) { if (quirks->fn) quirks->fn(); - break; } quirks++; } diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 5b2f5138d938ac626a1895b71a9a44cd0d757785..f1ca9479491bea2b88f2e8103e95b793428f9ac9 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -713,7 +713,7 @@ static struct omap_prcm_init_data scrm_data __initdata = { }; #endif -static const struct of_device_id const omap_prcm_dt_match_table[] __initconst = { +static const struct of_device_id omap_prcm_dt_match_table[] __initconst = { #ifdef CONFIG_SOC_AM33XX { .compatible = "ti,am3-prcm", .data = &am3_prm_data }, #endif diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 2028167fff310041cf54037798f81cc8efa9efc2..d76b1e5eb8ba50ed9a09b0e1df3c56b1e2f0c6bb 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -559,7 +559,7 @@ struct i2c_init_data { u8 hsscll_12; }; -static const struct i2c_init_data const omap4_i2c_timing_data[] __initconst = { +static const struct i2c_init_data omap4_i2c_timing_data[] __initconst = { { .load = 50, .loadbits = 0x3, diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index f4d7965e10ae2a58f1ef2c69911b87dfe41833d1..4952b98eb86f8975ad1485581fe05432738d353c 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -43,13 +43,38 @@ config ARCH_SDXPOORWILLS select CPU_V7 select HAVE_ARM_ARCH_TIMER select MSM_CORTEX_A7 - select COMMON_CLK_MSM select PINCTRL + select PCI select QCOM_SCM if SMP select MSM_JTAG_MM if CORESIGHT_ETM select PM_DEVFREQ select COMMON_CLK select COMMON_CLK_QCOM select QCOM_GDSC + +config ARCH_MSM8953 + bool "Enable support for MSM8953" + select CPU_V7 + select HAVE_ARM_ARCH_TIMER + select PINCTRL + select QCOM_SCM if SMP + select PM_DEVFREQ + select CLKDEV_LOOKUP + select HAVE_CLK + select HAVE_CLK_PREPARE + select COMMON_CLK_MSM + +config ARCH_SDM450 + bool "Enable support for SDM450" + select CPU_V7 + select HAVE_ARM_ARCH_TIMER + select PINCTRL + select QCOM_SCM if SMP + select PM_DEVFREQ + select CLKDEV_LOOKUP + select HAVE_CLK + select HAVE_CLK_PREPARE + select COMMON_CLK_MSM + endmenu endif diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile index d893b2732f2718d7f20d0561ef132173e7444e09..828e9c9fc9bbced4b5fd31d6b38e1d7fde70a21a 100644 --- a/arch/arm/mach-qcom/Makefile +++ b/arch/arm/mach-qcom/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_USE_OF) += board-dt.o obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o +obj-$(CONFIG_ARCH_MSM8953) += board-msm8953.o +obj-$(CONFIG_ARCH_SDM450) += board-sdm450.o diff --git a/arch/arm/mach-qcom/board-msm8953.c b/arch/arm/mach-qcom/board-msm8953.c new file mode 100644 index 0000000000000000000000000000000000000000..cae3bf777b107f7e5fbde8ed8883e9ab01fd97e9 --- /dev/null +++ b/arch/arm/mach-qcom/board-msm8953.c @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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 +#include "board-dt.h" +#include +#include + +static const char *msm8953_dt_match[] __initconst = { + "qcom,msm8953", + NULL +}; + +static void __init msm8953_init(void) +{ + board_dt_populate(NULL); +} + +DT_MACHINE_START(MSM8953_DT, + "Qualcomm Technologies, Inc. MSM8953 (Flattened Device Tree)") + .init_machine = msm8953_init, + .dt_compat = msm8953_dt_match, +MACHINE_END diff --git a/arch/arm/mach-qcom/board-sdm450.c b/arch/arm/mach-qcom/board-sdm450.c new file mode 100644 index 0000000000000000000000000000000000000000..5f68ede502c1e2a9a83c5f8fa7fac5db52f78176 --- /dev/null +++ b/arch/arm/mach-qcom/board-sdm450.c @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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 +#include "board-dt.h" +#include +#include + +static const char *sdm450_dt_match[] __initconst = { + "qcom,sdm450", + NULL +}; + +static void __init sdm450_init(void) +{ + board_dt_populate(NULL); +} + +DT_MACHINE_START(SDM450_DT, + "Qualcomm Technologies, Inc. SDM450 (Flattened Device Tree)") + .init_machine = sdm450_init, + .dt_compat = sdm450_dt_match, +MACHINE_END diff --git a/arch/arm/mach-spear/time.c b/arch/arm/mach-spear/time.c index 9ccffc1d0f28dd43edbb8649ffd8fdd3c6e51431..aaaa6781b9feab2102c9f143af0efc22aed10bb1 100644 --- a/arch/arm/mach-spear/time.c +++ b/arch/arm/mach-spear/time.c @@ -204,7 +204,7 @@ static void __init spear_clockevent_init(int irq) setup_irq(irq, &spear_timer_irq); } -static const struct of_device_id const timer_of_match[] __initconst = { +static const struct of_device_id timer_of_match[] __initconst = { { .compatible = "st,spear-timer", }, { }, }; diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 19f444e39a915b18a761930fd7c6208273978c8c..0a05c0ab34ddb8be2af8bba70e6cd4d524a0820e 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,8 @@ struct arm_dma_alloc_args { pgprot_t prot; const void *caller; bool want_vaddr; + bool skip_cpu_sync; + bool skip_zeroing; int coherent_flag; }; @@ -113,6 +116,21 @@ static void __dma_page_cpu_to_dev(struct page *, unsigned long, static void __dma_page_dev_to_cpu(struct page *, unsigned long, size_t, enum dma_data_direction); +static void * +__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, + const void *caller); + +static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn); + +static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot); + +static void *arm_dma_remap(struct device *dev, void *cpu_addr, + dma_addr_t handle, size_t size, + unsigned long attrs); + +static void arm_dma_unremap(struct device *dev, void *remapped_addr, + size_t size); + /** * arm_dma_map_page - map a portion of a page for streaming DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -194,6 +212,8 @@ struct dma_map_ops arm_dma_ops = { .sync_single_for_device = arm_dma_sync_single_for_device, .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, .sync_sg_for_device = arm_dma_sync_sg_for_device, + .remap = arm_dma_remap, + .unremap = arm_dma_unremap, }; EXPORT_SYMBOL(arm_dma_ops); @@ -276,7 +296,8 @@ static u64 get_coherent_dma_mask(struct device *dev) return mask; } -static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag) +static void __dma_clear_buffer(struct page *page, size_t size, + bool skip_zeroing, int coherent_flag) { /* * Ensure that the allocated pages are zeroed, and that any data @@ -287,7 +308,8 @@ static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag phys_addr_t end = base + size; while (size > 0) { void *ptr = kmap_atomic(page); - memset(ptr, 0, PAGE_SIZE); + if (!skip_zeroing) + memset(ptr, 0, PAGE_SIZE); if (coherent_flag != COHERENT) dmac_flush_range(ptr, ptr + PAGE_SIZE); kunmap_atomic(ptr); @@ -298,7 +320,8 @@ static void __dma_clear_buffer(struct page *page, size_t size, int coherent_flag outer_flush_range(base, end); } else { void *ptr = page_address(page); - memset(ptr, 0, size); + if (!skip_zeroing) + memset(ptr, 0, size); if (coherent_flag != COHERENT) { dmac_flush_range(ptr, ptr + size); outer_flush_range(__pa(ptr), __pa(ptr) + size); @@ -327,7 +350,7 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++) __free_page(p); - __dma_clear_buffer(page, size, coherent_flag); + __dma_clear_buffer(page, size, false, coherent_flag); return page; } @@ -350,6 +373,7 @@ static void __dma_free_buffer(struct page *page, size_t size) static void *__alloc_from_contiguous(struct device *dev, size_t size, pgprot_t prot, struct page **ret_page, const void *caller, bool want_vaddr, + bool skip_cpu_sync, bool skip_zeroing, int coherent_flag); static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, @@ -369,10 +393,10 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, prot, caller); } -static void __dma_free_remap(void *cpu_addr, size_t size) +static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn) { dma_common_free_remap(cpu_addr, size, - VM_ARM_DMA_CONSISTENT | VM_USERMAP, false); + VM_ARM_DMA_CONSISTENT | VM_USERMAP, no_warn); } #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K @@ -421,7 +445,8 @@ static int __init atomic_pool_init(void) */ if (dev_get_cma_area(NULL)) ptr = __alloc_from_contiguous(NULL, atomic_pool_size, prot, - &page, atomic_pool_init, true, NORMAL); + &page, atomic_pool_init, true, false, + false, NORMAL); else ptr = __alloc_remap_buffer(NULL, atomic_pool_size, gfp, prot, &page, atomic_pool_init, true); @@ -480,6 +505,15 @@ void __init dma_contiguous_remap(void) struct map_desc map; unsigned long addr; + /* + * Make start and end PMD_SIZE aligned, observing memory + * boundaries + */ + if (memblock_is_memory(start & PMD_MASK)) + start = start & PMD_MASK; + if (memblock_is_memory(ALIGN(end, PMD_SIZE))) + end = ALIGN(end, PMD_SIZE); + if (end > arm_lowmem_limit) end = arm_lowmem_limit; if (start >= end) @@ -500,8 +534,13 @@ void __init dma_contiguous_remap(void) * and ensures that this code is architecturally compliant. */ for (addr = __phys_to_virt(start); addr < __phys_to_virt(end); - addr += PMD_SIZE) - pmd_clear(pmd_off_k(addr)); + addr += PMD_SIZE) { + pmd_t *pmd; + + pmd = pmd_off_k(addr); + if (pmd_bad(*pmd)) + pmd_clear(pmd); + } flush_tlb_kernel_range(__phys_to_virt(start), __phys_to_virt(end)); @@ -520,21 +559,39 @@ static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, return 0; } -static void __dma_remap(struct page *page, size_t size, pgprot_t prot) +static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr, + void *data) +{ + pte_clear(&init_mm, addr, pte); + return 0; +} + +static void __dma_remap(struct page *page, size_t size, pgprot_t prot, + bool want_vaddr) { unsigned long start = (unsigned long) page_address(page); unsigned end = start + size; + int (*func)(pte_t *pte, pgtable_t token, unsigned long addr, + void *data); - apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot); + if (!want_vaddr) + func = __dma_clear_pte; + else + func = __dma_update_pte; + + apply_to_page_range(&init_mm, start, size, func, &prot); + mb(); /*Ensure pte's are updated */ flush_tlb_kernel_range(start, end); } + +#define NO_KERNEL_MAPPING_DUMMY 0x2222 static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, pgprot_t prot, struct page **ret_page, const void *caller, bool want_vaddr) { struct page *page; - void *ptr = NULL; + void *ptr = (void *)NO_KERNEL_MAPPING_DUMMY; /* * __alloc_remap_buffer is only called when the device is * non-coherent @@ -595,6 +652,7 @@ static int __free_from_pool(void *start, size_t size) static void *__alloc_from_contiguous(struct device *dev, size_t size, pgprot_t prot, struct page **ret_page, const void *caller, bool want_vaddr, + bool skip_cpu_sync, bool skip_zeroing, int coherent_flag) { unsigned long order = get_order(size); @@ -606,23 +664,37 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, if (!page) return NULL; - __dma_clear_buffer(page, size, coherent_flag); - - if (!want_vaddr) - goto out; + /* + * skip completely if we neither need to zero nor sync. + */ + if (!(skip_cpu_sync && skip_zeroing)) + __dma_clear_buffer(page, size, skip_zeroing, coherent_flag); if (PageHighMem(page)) { - ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller); - if (!ptr) { - dma_release_from_contiguous(dev, page, count); - return NULL; + if (!want_vaddr) { + /* + * Something non-NULL needs to be returned here. Give + * back a dummy address that is unmapped to catch + * clients trying to use the address incorrectly + */ + ptr = (void *)NO_KERNEL_MAPPING_DUMMY; + + /* also flush out the stale highmem mappings */ + kmap_flush_unused(); + kmap_atomic_flush_unused(); + } else { + ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, + caller); + if (!ptr) { + dma_release_from_contiguous(dev, page, count); + return NULL; + } } } else { - __dma_remap(page, size, prot); + __dma_remap(page, size, prot, want_vaddr); ptr = page_address(page); } - out: *ret_page = page; return ptr; } @@ -630,20 +702,23 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, static void __free_from_contiguous(struct device *dev, struct page *page, void *cpu_addr, size_t size, bool want_vaddr) { - if (want_vaddr) { - if (PageHighMem(page)) - __dma_free_remap(cpu_addr, size); - else - __dma_remap(page, size, PAGE_KERNEL); - } + if (PageHighMem(page)) + __dma_free_remap(cpu_addr, size, true); + else + __dma_remap(page, size, PAGE_KERNEL, true); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); } static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot) { - prot = (attrs & DMA_ATTR_WRITE_COMBINE) ? - pgprot_writecombine(prot) : - pgprot_dmacoherent(prot); + if (attrs & DMA_ATTR_WRITE_COMBINE) + prot = pgprot_writecombine(prot); + else if (attrs & DMA_ATTR_STRONGLY_ORDERED) + prot = pgprot_stronglyordered(prot); + /* if non-consistent just pass back what was given */ + else if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) + prot = pgprot_dmacoherent(prot); + return prot; } @@ -656,10 +731,11 @@ static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot) #define __get_dma_pgprot(attrs, prot) __pgprot(0) #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c, wv) NULL #define __alloc_from_pool(size, ret_page) NULL -#define __alloc_from_contiguous(dev, size, prot, ret, c, wv, coherent_flag) NULL +#define __alloc_from_contiguous(dev, size, prot, ret, c, \ + wv, scs, sz, coherent_flag) NULL #define __free_from_pool(cpu_addr, size) do { } while (0) #define __free_from_contiguous(dev, page, cpu_addr, size, wv) do { } while (0) -#define __dma_free_remap(cpu_addr, size) do { } while (0) +#define __dma_free_remap(cpu_addr, size, w) do { } while (0) #endif /* CONFIG_MMU */ @@ -698,7 +774,8 @@ static void *cma_allocator_alloc(struct arm_dma_alloc_args *args, { return __alloc_from_contiguous(args->dev, args->size, args->prot, ret_page, args->caller, - args->want_vaddr, args->coherent_flag); + args->want_vaddr, args->skip_cpu_sync, + args->skip_zeroing, args->coherent_flag); } static void cma_allocator_free(struct arm_dma_free_args *args) @@ -739,7 +816,7 @@ static void *remap_allocator_alloc(struct arm_dma_alloc_args *args, static void remap_allocator_free(struct arm_dma_free_args *args) { if (args->want_vaddr) - __dma_free_remap(args->cpu_addr, args->size); + __dma_free_remap(args->cpu_addr, args->size, false); __dma_free_buffer(args->page, args->size); } @@ -765,6 +842,8 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, .prot = prot, .caller = caller, .want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0), + .skip_cpu_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC), + .skip_zeroing = (attrs & DMA_ATTR_SKIP_ZEROING), .coherent_flag = is_coherent ? COHERENT : NORMAL, }; @@ -826,7 +905,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, kfree(buf); } - return args.want_vaddr ? addr : page; + return addr; } /* @@ -874,6 +953,41 @@ static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, return ret; } +static void *arm_dma_remap(struct device *dev, void *cpu_addr, + dma_addr_t handle, size_t size, + unsigned long attrs) +{ + void *ptr; + struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); + pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); + unsigned long offset = handle & ~PAGE_MASK; + + size = PAGE_ALIGN(size + offset); + ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, + __builtin_return_address(0)); + return ptr ? ptr + offset : ptr; +} + +static void arm_dma_unremap(struct device *dev, void *remapped_addr, + size_t size) +{ + unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP; + struct vm_struct *area; + + size = PAGE_ALIGN(size); + remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK); + + area = find_vm_area(remapped_addr); + if (!area || (area->flags & flags) != flags) { + WARN(1, "trying to free invalid coherent area: %p\n", + remapped_addr); + return; + } + + vunmap(remapped_addr); + flush_tlb_kernel_range((unsigned long)remapped_addr, + (unsigned long)(remapped_addr + size)); +} /* * Create userspace mapping for the DMA-coherent memory. */ @@ -931,13 +1045,31 @@ static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_add __arm_dma_free(dev, size, cpu_addr, handle, attrs, true); } +/* + * The whole dma_get_sgtable() idea is fundamentally unsafe - it seems + * that the intention is to allow exporting memory allocated via the + * coherent DMA APIs through the dma_buf API, which only accepts a + * scattertable. This presents a couple of problems: + * 1. Not all memory allocated via the coherent DMA APIs is backed by + * a struct page + * 2. Passing coherent DMA memory into the streaming APIs is not allowed + * as we will try to flush the memory through a different alias to that + * actually being used (and the flushes are redundant.) + */ int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr, dma_addr_t handle, size_t size, unsigned long attrs) { - struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); + unsigned long pfn = dma_to_pfn(dev, handle); + struct page *page; int ret; + /* If the PFN is not valid, we do not have a struct page */ + if (!pfn_valid(pfn)) + return -ENXIO; + + page = pfn_to_page(pfn); + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); if (unlikely(ret)) return ret; @@ -1298,7 +1430,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, if (!page) goto error; - __dma_clear_buffer(page, size, coherent_flag); + __dma_clear_buffer(page, size, false, coherent_flag); for (i = 0; i < count; i++) pages[i] = page + i; @@ -1348,7 +1480,8 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, pages[i + j] = pages[i] + j; } - __dma_clear_buffer(pages[i], PAGE_SIZE << order, coherent_flag); + __dma_clear_buffer(pages[i], PAGE_SIZE << order, + false, coherent_flag); i += 1 << order; count -= 1 << order; } @@ -1819,7 +1952,31 @@ int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg, int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { - return __iommu_map_sg(dev, sg, nents, dir, attrs, false); + struct scatterlist *s; + int i; + size_t ret; + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int total_length = 0, current_offset = 0; + dma_addr_t iova; + int prot = __dma_direction_to_prot(dir); + + for_each_sg(sg, s, nents, i) + total_length += s->length; + + iova = __alloc_iova(mapping, total_length); + ret = iommu_map_sg(mapping->domain, iova, sg, nents, prot); + if (ret != total_length) { + __free_iova(mapping, iova, total_length); + return 0; + } + + for_each_sg(sg, s, nents, i) { + s->dma_address = iova + current_offset; + s->dma_length = total_length - current_offset; + current_offset += s->length; + } + + return nents; } static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg, @@ -1870,7 +2027,15 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { - __iommu_unmap_sg(dev, sg, nents, dir, attrs, false); + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int total_length = sg_dma_len(sg); + dma_addr_t iova = sg_dma_address(sg); + + total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length); + iova &= PAGE_MASK; + + iommu_unmap(mapping->domain, iova, total_length); + __free_iova(mapping, iova, total_length); } /** @@ -1985,9 +2150,6 @@ static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle, int offset = handle & ~PAGE_MASK; int len = PAGE_ALIGN(size + offset); - if (!iova) - return; - iommu_unmap(mapping->domain, iova, len); __free_iova(mapping, iova, len); } @@ -2085,9 +2247,6 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev, struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); unsigned int offset = handle & ~PAGE_MASK; - if (!iova) - return; - __dma_page_dev_to_cpu(page, offset, size, dir); } @@ -2099,9 +2258,6 @@ static void arm_iommu_sync_single_for_device(struct device *dev, struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); unsigned int offset = handle & ~PAGE_MASK; - if (!iova) - return; - __dma_page_cpu_to_dev(page, offset, size, dir); } @@ -2151,69 +2307,81 @@ const struct dma_map_ops iommu_coherent_ops = { * IO address ranges, which is required to perform memory allocation and * mapping with IOMMU aware functions. * - * The client device need to be attached to the mapping with - * arm_iommu_attach_device function. + * Clients may use iommu_domain_set_attr() to set additional flags prior + * to calling arm_iommu_attach_device() to complete initialization. */ struct dma_iommu_mapping * arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size) { unsigned int bits = size >> PAGE_SHIFT; - unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); struct dma_iommu_mapping *mapping; + + if (!bits) + return ERR_PTR(-EINVAL); + + mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL); + if (!mapping) + return ERR_PTR(-ENOMEM); + + mapping->base = base; + mapping->bits = bits; + + mapping->domain = iommu_domain_alloc(bus); + if (!mapping->domain) + goto err_domain_alloc; + + mapping->init = false; + return mapping; + +err_domain_alloc: + kfree(mapping); + return ERR_PTR(-ENOMEM); +} +EXPORT_SYMBOL(arm_iommu_create_mapping); + +static int +iommu_init_mapping(struct device *dev, struct dma_iommu_mapping *mapping) +{ + unsigned int bitmap_size = BITS_TO_LONGS(mapping->bits) * sizeof(long); + u64 size = mapping->bits << PAGE_SHIFT; int extensions = 1; int err = -ENOMEM; - /* currently only 32-bit DMA address space is supported */ - if (size > DMA_BIT_MASK(32) + 1) - return ERR_PTR(-ERANGE); - if (!bitmap_size) - return ERR_PTR(-EINVAL); + return -EINVAL; + + WARN(!IS_ALIGNED(size, SZ_128M), + "size is not aligned to 128M, alignment enforced"); if (bitmap_size > PAGE_SIZE) { extensions = bitmap_size / PAGE_SIZE; bitmap_size = PAGE_SIZE; } - mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL); - if (!mapping) - goto err; - mapping->bitmap_size = bitmap_size; mapping->bitmaps = kzalloc(extensions * sizeof(unsigned long *), - GFP_KERNEL); + GFP_KERNEL); + if (!mapping->bitmaps) - goto err2; + return -ENOMEM; mapping->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL); if (!mapping->bitmaps[0]) - goto err3; + goto err; mapping->nr_bitmaps = 1; mapping->extensions = extensions; - mapping->base = base; - mapping->bits = bits; spin_lock_init(&mapping->lock); + mapping->ops = &iommu_ops; + return 0; - mapping->domain = iommu_domain_alloc(bus); - if (!mapping->domain) - goto err4; - - kref_init(&mapping->kref); - return mapping; -err4: - kfree(mapping->bitmaps[0]); -err3: - kfree(mapping->bitmaps); -err2: - kfree(mapping); err: - return ERR_PTR(err); + kfree(mapping->bitmaps); + return err; } -EXPORT_SYMBOL_GPL(arm_iommu_create_mapping); -static void release_iommu_mapping(struct kref *kref) +static void iommu_release_mapping(struct kref *kref) { int i; struct dma_iommu_mapping *mapping = @@ -2244,13 +2412,70 @@ static int extend_iommu_mapping(struct dma_iommu_mapping *mapping) return 0; } +/* + * arm_iommu_release_mapping + * @mapping: allocted via arm_iommu_create_mapping() + * + * Frees all resources associated with the iommu mapping. + * The device associated with this mapping must be in the 'detached' state + */ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping) { - if (mapping) - kref_put(&mapping->kref, release_iommu_mapping); + int is_fast = 0; + void (*release)(struct kref *kref); + + if (!mapping) + return; + + if (!mapping->init) { + iommu_domain_free(mapping->domain); + kfree(mapping); + return; + } + + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); + + if (is_fast) + release = fast_smmu_release_mapping; + else + release = iommu_release_mapping; + + kref_put(&mapping->kref, release); } EXPORT_SYMBOL_GPL(arm_iommu_release_mapping); +static int arm_iommu_init_mapping(struct device *dev, + struct dma_iommu_mapping *mapping) +{ + int err = -EINVAL; + u64 size = mapping->bits << PAGE_SHIFT; + int is_fast = 0; + + if (mapping->init) { + kref_get(&mapping->kref); + return 0; + } + + /* currently only 32-bit DMA address space is supported */ + if (size > DMA_BIT_MASK(32) + 1) { + dev_err(dev, "dma mask %llx too small\n", dma_get_mask(dev)); + return -ERANGE; + } + + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); + + if (is_fast) + err = fast_smmu_init_mapping(dev, mapping); + else + err = iommu_init_mapping(dev, mapping); + if (!err) { + kref_init(&mapping->kref); + mapping->init = true; + } + return err; +} + + static int __arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping) { @@ -2260,13 +2485,33 @@ static int __arm_iommu_attach_device(struct device *dev, if (err) return err; - kref_get(&mapping->kref); to_dma_iommu_mapping(dev) = mapping; pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); return 0; } +static void __arm_iommu_detach_device(struct device *dev) +{ + struct dma_iommu_mapping *mapping; + int is_fast; + + mapping = to_dma_iommu_mapping(dev); + if (!mapping) { + dev_warn(dev, "Not attached\n"); + return; + } + + if (msm_dma_unmap_all_for_dev(dev)) + dev_warn(dev, "IOMMU detach with outstanding mappings\n"); + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); + + iommu_detach_device(mapping->domain, dev); + to_dma_iommu_mapping(dev) = NULL; + + pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); +} + /** * arm_iommu_attach_device * @dev: valid struct device pointer @@ -2284,35 +2529,36 @@ int arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping) { int err; + int s1_bypass = 0; + struct iommu_group *group = dev->iommu_group; + + if (!group) { + dev_err(dev, "No iommu associated with device\n"); + return -EINVAL; + } + + if (iommu_get_domain_for_dev(dev)) { + dev_err(dev, "Device already attached to other iommu_domain\n"); + return -EINVAL; + } err = __arm_iommu_attach_device(dev, mapping); if (err) return err; - set_dma_ops(dev, &iommu_ops); - return 0; -} -EXPORT_SYMBOL_GPL(arm_iommu_attach_device); - -static void __arm_iommu_detach_device(struct device *dev) -{ - struct dma_iommu_mapping *mapping; - - mapping = to_dma_iommu_mapping(dev); - if (!mapping) { - dev_warn(dev, "Not attached\n"); - return; + err = arm_iommu_init_mapping(dev, mapping); + if (err) { + __arm_iommu_detach_device(dev); + return err; } - if (msm_dma_unmap_all_for_dev(dev)) - dev_warn(dev, "IOMMU detach with outstanding mappings\n"); - - iommu_detach_device(mapping->domain, dev); - kref_put(&mapping->kref, release_iommu_mapping); - to_dma_iommu_mapping(dev) = NULL; - - pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (!s1_bypass) + set_dma_ops(dev, mapping->ops); + return 0; } +EXPORT_SYMBOL_GPL(arm_iommu_attach_device); /** * arm_iommu_detach_device @@ -2323,8 +2569,21 @@ static void __arm_iommu_detach_device(struct device *dev) */ void arm_iommu_detach_device(struct device *dev) { + struct dma_iommu_mapping *mapping; + int s1_bypass = 0; + + mapping = to_dma_iommu_mapping(dev); + if (!mapping) { + dev_warn(dev, "Not attached\n"); + return; + } + __arm_iommu_detach_device(dev); - set_dma_ops(dev, NULL); + + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (!s1_bypass) + set_dma_ops(dev, NULL); } EXPORT_SYMBOL_GPL(arm_iommu_detach_device); diff --git a/arch/arm/mm/dma.h b/arch/arm/mm/dma.h index 70ea6852f94e41eafe8f165f562cb35a3aafafba..29c54f7d81f32f72553b3a17e92c9bcc5e03ba28 100644 --- a/arch/arm/mm/dma.h +++ b/arch/arm/mm/dma.h @@ -4,9 +4,6 @@ #include #ifndef MULTI_CACHE -#define dmac_map_area __glue(_CACHE,_dma_map_area) -#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area) - /* * These are private to the dma-mapping API. Do not use directly. * Their sole purpose is to ensure that data held in the cache diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c index 9fe8e241335c6edcb0db5077f5d4621aefb68944..e1f6f0daa8479cf1ef73f9bd644581fde2bfce60 100644 --- a/arch/arm/mm/dump.c +++ b/arch/arm/mm/dump.c @@ -126,8 +126,8 @@ static const struct prot_bits section_bits[] = { .val = PMD_SECT_USER, .set = "USR", }, { - .mask = L_PMD_SECT_RDONLY, - .val = L_PMD_SECT_RDONLY, + .mask = L_PMD_SECT_RDONLY | PMD_SECT_AP2, + .val = L_PMD_SECT_RDONLY | PMD_SECT_AP2, .set = "ro", .clear = "RW", #elif __LINUX_ARM_ARCH__ >= 6 diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index aec74bf85b39631081eeb5c399b421e1501272ce..a9ef54db9d5e47426a7bf75420312960fcee63c0 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -314,8 +314,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) * signal first. We do not need to release the mmap_sem because * it would already be released in __lock_page_or_retry in * mm/filemap.c. */ - if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) { + if (!user_mode(regs)) + goto no_context; return 0; + } /* * Major/minor page fault accounting is only done on the diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index d02f8187b1ccedb0df0520d2d75e6d93c838b360..0bb76731ba118f5f10258dd0741e8aab2fa2a5f4 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -147,3 +148,36 @@ void *kmap_atomic_pfn(unsigned long pfn) return (void *)vaddr; } + +#ifdef CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH +int kmap_remove_unused_cpu(unsigned int cpu) +{ + int start_idx, idx, type; + + pagefault_disable(); + type = kmap_atomic_idx(); + start_idx = type + 1 + KM_TYPE_NR * cpu; + + for (idx = start_idx; idx < KM_TYPE_NR + KM_TYPE_NR * cpu; idx++) { + unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + pte_t ptep; + + ptep = get_top_pte(vaddr); + if (ptep) + set_top_pte(vaddr, __pte(0)); + } + pagefault_enable(); + return 0; +} + +static void kmap_remove_unused(void *unused) +{ + kmap_remove_unused_cpu(smp_processor_id()); +} + +void kmap_atomic_flush_unused(void) +{ + on_each_cpu(kmap_remove_unused, NULL, 1); +} + +#endif diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 370581aeb87104273df695409af37876956c639f..cae69148ac3fbcb2e361255112b6f256320b4155 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -469,6 +469,54 @@ static void __init free_highpages(void) #endif } +#define MLK(b, t) (b), (t), (((t) - (b)) >> 10) +#define MLM(b, t) (b), (t), (((t) - (b)) >> 20) +#define MLK_ROUNDUP(b, t) (b), (t), (DIV_ROUND_UP(((t) - (b)), SZ_1K)) + +#ifdef CONFIG_ENABLE_VMALLOC_SAVING +static void print_vmalloc_lowmem_info(void) +{ + struct memblock_region *reg, *prev_reg = NULL; + + pr_notice( + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)high_memory, VMALLOC_END)); + + for_each_memblock_rev(memory, reg) { + phys_addr_t start_phys = reg->base; + phys_addr_t end_phys = reg->base + reg->size; + + if (start_phys > arm_lowmem_limit) + continue; + + if (end_phys > arm_lowmem_limit) + end_phys = arm_lowmem_limit; + + if (prev_reg == NULL) { + prev_reg = reg; + + pr_notice( + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)__va(start_phys), + (unsigned long)__va(end_phys))); + + continue; + } + + pr_notice( + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)__va(end_phys), + (unsigned long)__va(prev_reg->base))); + + + pr_notice( + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n", + MLM((unsigned long)__va(start_phys), + (unsigned long)__va(end_phys))); + } +} +#endif + /* * mem_init() marks the free areas in the mem_map and tells us how much * memory is free. This is done after various parts of the system have @@ -497,9 +545,6 @@ void __init mem_init(void) mem_init_print_info(NULL); -#define MLK(b, t) b, t, ((t) - (b)) >> 10 -#define MLM(b, t) b, t, ((t) - (b)) >> 20 -#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K) pr_notice("Virtual kernel memory layout:\n" " vector : 0x%08lx - 0x%08lx (%4ld kB)\n" @@ -507,29 +552,34 @@ void __init mem_init(void) " DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n" " ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n" #endif - " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" - " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" - " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" -#ifdef CONFIG_HIGHMEM - " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" -#endif -#ifdef CONFIG_MODULES - " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" -#endif - " .text : 0x%p" " - 0x%p" " (%4td kB)\n" - " .init : 0x%p" " - 0x%p" " (%4td kB)\n" - " .data : 0x%p" " - 0x%p" " (%4td kB)\n" - " .bss : 0x%p" " - 0x%p" " (%4td kB)\n", - + " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n", MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) + (PAGE_SIZE)), #ifdef CONFIG_HAVE_TCM MLK(DTCM_OFFSET, (unsigned long) dtcm_end), MLK(ITCM_OFFSET, (unsigned long) itcm_end), #endif - MLK(FIXADDR_START, FIXADDR_END), + MLK(FIXADDR_START, FIXADDR_END)); +#ifdef CONFIG_ENABLE_VMALLOC_SAVING + print_vmalloc_lowmem_info(); +#else + printk(KERN_NOTICE + " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" + " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n", MLM(VMALLOC_START, VMALLOC_END), - MLM(PAGE_OFFSET, (unsigned long)high_memory), + MLM(PAGE_OFFSET, (unsigned long)high_memory)); +#endif + printk(KERN_NOTICE +#ifdef CONFIG_HIGHMEM + " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" +#endif +#ifdef CONFIG_MODULES + " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" +#endif + " .text : 0x%p" " - 0x%p" " (%4d kB)\n" + " .init : 0x%p" " - 0x%p" " (%4d kB)\n" + " .data : 0x%p" " - 0x%p" " (%4d kB)\n" + " .bss : 0x%p" " - 0x%p" " (%4d kB)\n", #ifdef CONFIG_HIGHMEM MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) * (PAGE_SIZE)), @@ -543,10 +593,6 @@ void __init mem_init(void) MLK_ROUNDUP(_sdata, _edata), MLK_ROUNDUP(__bss_start, __bss_stop)); -#undef MLK -#undef MLM -#undef MLK_ROUNDUP - /* * Check boundaries twice: Some fundamental inconsistencies can * be detected at build time already. @@ -573,6 +619,10 @@ void __init mem_init(void) } #ifdef CONFIG_DEBUG_RODATA +#undef MLK +#undef MLM +#undef MLK_ROUNDUP + struct section_perm { const char *name; unsigned long start; @@ -580,6 +630,9 @@ struct section_perm { pmdval_t mask; pmdval_t prot; pmdval_t clear; + pteval_t ptemask; + pteval_t pteprot; + pteval_t pteclear; }; /* First section-aligned location at or after __start_rodata. */ @@ -593,6 +646,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)_stext, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, /* Make init RW (set NX). */ { @@ -601,6 +656,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)_sdata, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, /* Make rodata NX (set RO in ro_perms below). */ { @@ -609,6 +666,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)__init_begin, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, }; @@ -619,13 +678,15 @@ static struct section_perm ro_perms[] = { .start = (unsigned long)_stext, .end = (unsigned long)__init_begin, #ifdef CONFIG_ARM_LPAE - .mask = ~L_PMD_SECT_RDONLY, - .prot = L_PMD_SECT_RDONLY, + .mask = ~(L_PMD_SECT_RDONLY | PMD_SECT_AP2), + .prot = L_PMD_SECT_RDONLY | PMD_SECT_AP2, #else .mask = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE), .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, .clear = PMD_SECT_AP_WRITE, #endif + .ptemask = ~L_PTE_RDONLY, + .pteprot = L_PTE_RDONLY, }, }; @@ -634,6 +695,35 @@ static struct section_perm ro_perms[] = { * copied into each mm). During startup, this is the init_mm. Is only * safe to be called with preemption disabled, as under stop_machine(). */ +struct pte_data { + pteval_t mask; + pteval_t val; +}; + +static int __pte_update(pte_t *ptep, pgtable_t token, unsigned long addr, + void *d) +{ + struct pte_data *data = d; + pte_t pte = *ptep; + + pte = __pte((pte_val(*ptep) & data->mask) | data->val); + set_pte_ext(ptep, pte, 0); + + return 0; +} + +static inline void pte_update(unsigned long addr, pteval_t mask, + pteval_t prot, struct mm_struct *mm) +{ + struct pte_data data; + + data.mask = mask; + data.val = prot; + + apply_to_page_range(mm, addr, SECTION_SIZE, __pte_update, &data); + flush_tlb_kernel_range(addr, addr + SECTION_SIZE); +} + static inline void section_update(unsigned long addr, pmdval_t mask, pmdval_t prot, struct mm_struct *mm) { @@ -682,11 +772,21 @@ void set_section_perms(struct section_perm *perms, int n, bool set, for (addr = perms[i].start; addr < perms[i].end; - addr += SECTION_SIZE) - section_update(addr, perms[i].mask, - set ? perms[i].prot : perms[i].clear, mm); + addr += SECTION_SIZE) { + pmd_t *pmd; + + pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), + addr), addr); + if (pmd_bad(*pmd)) + section_update(addr, perms[i].mask, + set ? perms[i].prot : perms[i].clear, + mm); + else + pte_update(addr, perms[i].ptemask, + set ? perms[i].pteprot : perms[i].pteclear, + mm); + } } - } static void update_sections_early(struct section_perm perms[], int n) diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index ff0eed23ddf1354afd26ee0711f34680380227a1..203728dfac97c53cfe38e898dc744d9dec410c22 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -92,7 +92,8 @@ void __init add_static_vm_early(struct static_vm *svm) void *vaddr; vm = &svm->vm; - vm_area_add_early(vm); + if (!vm_area_check_early(vm)) + vm_area_add_early(vm); vaddr = vm->addr; list_for_each_entry(curr_svm, &static_vmlist, list) { diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index 66353caa35b9f78fa2aa4754dea3ce813593303f..641334ebf46dcd09832d83843b8521989af3b26f 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -89,7 +89,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -140,7 +140,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4001dd15818d79aea7e586d19e70943c8b689975..219aa9c3fdc51594ee96300cd920af2c44adcaa2 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1152,13 +1152,12 @@ early_param("vmalloc", early_vmalloc); phys_addr_t arm_lowmem_limit __initdata = 0; -void __init sanity_check_meminfo(void) +void __init adjust_lowmem_bounds(void) { phys_addr_t memblock_limit = 0; - int highmem = 0; u64 vmalloc_limit; struct memblock_region *reg; - bool should_use_highmem = false; + phys_addr_t lowmem_limit = 0; /* * Let's use our own (unoptimized) equivalent of __pa() that is @@ -1169,46 +1168,34 @@ void __init sanity_check_meminfo(void) */ vmalloc_limit = (u64)(uintptr_t)vmalloc_min - PAGE_OFFSET + PHYS_OFFSET; +#ifdef CONFIG_ENABLE_VMALLOC_SAVING + struct memblock_region *prev_reg = NULL; + + for_each_memblock(memory, reg) { + if (prev_reg == NULL) { + prev_reg = reg; + continue; + } + vmalloc_limit += reg->base - (prev_reg->base + prev_reg->size); + prev_reg = reg; + } +#endif + for_each_memblock(memory, reg) { phys_addr_t block_start = reg->base; phys_addr_t block_end = reg->base + reg->size; - phys_addr_t size_limit = reg->size; - - if (reg->base >= vmalloc_limit) - highmem = 1; - else - size_limit = vmalloc_limit - reg->base; - - - if (!IS_ENABLED(CONFIG_HIGHMEM) || cache_is_vipt_aliasing()) { - - if (highmem) { - pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n", - &block_start, &block_end); - memblock_remove(reg->base, reg->size); - should_use_highmem = true; - continue; - } - if (reg->size > size_limit) { - phys_addr_t overlap_size = reg->size - size_limit; - - pr_notice("Truncating RAM at %pa-%pa", - &block_start, &block_end); - block_end = vmalloc_limit; - pr_cont(" to -%pa", &block_end); - memblock_remove(vmalloc_limit, overlap_size); - should_use_highmem = true; - } - } - - if (!highmem) { - if (block_end > arm_lowmem_limit) { - if (reg->size > size_limit) - arm_lowmem_limit = vmalloc_limit; - else - arm_lowmem_limit = block_end; - } + if (reg->base < vmalloc_limit) { + if (block_end > lowmem_limit) + /* + * Compare as u64 to ensure vmalloc_limit does + * not get truncated. block_end should always + * fit in phys_addr_t so there should be no + * issue with assignment. + */ + lowmem_limit = min_t(u64, + vmalloc_limit, + block_end); /* * Find the first non-pmd-aligned page, and point @@ -1227,26 +1214,37 @@ void __init sanity_check_meminfo(void) if (!IS_ALIGNED(block_start, PMD_SIZE)) memblock_limit = block_start; else if (!IS_ALIGNED(block_end, PMD_SIZE)) - memblock_limit = arm_lowmem_limit; + memblock_limit = lowmem_limit; } } } - if (should_use_highmem) - pr_notice("Consider using a HIGHMEM enabled kernel.\n"); + arm_lowmem_limit = lowmem_limit; high_memory = __va(arm_lowmem_limit - 1) + 1; + if (!memblock_limit) + memblock_limit = arm_lowmem_limit; + /* * Round the memblock limit down to a pmd size. This * helps to ensure that we will allocate memory from the * last full pmd, which should be mapped. */ - if (memblock_limit) - memblock_limit = round_down(memblock_limit, PMD_SIZE); - if (!memblock_limit) - memblock_limit = arm_lowmem_limit; + memblock_limit = round_down(memblock_limit, PMD_SIZE); + + if (!IS_ENABLED(CONFIG_HIGHMEM) || cache_is_vipt_aliasing()) { + if (memblock_end_of_DRAM() > arm_lowmem_limit) { + phys_addr_t end = memblock_end_of_DRAM(); + + pr_notice("Ignoring RAM at %pa-%pa\n", + &memblock_limit, &end); + pr_notice("Consider using a HIGHMEM enabled kernel.\n"); + + memblock_remove(memblock_limit, end - memblock_limit); + } + } memblock_set_current_limit(memblock_limit); } @@ -1443,12 +1441,21 @@ static void __init map_lowmem(void) phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE); #endif phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE); + struct static_vm *svm; + phys_addr_t start; + phys_addr_t end; + unsigned long vaddr; + unsigned long pfn; + unsigned long length; + unsigned int type; + int nr = 0; /* Map all the lowmem memory banks. */ for_each_memblock(memory, reg) { - phys_addr_t start = reg->base; - phys_addr_t end = start + reg->size; struct map_desc map; + start = reg->base; + end = start + reg->size; + nr++; if (memblock_is_nomap(reg)) continue; @@ -1500,6 +1507,34 @@ static void __init map_lowmem(void) } } } + svm = early_alloc_aligned(sizeof(*svm) * nr, __alignof__(*svm)); + + for_each_memblock(memory, reg) { + struct vm_struct *vm; + + start = reg->base; + end = start + reg->size; + + if (end > arm_lowmem_limit) + end = arm_lowmem_limit; + if (start >= end) + break; + + vm = &svm->vm; + pfn = __phys_to_pfn(start); + vaddr = __phys_to_virt(start); + length = end - start; + type = MT_MEMORY_RW; + + vm->addr = (void *)(vaddr & PAGE_MASK); + vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK)); + vm->phys_addr = __pfn_to_phys(pfn); + vm->flags = VM_LOWMEM; + vm->flags |= VM_ARM_MTYPE(type); + vm->caller = map_lowmem; + add_static_vm_early(svm++); + mark_vmalloc_reserved_area(vm->addr, vm->size); + } } #ifdef CONFIG_ARM_PV_FIXUP @@ -1598,6 +1633,119 @@ void __init early_paging_init(const struct machine_desc *mdesc) #endif +#ifdef CONFIG_FORCE_PAGES +/* + * remap a PMD into pages + * We split a single pmd here none of this two pmd nonsense + */ +static noinline void __init split_pmd(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long pfn, + const struct mem_type *type) +{ + pte_t *pte, *start_pte; + pmd_t *base_pmd; + + base_pmd = pmd_offset( + pud_offset(pgd_offset(&init_mm, addr), addr), addr); + + if (pmd_none(*base_pmd) || pmd_bad(*base_pmd)) { + start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); +#ifndef CONFIG_ARM_LPAE + /* + * Following is needed when new pte is allocated for pmd[1] + * cases, which may happen when base (start) address falls + * under pmd[1]. + */ + if (addr & SECTION_SIZE) + start_pte += pte_index(addr); +#endif + } else { + start_pte = pte_offset_kernel(base_pmd, addr); + } + + pte = start_pte; + + do { + set_pte_ext(pte, pfn_pte(pfn, type->prot_pte), 0); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); + + *pmd = __pmd((__pa(start_pte) + PTE_HWTABLE_OFF) | type->prot_l1); + mb(); /* let pmd be programmed */ + flush_pmd_entry(pmd); + flush_tlb_all(); +} + +/* + * It's significantly easier to remap as pages later after all memory is + * mapped. Everything is sections so all we have to do is split + */ +static void __init remap_pages(void) +{ + struct memblock_region *reg; + + for_each_memblock(memory, reg) { + phys_addr_t phys_start = reg->base; + phys_addr_t phys_end = reg->base + reg->size; + unsigned long addr = (unsigned long)__va(phys_start); + unsigned long end = (unsigned long)__va(phys_end); + pmd_t *pmd = NULL; + unsigned long next; + unsigned long pfn = __phys_to_pfn(phys_start); + bool fixup = false; + unsigned long saved_start = addr; + + if (phys_start > arm_lowmem_limit) + break; + if (phys_end > arm_lowmem_limit) + end = (unsigned long)__va(arm_lowmem_limit); + if (phys_start >= phys_end) + break; + + pmd = pmd_offset( + pud_offset(pgd_offset(&init_mm, addr), addr), addr); + +#ifndef CONFIG_ARM_LPAE + if (addr & SECTION_SIZE) { + fixup = true; + pmd_empty_section_gap((addr - SECTION_SIZE) & PMD_MASK); + pmd++; + } + + if (end & SECTION_SIZE) + pmd_empty_section_gap(end); +#endif + + do { + next = addr + SECTION_SIZE; + + if (pmd_none(*pmd) || pmd_bad(*pmd)) + split_pmd(pmd, addr, next, pfn, + &mem_types[MT_MEMORY_RWX]); + pmd++; + pfn += SECTION_SIZE >> PAGE_SHIFT; + + } while (addr = next, addr < end); + + if (fixup) { + /* + * Put a faulting page table here to avoid detecting no + * pmd when accessing an odd section boundary. This + * needs to be faulting to help catch errors and avoid + * speculation + */ + pmd = pmd_off_k(saved_start); + pmd[0] = pmd[1] & ~1; + } + } +} +#else +static void __init remap_pages(void) +{ + +} +#endif + static void __init early_fixmap_shutdown(void) { int i; @@ -1641,6 +1789,7 @@ void __init paging_init(const struct machine_desc *mdesc) memblock_set_current_limit(arm_lowmem_limit); dma_contiguous_remap(); early_fixmap_shutdown(); + remap_pages(); devicemaps_init(mdesc); kmap_init(); tcm_init(); diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 2740967727e2057ef8897e4d4335d38acaeaac2c..13a25d6282f866f57839beff6a15280869ce4d53 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -85,7 +85,7 @@ static unsigned long irbar_read(void) } /* MPU initialisation functions */ -void __init sanity_check_meminfo_mpu(void) +void __init adjust_lowmem_bounds_mpu(void) { phys_addr_t phys_offset = PHYS_OFFSET; phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size; @@ -274,7 +274,7 @@ void __init mpu_setup(void) } } #else -static void sanity_check_meminfo_mpu(void) {} +static void adjust_lowmem_bounds_mpu(void) {} static void __init mpu_setup(void) {} #endif /* CONFIG_ARM_MPU */ @@ -295,10 +295,10 @@ void __init arm_mm_memblock_reserve(void) #endif } -void __init sanity_check_meminfo(void) +void __init adjust_lowmem_bounds(void) { phys_addr_t end; - sanity_check_meminfo_mpu(); + adjust_lowmem_bounds_mpu(); end = memblock_end_of_DRAM(); high_memory = __va(end - 1) + 1; memblock_set_current_limit(end); diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c index d19b1ad29b075fd8624d34edb0d9c18c9ef11e51..47b1f4781cceb2a87b45ecf5484654a6ef4d93dd 100644 --- a/arch/arm/mm/pageattr.c +++ b/arch/arm/mm/pageattr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2017 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 @@ -52,11 +52,13 @@ static int change_memory_common(unsigned long addr, int numpages, if (!numpages) return 0; - if (start < MODULES_VADDR || start >= MODULES_END) - return -EINVAL; + if (!IS_ENABLED(CONFIG_FORCE_PAGES)) { + if (start < MODULES_VADDR || start >= MODULES_END) + return -EINVAL; - if (end < MODULES_VADDR || start >= MODULES_END) - return -EINVAL; + if (end < MODULES_VADDR || start >= MODULES_END) + return -EINVAL; + } data.set_mask = set_mask; data.clear_mask = clear_mask; @@ -95,3 +97,19 @@ int set_memory_x(unsigned long addr, int numpages) __pgprot(0), __pgprot(L_PTE_XN)); } + +#ifdef CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC +void __kernel_map_pages(struct page *page, int numpages, int enable) +{ + unsigned long addr; + + if (PageHighMem(page)) + return; + + addr = (unsigned long) page_address(page); + if (enable) + set_memory_rw(addr, numpages); + else + set_memory_ro(addr, numpages); +} +#endif diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S index 8dea61640cc1a5e09332ad7ebf777773c9b38cc9..50497778c2e5908c82869b262cff0edfc8de6a5f 100644 --- a/arch/arm/mm/proc-v7m.S +++ b/arch/arm/mm/proc-v7m.S @@ -147,10 +147,10 @@ __v7m_setup_cont: @ Configure caches (if implemented) teq r8, #0 - stmneia r12, {r0-r6, lr} @ v7m_invalidate_l1 touches r0-r6 + stmneia sp, {r0-r6, lr} @ v7m_invalidate_l1 touches r0-r6 blne v7m_invalidate_l1 teq r8, #0 @ re-evalutae condition - ldmneia r12, {r0-r6, lr} + ldmneia sp, {r0-r6, lr} @ Configure the System Control Register to ensure 8-byte stack alignment @ Note the STKALIGN bit is either RW or RAO. diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c index a4ec240ee7ba38647e7a473b5eb88ef64029e39a..3eb018fa1a1f5c343817b79d3de2244f53b4f7ec 100644 --- a/arch/arm/probes/kprobes/core.c +++ b/arch/arm/probes/kprobes/core.c @@ -433,6 +433,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) struct hlist_node *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; + kprobe_opcode_t *correct_ret_addr = NULL; INIT_HLIST_HEAD(&empty_rp); kretprobe_hash_lock(current, &head, &flags); @@ -455,14 +456,34 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) /* another task is sharing our hash bucket */ continue; + orig_ret_address = (unsigned long)ri->ret_addr; + + if (orig_ret_address != trampoline_address) + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + + kretprobe_assert(ri, orig_ret_address, trampoline_address); + + correct_ret_addr = ri->ret_addr; + hlist_for_each_entry_safe(ri, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; + + orig_ret_address = (unsigned long)ri->ret_addr; if (ri->rp && ri->rp->handler) { __this_cpu_write(current_kprobe, &ri->rp->kp); get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; + ri->ret_addr = correct_ret_addr; ri->rp->handler(ri, regs); __this_cpu_write(current_kprobe, NULL); } - orig_ret_address = (unsigned long)ri->ret_addr; recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) @@ -474,7 +495,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) break; } - kretprobe_assert(ri, orig_ret_address, trampoline_address); kretprobe_hash_unlock(current, &flags); hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { diff --git a/arch/arm/probes/kprobes/test-core.c b/arch/arm/probes/kprobes/test-core.c index 9775de22e2ffa3359ff228116adc5a0874613bc8..a48354de1aa1e5f60beea896d0fa6d33ddef7c17 100644 --- a/arch/arm/probes/kprobes/test-core.c +++ b/arch/arm/probes/kprobes/test-core.c @@ -976,7 +976,10 @@ static void coverage_end(void) void __naked __kprobes_test_case_start(void) { __asm__ __volatile__ ( - "stmdb sp!, {r4-r11} \n\t" + "mov r2, sp \n\t" + "bic r3, r2, #7 \n\t" + "mov sp, r3 \n\t" + "stmdb sp!, {r2-r11} \n\t" "sub sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t" "bic r0, lr, #1 @ r0 = inline data \n\t" "mov r1, sp \n\t" @@ -996,7 +999,8 @@ void __naked __kprobes_test_case_end_32(void) "movne pc, r0 \n\t" "mov r0, r4 \n\t" "add sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t" - "ldmia sp!, {r4-r11} \n\t" + "ldmia sp!, {r2-r11} \n\t" + "mov sp, r2 \n\t" "mov pc, r0 \n\t" ); } @@ -1012,7 +1016,8 @@ void __naked __kprobes_test_case_end_16(void) "bxne r0 \n\t" "mov r0, r4 \n\t" "add sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t" - "ldmia sp!, {r4-r11} \n\t" + "ldmia sp!, {r2-r11} \n\t" + "mov sp, r2 \n\t" "bx r0 \n\t" ); } diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index d062f08f50200f10f54e779e4086ddd6c4bd10ca..4b24964a520aa61b0f4674143446b18a5630466f 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c @@ -199,6 +199,7 @@ static struct dma_map_ops xen_swiotlb_dma_ops = { .unmap_page = xen_swiotlb_unmap_page, .dma_supported = xen_swiotlb_dma_supported, .set_dma_mask = xen_swiotlb_set_dma_mask, + .mmap = xen_swiotlb_dma_mmap, }; int __init xen_mm_init(void) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b8618766fbd03c4bcab52a407d73f1289340e83f..32a80d6e404577800cb53213b8dde6a2ee10c5cb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -9,6 +9,7 @@ config ARM64 select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_ELF_RANDOMIZE + select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_KCOV @@ -30,7 +31,7 @@ config ARM64 select ARM_PSCI_FW select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS - select COMMON_CLK + select COMMON_CLK if !ARCH_QCOM select CPU_PM if (SUSPEND || CPU_IDLE) select DCACHE_WORD_ACCESS select EDAC_SUPPORT @@ -108,6 +109,7 @@ config ARM64 select POWER_SUPPLY select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE + select THREAD_INFO_IN_TASK help ARM 64-bit (AArch64) Linux support. @@ -594,7 +596,7 @@ config HOTPLUG_CPU # selected platforms. config ARCH_NR_GPIO int - default 1024 if ARCH_QCOM + default 1280 if ARCH_QCOM default 256 help Maximum number of GPIOs in the system. @@ -779,6 +781,34 @@ config FORCE_MAX_ZONEORDER However for 4K, we choose a higher default value, 11 as opposed to 10, giving us 4M allocations matching the default size used by generic code. +config UNMAP_KERNEL_AT_EL0 + bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT + default y + help + Speculation attacks against some high-performance processors can + be used to bypass MMU permission checks and leak kernel data to + userspace. This can be defended against by unmapping the kernel + when running in userspace, mapping it back in on exception entry + via a trampoline page in the vector table. + + If unsure, say Y. + +config HARDEN_BRANCH_PREDICTOR + bool "Harden the branch predictor against aliasing attacks" if EXPERT + help + Speculation attacks against some high-performance processors rely on + being able to manipulate the branch predictor for a victim context by + executing aliasing branches in the attacker context. Such attacks + can be partially mitigated against by clearing internal branch + predictor state and limiting the prediction logic in some situations. + + This config option will take CPU-specific actions to harden the + branch predictor against aliasing attacks and may rely on specific + instruction sequences or control bits being set by the system + firmware. + + If unsure, say Y. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT @@ -1105,6 +1135,11 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES Space separated list of names of dtbs to append when building a concatenated Image.gz-dtb. +config BUILD_ARM64_DT_OVERLAY + bool "enable DT overlay compilation support" + depends on OF + help + This option enables support for DT overlay compilation. endmenu menu "Userspace binary formats" diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index b661fe74261538348c01be103fa00a35a9480d5e..3d9d6f36f8a5f4d7135e9dd5c2f4c9fae7bcf4d6 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -62,6 +62,9 @@ config DEBUG_ALIGN_RODATA If in doubt, say N. +config ARM64_STRICT_BREAK_BEFORE_MAKE + bool "Enforce strict break-before-make on page table updates " + source "drivers/hwtracing/coresight/Kconfig" endmenu diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 445aeb619837aac69ce6ea08eee8440064efb78a..d35cecbd74b249862239000186c7ffc6db04ca5a 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -114,27 +114,62 @@ config ARCH_MVEBU config ARCH_QCOM bool "Qualcomm Platforms" select PINCTRL + select CLKDEV_LOOKUP + select HAVE_CLK + select HAVE_CLK_PREPARE select SOC_BUS select PM_OPP + select MFD_CORE + select SND_SOC_COMPRESS + select SND_HWDEP help This enables support for the ARMv8 based Qualcomm chipsets. config ARCH_SDM845 bool "Enable Support for Qualcomm Technologies Inc. SDM845" depends on ARCH_QCOM + select COMMON_CLK select COMMON_CLK_QCOM select QCOM_GDSC help This enables support for the SDM845 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. -config ARCH_SDM830 - bool "Enable Support for Qualcomm Technologies Inc. SDM830" +config ARCH_SDM670 + bool "Enable Support for Qualcomm Technologies Inc. SDM670" depends on ARCH_QCOM + select COMMON_CLK select COMMON_CLK_QCOM select QCOM_GDSC help - This enables support for the SDM830 chipset. If you do not + This enables support for the SDM670 chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + +config ARCH_MSM8953 + bool "Enable Support for Qualcomm Technologies Inc. MSM8953" + depends on ARCH_QCOM + select CPU_FREQ_QCOM + select COMMON_CLK_MSM + help + This enables support for the MSM8953 chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + +config ARCH_SDM450 + bool "Enable Support for Qualcomm Technologies Inc. SDM450" + depends on ARCH_QCOM + select CPU_FREQ_QCOM + select COMMON_CLK_MSM + help + This enables support for the sdm450 chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + +config ARCH_SDM632 + bool "Enable Support for Qualcomm Technologies Inc. SDM632" + depends on ARCH_QCOM + select CPU_FREQ_QCOM + select COMMON_CLK_MSM + help + This enables support for the sdm632 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. config ARCH_ROCKCHIP diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 13a64c9b1e4a6d21d3a2b763145dc4e4b59c3ad3..b5e154ebcde2d7259fd2d511581ef0c0ddca5db6 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -14,8 +14,12 @@ LDFLAGS_vmlinux :=-p --no-undefined -X CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) GZFLAGS :=-9 -ifneq ($(CONFIG_RELOCATABLE),) -LDFLAGS_vmlinux += -pie -shared -Bsymbolic +ifeq ($(CONFIG_RELOCATABLE), y) +# Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour +# for relative relocs, since this leads to better Image compression +# with the relocation offsets always being zero. +LDFLAGS_vmlinux += -pie -shared -Bsymbolic \ + $(call ld-option, --no-apply-dynamic-relocs) endif ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) @@ -103,6 +107,10 @@ endif KBUILD_DTBS := dtbs +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +export DTC_FLAGS := -@ +endif + all: $(KBUILD_IMAGE) $(KBUILD_DTBS) boot := arch/arm64/boot diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 92dc1e631ae8c10dd27fec1b9d8cb6dfe5821348..b97f1de46be46db0e16d1a7d7eac1f5880854b35 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -28,6 +28,17 @@ else DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb) endif +# Add RTIC DTB to the DTB list if RTIC MPGen is enabled +ifdef RTIC_MPGEN +DTB_OBJS += rtic_mp.dtb +endif + +rtic_mp.dtb: vmlinux FORCE + $(RTIC_MPGEN) --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \ + --binpath="" --vmlinux="vmlinux" --config=${KCONFIG_CONFIG} \ + --cc="${CC}" --dts=rtic_mp.dts && \ + $(DTC) -O dtb -o rtic_mp.dtb -b 0 $(DTC_FLAGS) rtic_mp.dts + $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts index e6e3491d48a5ae97f877e4b9159b549a994a30b3..f150a4c63efe3c0a9b3cb11e9e8bac16401736ba 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -85,6 +85,18 @@ status = "okay"; pinctrl-0 = <ð_pins>; pinctrl-names = "default"; + phy-handle = <ð_phy0>; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@0 { + reg = <0>; + eee-broken-1000t; + }; + }; }; &ir { diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi index d95dc408629ad5ab93a37fb01c1a5d2182b2aedf..a16b1b3f9fc6a44bc80206c896ab690e0171db7c 100644 --- a/arch/arm64/boot/dts/broadcom/ns2.dtsi +++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi @@ -30,6 +30,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/memreserve/ 0x81000000 0x00200000; + #include #include diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi index 17839db585d5c8ec16f88fc6b8b383741bdd6eb3..509a2eda2ce408f28a723c7e65854f0b29b717df 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi @@ -772,6 +772,7 @@ clocks = <&sys_ctrl 2>, <&sys_ctrl 1>; clock-names = "ciu", "biu"; resets = <&sys_ctrl PERIPH_RSTDIS0_MMC0>; + reset-names = "reset"; bus-width = <0x8>; vmmc-supply = <&ldo19>; pinctrl-names = "default"; @@ -795,6 +796,7 @@ clocks = <&sys_ctrl 4>, <&sys_ctrl 3>; clock-names = "ciu", "biu"; resets = <&sys_ctrl PERIPH_RSTDIS0_MMC1>; + reset-names = "reset"; vqmmc-supply = <&ldo7>; vmmc-supply = <&ldo10>; bus-width = <0x4>; @@ -813,6 +815,7 @@ clocks = <&sys_ctrl HI6220_MMC2_CIUCLK>, <&sys_ctrl HI6220_MMC2_CLK>; clock-names = "ciu", "biu"; resets = <&sys_ctrl PERIPH_RSTDIS0_MMC2>; + reset-names = "reset"; bus-width = <0x4>; broken-cd; pinctrl-names = "default", "idle"; diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi index e9bd5879346499748b0cf8b39f6d921b31bede1c..68e6f88bdcfef83f396c385c7d98d7de2b19aabb 100644 --- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi @@ -75,14 +75,10 @@ timer { compatible = "arm,armv8-timer"; - interrupts = , - , - , - ; + interrupts = , + , + , + ; }; soc { @@ -174,6 +170,7 @@ interrupt-controller; reg = <0x1d00000 0x10000>, /* GICD */ <0x1d40000 0x40000>; /* GICR */ + interrupts = ; }; }; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index ff2cc3e428164276f3f489aa5301107d0e26ae1e..80d3e82cc4eee67ae786fa995e558ed5e61fa73f 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -2,6 +2,94 @@ dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb msm8916-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_SDM845) += \ + sdm845-cdp-overlay.dtbo \ + sdm845-mtp-overlay.dtbo \ + sdm845-qrd-overlay.dtbo \ + sdm845-4k-panel-mtp-overlay.dtbo \ + sdm845-4k-panel-cdp-overlay.dtbo \ + sdm845-4k-panel-qrd-overlay.dtbo \ + sdm845-v2-qvr-evt-overlay.dtbo \ + sdm845-v2-qvr-dvt-overlay.dtbo \ + sdm845-v2-cdp-overlay.dtbo \ + sdm845-v2-mtp-overlay.dtbo \ + sdm845-v2-qrd-overlay.dtbo \ + sdm845-v2-4k-panel-mtp-overlay.dtbo \ + sdm845-v2-4k-panel-cdp-overlay.dtbo \ + sdm845-v2-4k-panel-qrd-overlay.dtbo \ + sdm845-v2.1-cdp-overlay.dtbo \ + sdm845-v2.1-mtp-overlay.dtbo \ + sdm845-v2.1-qrd-overlay.dtbo \ + sdm845-v2.1-4k-panel-mtp-overlay.dtbo \ + sdm845-v2.1-4k-panel-cdp-overlay.dtbo \ + sdm845-v2.1-4k-panel-qrd-overlay.dtbo \ + sda845-cdp-overlay.dtbo \ + sda845-mtp-overlay.dtbo \ + sda845-qrd-overlay.dtbo \ + sda845-4k-panel-mtp-overlay.dtbo \ + sda845-4k-panel-cdp-overlay.dtbo \ + sda845-4k-panel-qrd-overlay.dtbo \ + sda845-v2-cdp-overlay.dtbo \ + sda845-v2-mtp-overlay.dtbo \ + sda845-v2-qrd-overlay.dtbo \ + sda845-v2-hdk-overlay.dtbo \ + sda845-v2-4k-panel-mtp-overlay.dtbo \ + sda845-v2-4k-panel-cdp-overlay.dtbo \ + sda845-v2-4k-panel-qrd-overlay.dtbo \ + sda845-v2.1-cdp-overlay.dtbo \ + sda845-v2.1-mtp-overlay.dtbo \ + sda845-v2.1-qrd-overlay.dtbo \ + sda845-v2.1-4k-panel-cdp-overlay.dtbo \ + sda845-v2.1-4k-panel-mtp-overlay.dtbo \ + sda845-v2.1-4k-panel-qrd-overlay.dtbo \ + sda845-v2.1-cdp-sdxpoorwills-overlay.dtbo \ + sda845-v2.1-mtp-sdxpoorwills-overlay.dtbo \ + sda845-v2-mtp-sdxpoorwills-overlay.dtbo + +sdm845-cdp-overlay.dtbo-base := sdm845.dtb +sdm845-mtp-overlay.dtbo-base := sdm845.dtb +sdm845-qrd-overlay.dtbo-base := sdm845.dtb +sdm845-4k-panel-mtp-overlay.dtbo-base := sdm845.dtb +sdm845-4k-panel-cdp-overlay.dtbo-base := sdm845.dtb +sdm845-4k-panel-qrd-overlay.dtbo-base := sdm845.dtb +sdm845-v2-qvr-evt-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-qvr-dvt-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-4k-panel-mtp-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-4k-panel-cdp-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2-4k-panel-qrd-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2.1-cdp-overlay.dtbo-base := sdm845-v2.1.dtb +sdm845-v2.1-mtp-overlay.dtbo-base := sdm845-v2.1.dtb +sdm845-v2.1-qrd-overlay.dtbo-base := sdm845-v2.1.dtb +sdm845-v2.1-4k-panel-mtp-overlay.dtbo-base := sdm845-v2.1.dtb +sdm845-v2.1-4k-panel-cdp-overlay.dtbo-base := sdm845-v2.1.dtb +sdm845-v2.1-4k-panel-qrd-overlay.dtbo-base := sdm845-v2.1.dtb +sda845-cdp-overlay.dtbo-base := sda845.dtb +sda845-mtp-overlay.dtbo-base := sda845.dtb +sda845-qrd-overlay.dtbo-base := sda845.dtb +sda845-4k-panel-mtp-overlay.dtbo-base := sda845.dtb +sda845-4k-panel-cdp-overlay.dtbo-base := sda845.dtb +sda845-4k-panel-qrd-overlay.dtbo-base := sda845.dtb +sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb +sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb +sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb +sda845-v2-hdk-overlay.dtbo-base := sda845-v2.dtb +sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb +sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb +sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb +sda845-v2.1-cdp-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-mtp-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-qrd-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-4k-panel-cdp-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-4k-panel-mtp-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-4k-panel-qrd-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-cdp-sdxpoorwills-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2.1-mtp-sdxpoorwills-overlay.dtbo-base := sda845-v2.1.dtb +sda845-v2-mtp-sdxpoorwills-overlay.dtbo-base := sda845-v2.dtb +else dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \ sdm845-rumi.dtb \ sdm845-mtp.dtb \ @@ -10,14 +98,198 @@ dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \ sdm845-v2-mtp.dtb \ sdm845-v2-cdp.dtb \ sdm845-qrd.dtb \ + sdm845-v2-qrd.dtb \ + sdm845-v2-qvr-evt.dtb \ + sdm845-v2-qvr-dvt.dtb \ sdm845-4k-panel-mtp.dtb \ sdm845-4k-panel-cdp.dtb \ - sdm845-4k-panel-qrd.dtb + sdm845-4k-panel-qrd.dtb \ + sdm845-interposer-sdm670-mtp.dtb \ + sdm845-interposer-sdm670-cdp.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_SDM670) += \ + sdm670-cdp-overlay.dtbo \ + sdm670-mtp-overlay.dtbo \ + sdm670-rumi-overlay.dtbo \ + sdm670-qrd-overlay.dtbo \ + sdm670-qrd-sku2-overlay.dtbo \ + sdm670-pm660a-cdp-overlay.dtbo \ + sdm670-pm660a-mtp-overlay.dtbo \ + sdm670-external-codec-cdp-overlay.dtbo \ + sdm670-external-codec-mtp-overlay.dtbo \ + sdm670-external-codec-pm660a-cdp-overlay.dtbo \ + sdm670-external-codec-pm660a-mtp-overlay.dtbo \ + sdm670-usbc-cdp-overlay.dtbo \ + sdm670-usbc-mtp-overlay.dtbo \ + sdm670-usbc-pm660a-cdp-overlay.dtbo \ + sdm670-usbc-pm660a-mtp-overlay.dtbo \ + sdm670-usbc-external-codec-cdp-overlay.dtbo \ + sdm670-usbc-external-codec-mtp-overlay.dtbo \ + sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo \ + sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo \ + sda670-cdp-overlay.dtbo \ + sda670-mtp-overlay.dtbo \ + sda670-pm660a-cdp-overlay.dtbo \ + sda670-pm660a-mtp-overlay.dtbo \ + sdm670-tasha-codec-cdp-overlay.dtbo \ + sdm670-pm660a-tasha-codec-cdp-overlay.dtbo \ + qcs605-cdp-overlay.dtbo \ + qcs605-mtp-overlay.dtbo \ + qcs605-360camera-overlay.dtbo \ + qcs605-external-codec-mtp-overlay.dtbo \ + qcs605-lc-mtp-overlay.dtbo + +sdm670-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-rumi-overlay.dtbo-base := sdm670.dtb +sdm670-qrd-overlay.dtbo-base := sdm670.dtb +sdm670-qrd-sku2-overlay.dtbo-base := sdm670.dtb +sdm670-pm660a-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-pm660a-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-external-codec-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-external-codec-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-pm660a-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-pm660a-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-external-codec-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-external-codec-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb +sdm670-tasha-codec-cdp-overlay.dtbo-base := sdm670.dtb +sdm670-pm660a-tasha-codec-cdp-overlay.dtbo-base := sdm670.dtb +sda670-cdp-overlay.dtbo-base := sda670.dtb +sda670-mtp-overlay.dtbo-base := sda670.dtb +sda670-pm660a-cdp-overlay.dtbo-base := sda670.dtb +sda670-pm660a-mtp-overlay.dtbo-base := sda670.dtb +qcs605-cdp-overlay.dtbo-base := qcs605.dtb +qcs605-mtp-overlay.dtbo-base := qcs605.dtb +qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb +qcs605-lc-mtp-overlay.dtbo-base := qcs605.dtb +qcs605-360camera-overlay.dtbo-base := qcs605.dtb + +else +dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ + sdm670-mtp.dtb \ + sdm670-cdp.dtb \ + sdm670-qrd.dtb \ + sdm670-qrd-sku2.dtb \ + sdm670-pm660a-mtp.dtb \ + sdm670-pm660a-cdp.dtb \ + sdm670-external-codec-cdp.dtb \ + sdm670-external-codec-mtp.dtb \ + sdm670-external-codec-pm660a-cdp.dtb \ + sdm670-external-codec-pm660a-mtp.dtb \ + sdm670-usbc-cdp.dtb \ + sdm670-usbc-external-codec-cdp.dtb \ + sdm670-usbc-external-codec-mtp.dtb \ + sdm670-usbc-external-codec-pm660a-cdp.dtb \ + sdm670-usbc-external-codec-pm660a-mtp.dtb \ + sdm670-usbc-mtp.dtb \ + sdm670-usbc-pm660a-cdp.dtb \ + sdm670-usbc-pm660a-mtp.dtb \ + sda670-mtp.dtb \ + sda670-cdp.dtb \ + sdm670-tasha-codec-cdp.dtb \ + sdm670-pm660a-tasha-codec-cdp.dtb \ + sda670-pm660a-mtp.dtb \ + sda670-pm660a-cdp.dtb \ + qcs605-360camera.dtb \ + qcs605-mtp.dtb \ + qcs605-cdp.dtb \ + qcs605-external-codec-mtp.dtb \ + qcs605-lc-mtp.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +dtbo-$(CONFIG_ARCH_MSM8953) += msm8953-mtp-overlay.dtbo \ + msm8953-cdp-overlay.dtbo \ + msm8953-rcm-overlay.dtbo \ + msm8953-ipc-overlay.dtbo \ + msm8953-qrd-overlay.dtbo \ + msm8953-iot-mtp-overlay.dtbo \ + msm8953-ext-codec-mtp-overlay.dtbo \ + msm8953-ext-codec-rcm-overlay.dtbo \ + msm8953-cdp-1200p-overlay.dtbo + +dtbo-$(CONFIG_ARCH_SDM450) += msm8953-mtp-overlay.dtbo \ + msm8953-cdp-overlay.dtbo \ + msm8953-rcm-overlay.dtbo \ + msm8953-qrd-overlay.dtbo \ + msm8953-iot-mtp-overlay.dtbo + +msm8953-mtp-overlay.dtbo-base := sdm450.dtb \ + msm8953.dtb \ + apq8053.dtb \ + msm8953-pmi8940.dtb \ + msm8953-pmi8937.dtb \ + sdm450-pmi8940.dtb \ + sdm450-pmi8937.dtb +msm8953-cdp-overlay.dtbo-base := sdm450.dtb \ + msm8953.dtb \ + apq8053.dtb \ + msm8953-pmi8940.dtb \ + msm8953-pmi8937.dtb +msm8953-rcm-overlay.dtbo-base := sdm450.dtb \ + msm8953.dtb \ + apq8053.dtb +msm8953-ipc-overlay.dtbo-base := msm8953.dtb \ + apq8053.dtb +msm8953-qrd-overlay.dtbo-base := sdm450.dtb \ + msm8953.dtb +msm8953-iot-mtp-overlay.dtbo-base := sdm450.dtb \ + msm8953.dtb \ + apq8053.dtb +msm8953-ext-codec-mtp-overlay.dtbo-base := msm8953.dtb \ + apq8053.dtb \ + msm8953-pmi8940.dtb \ + msm8953-pmi8937.dtb +msm8953-ext-codec-rcm-overlay.dtbo-base := msm8953.dtb \ + apq8053.dtb +msm8953-cdp-1200p-overlay.dtbo-base := msm8953.dtb + +else +dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \ + msm8953-mtp.dtb \ + msm8953-ext-codec-mtp.dtb \ + msm8953-qrd-sku3.dtb \ + msm8953-rcm.dtb \ + apq8053-rcm.dtb \ + msm8953-ext-codec-rcm.dtb \ + apq8053-cdp.dtb \ + apq8053-ipc.dtb \ + msm8953-ipc.dtb \ + apq8053-mtp.dtb \ + apq8053-ext-audio-mtp.dtb \ + apq8053-ext-codec-rcm.dtb \ + msm8953-cdp-1200p.dtb \ + msm8953-iot-mtp.dtb \ + apq8053-iot-mtp.dtb \ + msm8953-pmi8940-cdp.dtb \ + msm8953-pmi8940-mtp.dtb \ + msm8953-pmi8937-cdp.dtb \ + msm8953-pmi8937-mtp.dtb \ + msm8953-pmi8940-ext-codec-mtp.dtb \ + msm8953-pmi8937-ext-codec-mtp.dtb + +dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \ + sdm450-cdp.dtb \ + sdm450-mtp.dtb \ + sdm450-qrd.dtb \ + sdm450-pmi8940-mtp.dtb \ + sdm450-pmi8937-mtp.dtb \ + sdm450-iot-mtp.dtb \ + sdm450-qrd-sku4.dtb \ + sdm450-pmi632-cdp-s2.dtb \ + sdm450-pmi632-mtp-s3.dtb + +dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb -dtb-$(CONFIG_ARCH_SDM830) += sdm830-sim.dtb \ - sdm830-rumi.dtb \ - sdm830-mtp.dtb \ - sdm830-cdp.dtb +endif always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/qcom/apq8053-cdp.dts b/arch/arm64/boot/dts/qcom/apq8053-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..57401d838b02ecbdbcfec36748e1b41ec16cbe75 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-cdp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "apq8053.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 CDP"; + compatible = "qcom,apq8053-cdp", "qcom,apq8053", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/apq8053-ext-audio-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-ext-audio-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..2d5e761a403f8d4fc706a5b7b847cea0d5147da0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-ext-audio-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "apq8053.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 Ext Codec MTP"; + compatible = "qcom,apq8053-mtp", "qcom,apq8053", "qcom,mtp"; + qcom,board-id= <8 1>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/apq8053-ext-codec-rcm.dts b/arch/arm64/boot/dts/qcom/apq8053-ext-codec-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..96e1d53069e87b71d0bb79c8150351ce0f820ab8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-ext-codec-rcm.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "apq8053.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 Ext Codec RCM"; + compatible = "qcom,apq8053-cdp", "qcom,apq8053", "qcom,cdp"; + qcom,board-id= <21 1>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..44b479224d57c03127387b48e7d0b121bba66854 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "apq8053.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 IOT MTP"; + compatible = "qcom,apq8053-mtp", "qcom,apq8053", "qcom,mtp"; + qcom,board-id= <8 2>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/apq8053-ipc.dts b/arch/arm64/boot/dts/qcom/apq8053-ipc.dts new file mode 100644 index 0000000000000000000000000000000000000000..3381b2a29cdd447b32a63512206fe661914e432a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-ipc.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016-2017, 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 "apq8053.dtsi" +#include "msm8953-ipc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 IPC"; + compatible = "qcom,apq8053-ipc", "qcom,apq8053", "qcom,ipc"; + qcom,board-id= <12 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..89b76246499e0f8090c12e789bc944248f4c1f18 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "apq8053.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 MTP"; + compatible = "qcom,apq8053-mtp", "qcom,apq8053", "qcom,mtp"; + qcom,board-id= <8 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/apq8053-rcm.dts b/arch/arm64/boot/dts/qcom/apq8053-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..d70b99f238ae05605bab8776b927ad831f80dd8c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-rcm.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016-2018, 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 "apq8053.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 RCM"; + compatible = "qcom,apq8053-cdp", "qcom,apq8053", "qcom,cdp"; + qcom,board-id= <21 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm830-sim.dtsi b/arch/arm64/boot/dts/qcom/apq8053.dts similarity index 63% rename from arch/arm64/boot/dts/qcom/sdm830-sim.dtsi rename to arch/arm64/boot/dts/qcom/apq8053.dts index 85e8075aceab8312a18626b4616e6bde1691abb5..bf9e2f2c9efe7c7929bc473559fa787f9119d37f 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-sim.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,11 +11,13 @@ * GNU General Public License for more details. */ -/* - * As a general rule, only version-specific property overrides should be placed - * inside this file. Common device definitions should be placed inside the - * sdm845-sim.dtsi file. - */ +/dts-v1/; - #include "sdm845-sim.dtsi" +#include "apq8053.dtsi" +/ { + model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC"; + compatible = "qcom,apq8053"; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; + qcom,pmic-name = "PMI8950"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053.dtsi b/arch/arm64/boot/dts/qcom/apq8053.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4600dc1fec9a4c2d1f70072ce10903952e2020da --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053.dtsi @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +/ { + model = "Qualcomm Technologies, Inc. APQ8053"; + compatible = "qcom,apq8053"; + qcom,msm-id = <304 0x0>; + qcom,msm-name = "APQ8053"; +}; + +&secure_mem { + status = "disabled"; +}; + diff --git a/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi b/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3eed42aca5bf7c67df97ad0e1136aa77e851645a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,ascent-3450mah { + /* #Ascent_860_82209_0000_3450mAh_averaged_MasterSlave_Sept28th2015*/ + qcom,max-voltage-uv = <4350000>; + qcom,nom-batt-capacity-mah = <3450>; + qcom,batt-id-kohm = <60>; + qcom,battery-beta = <3435>; + qcom,battery-type = "ascent_3450mah"; + qcom,chg-rslow-comp-c1 = <6834679>; + qcom,chg-rslow-comp-c2 = <20647220>; + qcom,chg-rs-to-rslow = <915002>; + qcom,chg-rslow-comp-thr = <0xD5>; + qcom,checksum = <0xE50C>; + qcom,fg-profile-data = [ + C5 83 25 77 + AB 7B CA 74 + 4C 83 7F 5B + EB 80 ED 8C + EA 81 61 9B + A6 BE 2B D0 + 55 0E D6 83 + 09 77 25 7B + 03 74 49 83 + CC 70 0C 70 + 0C 85 67 82 + E6 93 27 B5 + 61 C0 58 10 + 23 0D 50 59 + CE 6E 71 FD + CD 15 CC 3F + 1D 36 00 00 + B9 47 29 3B + 1D 2E 00 00 + 00 00 00 00 + 00 00 00 00 + D8 6A E7 69 + B3 7C 4E 7A + 7E 77 77 70 + 40 77 0D 73 + 22 76 96 6A + 71 65 20 B0 + 2C 97 63 12 + 64 A0 71 0C + 28 00 FF 36 + F0 11 30 03 + 00 00 00 0C + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..24b46262718999de10891736216cc4e332f40250 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi @@ -0,0 +1,61 @@ +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,itech-3000mah { + /* #Itech_B00826LF_3000mAh_Feb24th_Averaged*/ + qcom,max-voltage-uv = <4350000>; + qcom,v-cutoff-uv = <3400000>; + qcom,chg-term-ua = <100000>; + qcom,batt-id-kohm = <100>; + qcom,battery-type = "itech_3000mah"; + qcom,chg-rslow-comp-c1 = <4365000>; + qcom,chg-rslow-comp-c2 = <8609000>; + qcom,chg-rslow-comp-thr = <0xBE>; + qcom,chg-rs-to-rslow = <761000>; + qcom,fastchg-current-ma = <2000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,checksum = <0x0B7C>; + qcom,fg-profile-data = [ + F0 83 6B 7D + 66 81 EC 77 + 43 83 E3 5A + 7C 81 33 8D + E1 81 EC 98 + 7B B5 F8 BB + 5B 12 E2 83 + 4A 7C 63 80 + CF 75 50 83 + FD 5A 83 82 + E6 8E 12 82 + B6 9A 1A BE + BE CB 55 0E + 96 0B E0 5A + CE 6E 71 FD + 2A 31 7E 47 + CF 40 00 00 + DB 45 0F 32 + AF 31 00 00 + 00 00 00 00 + 00 00 00 00 + E3 6A 60 69 + 9E 6D 47 83 + 13 7C 23 70 + 0B 74 8F 80 + DB 75 17 68 + BA 75 BF B3 + 21 5B 69 B5 + 6C A0 71 0C + 28 00 FF 36 + F0 11 30 03 + 00 00 00 0E + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..da520398cbaa075963deb6b2f4190197cee802d7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi @@ -0,0 +1,62 @@ +/* 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. + */ + +qcom,qrd_msm8937_sku1_2920mah { + /* #QRD8937_2800mAh_China_data_averaged_MasterSlave_Oct30th2015*/ + qcom,max-voltage-uv = <4400000>; + qcom,nom-batt-capacity-mah = <2800>; + qcom,batt-id-kohm = <90>; + qcom,battery-beta = <3380>; + qcom,battery-type = "qrd_msm8937_sku1_2800mah"; + qcom,fastchg-current-ma = <2600>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,chg-rslow-comp-c1 = <6733839>; + qcom,chg-rslow-comp-c2 = <23336040>; + qcom,chg-rs-to-rslow = <1049243>; + qcom,chg-rslow-comp-thr = <0xDB>; + qcom,checksum = <0x7E2A>; + qcom,gui-version = "PMI8950GUI - 2.0.0.14"; + qcom,fg-profile-data = [ + C6 83 8A 77 + 3E 80 84 75 + 72 83 A1 7C + A0 90 FC 97 + 3F 82 09 99 + 92 B7 97 C3 + 4C 14 EB 83 + A7 7C CE 80 + 79 76 60 83 + 3B 64 34 88 + 19 94 49 82 + 07 9A 7F BD + BF CA 53 0D + 32 0B 68 59 + 14 70 71 FD + 8C 28 9C 45 + 3F 21 00 00 + B6 47 FE 30 + 0B 40 00 00 + 00 00 00 00 + 00 00 00 00 + 3A 70 78 6B + F7 77 7F 88 + 32 7C F2 70 + 64 75 0B 79 + 2B 77 F3 6B + CA 70 7D B1 + 21 57 6B 6B + 6D A0 71 0C + 28 00 FF 36 + F0 11 30 03 + 00 00 00 0C + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3af01c1f7806dc536412329ce9cf74cd4fd847e0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi @@ -0,0 +1,114 @@ +/* Copyright (c) 2018, 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. + */ + +&mdss_mdp { + dsi_hx8399_truly_cmd: qcom,mdss_dsi_hx8399_truly_cmd { + qcom,mdss-dsi-panel-name = + "hx8399 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-pre = <0x30>; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <24>; + qcom,mdss-dsi-h-back-porch = <24>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <40>; + qcom,mdss-dsi-v-front-porch = <36>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 FF 83 99 + 39 01 00 00 00 00 02 D2 88 + 39 01 00 00 00 00 10 B1 02 04 74 94 01 + 32 33 11 11 E6 5D 56 73 02 02 + 39 01 00 00 00 00 10 B2 00 80 80 CC 05 + 07 5A 11 10 10 00 1E 70 03 D4 + 39 01 00 00 00 00 2D B4 00 FF 59 59 0C + AC 00 00 0C 00 07 0A 00 28 07 08 0C + 21 03 00 00 00 AE 87 59 59 0C AC 00 + 00 0C 00 07 0A 00 28 07 08 0C 01 00 + 00 AE 01 + 39 01 00 00 05 00 22 D3 00 00 01 01 00 + 00 10 10 00 00 03 00 03 00 08 78 08 + 78 00 00 00 00 00 24 02 05 05 03 00 + 00 00 05 40 + 39 01 00 00 05 00 21 D5 20 20 19 19 18 + 18 02 03 00 01 24 24 18 18 18 18 24 + 24 00 00 00 00 00 00 00 00 2F 2F 30 + 30 31 31 + 39 01 00 00 05 00 21 D6 24 24 18 18 19 + 19 01 00 03 02 24 24 18 18 18 18 20 + 20 40 40 40 40 40 40 40 40 2F 2F 30 + 30 31 31 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 11 D8 AA AA AA AA AA + AA AA AA AA BA AA AA AA BA AA AA + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 11 D8 82 EA AA AA 82 + EA AA AA 82 EA AA AA 82 EA AA AA + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 09 D8 FF FF C0 3F FF + FF C0 3F + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 05 00 37 E0 08 2A 39 35 74 + 7C 87 7F 84 8A 8E 91 93 96 9B 9C 9E + A5 A6 AE A1 AF B2 5C 58 63 74 08 2A + 39 35 74 7C 87 7F 84 8A 8E 91 93 96 + 9B 9C 9E A5 A6 AE A1 AF B2 5C 58 63 + 74 + 39 01 00 00 00 00 03 B6 7E 7E + 39 01 00 00 00 00 02 CC 08 + 39 01 00 00 00 00 06 C7 00 08 00 01 08 + 39 01 00 00 00 00 03 C0 25 5A + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 14 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..78f933ad23c291be09a8634fba94e46f31209f00 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,112 @@ +/* Copyright (c) 2015-2017, 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. + */ + +&mdss_mdp { + dsi_dual_nt35597_cmd: qcom,mdss_dsi_nt35597_wqxga_cmd{ + qcom,mdss-dsi-panel-name = + "Dual nt35597 cmd mode dsi panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,ulps-enabled; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 10 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 ba 03 + 15 01 00 00 10 00 02 e5 01 + 15 01 00 00 10 00 02 35 00 + 15 01 00 00 10 00 02 bb 10 + 15 01 00 00 10 00 02 b0 03 + 15 01 00 00 10 00 02 ff e0 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 6b 3d + 15 01 00 00 10 00 02 6c 3d + 15 01 00 00 10 00 02 6d 3d + 15 01 00 00 10 00 02 6e 3d + 15 01 00 00 10 00 02 6f 3d + 15 01 00 00 10 00 02 35 02 + 15 01 00 00 10 00 02 36 72 + 15 01 00 00 10 00 02 37 10 + 15 01 00 00 10 00 02 08 c0 + 15 01 00 00 10 00 02 ff 24 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 c6 06 + 15 01 00 00 10 00 02 ff 10 + 05 01 00 00 a0 00 02 11 00 + 05 01 00 00 a0 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 + 02 28 00 05 01 00 00 3c 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 + 64 26 34 29 03 04 00]; + + qcom,config-select = + <&dsi_dual_nt35597_cmd_config0>; + + dsi_dual_nt35597_cmd_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + dsi_dual_nt35597_cmd_config1: config1 { + qcom,split-mode = "pingpong-split"; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9cd5815e7529799e79dc5cb6c0dfe93471dc816b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -0,0 +1,111 @@ +/* Copyright (c) 2015-2017, 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. + */ + +&mdss_mdp { + dsi_dual_nt35597_video: qcom,mdss_dsi_nt35597_wqxga_video { + qcom,mdss-dsi-panel-name = + "Dual nt35597 video mode dsi panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0x3ff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 ba 03 + 15 01 00 00 00 00 02 e5 01 + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 bb 03 + 15 01 00 00 00 00 02 b0 03 + 39 01 00 00 00 00 06 3b 03 + 08 08 64 9a + 15 01 00 00 00 00 02 ff e0 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 6b 3d + 15 01 00 00 00 00 02 6c 3d + 15 01 00 00 00 00 02 6d 3d + 15 01 00 00 00 00 02 6e 3d + 15 01 00 00 00 00 02 6f 3d + 15 01 00 00 00 00 02 35 02 + 15 01 00 00 00 00 02 36 72 + 15 01 00 00 00 00 02 37 10 + 15 01 00 00 00 00 02 08 c0 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 0a 00 02 28 00 05 01 00 00 3c 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 + 6a 28 38 2a 03 04 00]; + + qcom,config-select = + <&dsi_dual_nt35597_video_config0>; + + dsi_dual_nt35597_video_config0: + config0 { + qcom,split-mode = + "dualctl-split"; + }; + + dsi_dual_nt35597_video_config1: + config1 { + qcom,split-mode = + "pingpong-split"; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi index c6dfc8da69b515563195f7d3de2f30bfc2e219cb..0e60a0c1f22e1f18eb045f15c26b3431c5051dd7 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi @@ -15,191 +15,19 @@ qcom,mdss-dsi-panel-name = "nt35597 cmd mode dsi truly panel with DSC"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1440>; - qcom,mdss-dsi-panel-height = <2560>; - qcom,mdss-dsi-h-front-porch = <100>; - qcom,mdss-dsi-h-back-porch = <32>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <8>; - qcom,mdss-dsi-v-front-porch = <10>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - /* CMD2_P0 */ - 15 01 00 00 00 00 02 ff 20 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 01 - 15 01 00 00 00 00 02 01 55 - 15 01 00 00 00 00 02 02 45 - 15 01 00 00 00 00 02 05 40 - 15 01 00 00 00 00 02 06 19 - 15 01 00 00 00 00 02 07 1e - 15 01 00 00 00 00 02 0b 73 - 15 01 00 00 00 00 02 0c 73 - 15 01 00 00 00 00 02 0e b0 - 15 01 00 00 00 00 02 0f ae - 15 01 00 00 00 00 02 11 b8 - 15 01 00 00 00 00 02 13 00 - 15 01 00 00 00 00 02 58 80 - 15 01 00 00 00 00 02 59 01 - 15 01 00 00 00 00 02 5a 00 - 15 01 00 00 00 00 02 5b 01 - 15 01 00 00 00 00 02 5c 80 - 15 01 00 00 00 00 02 5d 81 - 15 01 00 00 00 00 02 5e 00 - 15 01 00 00 00 00 02 5f 01 - 15 01 00 00 00 00 02 72 31 - 15 01 00 00 00 00 02 68 03 - /* CMD2_P4 */ - 15 01 00 00 00 00 02 ff 24 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 1c - 15 01 00 00 00 00 02 01 0b - 15 01 00 00 00 00 02 02 0c - 15 01 00 00 00 00 02 03 01 - 15 01 00 00 00 00 02 04 0f - 15 01 00 00 00 00 02 05 10 - 15 01 00 00 00 00 02 06 10 - 15 01 00 00 00 00 02 07 10 - 15 01 00 00 00 00 02 08 89 - 15 01 00 00 00 00 02 09 8a - 15 01 00 00 00 00 02 0a 13 - 15 01 00 00 00 00 02 0b 13 - 15 01 00 00 00 00 02 0c 15 - 15 01 00 00 00 00 02 0d 15 - 15 01 00 00 00 00 02 0e 17 - 15 01 00 00 00 00 02 0f 17 - 15 01 00 00 00 00 02 10 1c - 15 01 00 00 00 00 02 11 0b - 15 01 00 00 00 00 02 12 0c - 15 01 00 00 00 00 02 13 01 - 15 01 00 00 00 00 02 14 0f - 15 01 00 00 00 00 02 15 10 - 15 01 00 00 00 00 02 16 10 - 15 01 00 00 00 00 02 17 10 - 15 01 00 00 00 00 02 18 89 - 15 01 00 00 00 00 02 19 8a - 15 01 00 00 00 00 02 1a 13 - 15 01 00 00 00 00 02 1b 13 - 15 01 00 00 00 00 02 1c 15 - 15 01 00 00 00 00 02 1d 15 - 15 01 00 00 00 00 02 1e 17 - 15 01 00 00 00 00 02 1f 17 - /* STV */ - 15 01 00 00 00 00 02 20 40 - 15 01 00 00 00 00 02 21 01 - 15 01 00 00 00 00 02 22 00 - 15 01 00 00 00 00 02 23 40 - 15 01 00 00 00 00 02 24 40 - 15 01 00 00 00 00 02 25 6d - 15 01 00 00 00 00 02 26 40 - 15 01 00 00 00 00 02 27 40 - /* Vend */ - 15 01 00 00 00 00 02 e0 00 - 15 01 00 00 00 00 02 dc 21 - 15 01 00 00 00 00 02 dd 22 - 15 01 00 00 00 00 02 de 07 - 15 01 00 00 00 00 02 df 07 - 15 01 00 00 00 00 02 e3 6D - 15 01 00 00 00 00 02 e1 07 - 15 01 00 00 00 00 02 e2 07 - /* UD */ - 15 01 00 00 00 00 02 29 d8 - 15 01 00 00 00 00 02 2a 2a - /* CLK */ - 15 01 00 00 00 00 02 4b 03 - 15 01 00 00 00 00 02 4c 11 - 15 01 00 00 00 00 02 4d 10 - 15 01 00 00 00 00 02 4e 01 - 15 01 00 00 00 00 02 4f 01 - 15 01 00 00 00 00 02 50 10 - 15 01 00 00 00 00 02 51 00 - 15 01 00 00 00 00 02 52 80 - 15 01 00 00 00 00 02 53 00 - 15 01 00 00 00 00 02 56 00 - 15 01 00 00 00 00 02 54 07 - 15 01 00 00 00 00 02 58 07 - 15 01 00 00 00 00 02 55 25 - /* Reset XDONB */ - 15 01 00 00 00 00 02 5b 43 - 15 01 00 00 00 00 02 5c 00 - 15 01 00 00 00 00 02 5f 73 - 15 01 00 00 00 00 02 60 73 - 15 01 00 00 00 00 02 63 22 - 15 01 00 00 00 00 02 64 00 - 15 01 00 00 00 00 02 67 08 - 15 01 00 00 00 00 02 68 04 - /* Resolution:1440x2560*/ - 15 01 00 00 00 00 02 72 02 - /* mux */ - 15 01 00 00 00 00 02 7a 80 - 15 01 00 00 00 00 02 7b 91 - 15 01 00 00 00 00 02 7c D8 - 15 01 00 00 00 00 02 7d 60 - 15 01 00 00 00 00 02 7f 15 - 15 01 00 00 00 00 02 75 15 - /* ABOFF */ - 15 01 00 00 00 00 02 b3 C0 - 15 01 00 00 00 00 02 b4 00 - 15 01 00 00 00 00 02 b5 00 - /* Source EQ */ - 15 01 00 00 00 00 02 78 00 - 15 01 00 00 00 00 02 79 00 - 15 01 00 00 00 00 02 80 00 - 15 01 00 00 00 00 02 83 00 - /* FP BP */ - 15 01 00 00 00 00 02 93 0a - 15 01 00 00 00 00 02 94 0a - /* Inversion Type */ - 15 01 00 00 00 00 02 8a 00 - 15 01 00 00 00 00 02 9b ff - /* IMGSWAP =1 @PortSwap=1 */ - 15 01 00 00 00 00 02 9d b0 - 15 01 00 00 00 00 02 9f 63 - 15 01 00 00 00 00 02 98 10 - /* FRM */ - 15 01 00 00 00 00 02 ec 00 - /* CMD1 */ - 15 01 00 00 00 00 02 ff 10 - /* VESA DSC PPS settings(1440x2560 slide 16H) */ - 39 01 00 00 00 00 11 c1 09 20 00 10 02 00 02 68 - 01 bb 00 0a 06 67 04 c5 - 39 01 00 00 00 00 03 c2 10 f0 - /* C0h = 0x0(2 Port SDC)0x01(1 PortA FBC) - * 0x02(MTK) 0x03(1 PortA VESA) - */ - 15 01 00 00 00 00 02 c0 03 - /* VBP+VSA=,VFP = 10H */ - 15 01 00 00 00 00 04 3b 03 0a 0a - /* FTE on */ - 15 01 00 00 00 00 02 35 00 - /* EN_BK =1(auto black) */ - 15 01 00 00 00 00 02 e5 01 - /* CMD mode(10) VDO mode(03) */ - 15 01 00 00 00 00 02 bb 10 - /* Non Reload MTP */ - 15 01 00 00 00 00 02 fb 01 - /* SlpOut + DispOn */ - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 78 00 02 29 00 - ]; - qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - - qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -210,7 +38,6 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; - qcom,mdss-dsi-bl-max-level = <4095>; qcom,adjust-timer-wakeup-ms = <1>; qcom,mdss-dsi-te-pin-select = <1>; @@ -220,42 +47,201 @@ qcom,mdss-dsi-te-check-enable; qcom,mdss-dsi-te-using-te-pin; - qcom,compression-mode = "dsc"; - qcom,config-select = <&dsi_nt35597_truly_dsc_cmd_config0>; - - dsi_nt35597_truly_dsc_cmd_config0: config0 { - qcom,mdss-dsc-encoders = <1>; - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <720>; - qcom,mdss-dsc-slice-per-pkt = <2>; - - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - }; - - dsi_nt35597_truly_dsc_cmd_config1: config1 { - qcom,lm-split = <720 720>; - qcom,mdss-dsc-encoders = <1>; /* 3D Mux */ - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <720>; - qcom,mdss-dsc-slice-per-pkt = <2>; - - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - }; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x1 0x1>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f ae + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6D + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c D8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 C0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 - dsi_nt35597_truly_dsc_cmd_config2: config2 { - qcom,lm-split = <720 720>; - qcom,mdss-dsc-encoders = <2>; /* DSC Merge */ - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <720>; - qcom,mdss-dsc-slice-per-pkt = <2>; + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi index 334120ac98ccad9bb04e045b96f3f5ab4a9e5ae1..2c54504dc8cdbb761119c899ffc17258454743fc 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -15,185 +15,16 @@ qcom,mdss-dsi-panel-name = "nt35597 video mode dsi truly panel with DSC"; qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1440>; - qcom,mdss-dsi-panel-height = <2560>; - qcom,mdss-dsi-h-front-porch = <100>; - qcom,mdss-dsi-h-back-porch = <32>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <8>; - qcom,mdss-dsi-v-front-porch = <10>; - qcom,mdss-dsi-v-pulse-width = <2>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - /* CMD2_P0 */ - 15 01 00 00 00 00 02 ff 20 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 01 - 15 01 00 00 00 00 02 01 55 - 15 01 00 00 00 00 02 02 45 - 15 01 00 00 00 00 02 05 40 - 15 01 00 00 00 00 02 06 19 - 15 01 00 00 00 00 02 07 1e - 15 01 00 00 00 00 02 0b 73 - 15 01 00 00 00 00 02 0c 73 - 15 01 00 00 00 00 02 0e b0 - 15 01 00 00 00 00 02 0f aE - 15 01 00 00 00 00 02 11 b8 - 15 01 00 00 00 00 02 13 00 - 15 01 00 00 00 00 02 58 80 - 15 01 00 00 00 00 02 59 01 - 15 01 00 00 00 00 02 5a 00 - 15 01 00 00 00 00 02 5b 01 - 15 01 00 00 00 00 02 5c 80 - 15 01 00 00 00 00 02 5d 81 - 15 01 00 00 00 00 02 5e 00 - 15 01 00 00 00 00 02 5f 01 - 15 01 00 00 00 00 02 72 31 - 15 01 00 00 00 00 02 68 03 - /* CMD2_P4 */ - 15 01 00 00 00 00 02 ff 24 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 1c - 15 01 00 00 00 00 02 01 0b - 15 01 00 00 00 00 02 02 0c - 15 01 00 00 00 00 02 03 01 - 15 01 00 00 00 00 02 04 0f - 15 01 00 00 00 00 02 05 10 - 15 01 00 00 00 00 02 06 10 - 15 01 00 00 00 00 02 07 10 - 15 01 00 00 00 00 02 08 89 - 15 01 00 00 00 00 02 09 8a - 15 01 00 00 00 00 02 0a 13 - 15 01 00 00 00 00 02 0b 13 - 15 01 00 00 00 00 02 0c 15 - 15 01 00 00 00 00 02 0d 15 - 15 01 00 00 00 00 02 0e 17 - 15 01 00 00 00 00 02 0f 17 - 15 01 00 00 00 00 02 10 1c - 15 01 00 00 00 00 02 11 0b - 15 01 00 00 00 00 02 12 0c - 15 01 00 00 00 00 02 13 01 - 15 01 00 00 00 00 02 14 0f - 15 01 00 00 00 00 02 15 10 - 15 01 00 00 00 00 02 16 10 - 15 01 00 00 00 00 02 17 10 - 15 01 00 00 00 00 02 18 89 - 15 01 00 00 00 00 02 19 8a - 15 01 00 00 00 00 02 1a 13 - 15 01 00 00 00 00 02 1b 13 - 15 01 00 00 00 00 02 1c 15 - 15 01 00 00 00 00 02 1d 15 - 15 01 00 00 00 00 02 1e 17 - 15 01 00 00 00 00 02 1f 17 - /* STV */ - 15 01 00 00 00 00 02 20 40 - 15 01 00 00 00 00 02 21 01 - 15 01 00 00 00 00 02 22 00 - 15 01 00 00 00 00 02 23 40 - 15 01 00 00 00 00 02 24 40 - 15 01 00 00 00 00 02 25 6d - 15 01 00 00 00 00 02 26 40 - 15 01 00 00 00 00 02 27 40 - /* Vend */ - 15 01 00 00 00 00 02 e0 00 - 15 01 00 00 00 00 02 dc 21 - 15 01 00 00 00 00 02 dd 22 - 15 01 00 00 00 00 02 de 07 - 15 01 00 00 00 00 02 df 07 - 15 01 00 00 00 00 02 e3 6d - 15 01 00 00 00 00 02 e1 07 - 15 01 00 00 00 00 02 e2 07 - /* UD */ - 15 01 00 00 00 00 02 29 d8 - 15 01 00 00 00 00 02 2a 2a - /* CLK */ - 15 01 00 00 00 00 02 4b 03 - 15 01 00 00 00 00 02 4c 11 - 15 01 00 00 00 00 02 4d 10 - 15 01 00 00 00 00 02 4e 01 - 15 01 00 00 00 00 02 4f 01 - 15 01 00 00 00 00 02 50 10 - 15 01 00 00 00 00 02 51 00 - 15 01 00 00 00 00 02 52 80 - 15 01 00 00 00 00 02 53 00 - 15 01 00 00 00 00 02 56 00 - 15 01 00 00 00 00 02 54 07 - 15 01 00 00 00 00 02 58 07 - 15 01 00 00 00 00 02 55 25 - /* Reset XDONB */ - 15 01 00 00 00 00 02 5b 43 - 15 01 00 00 00 00 02 5c 00 - 15 01 00 00 00 00 02 5f 73 - 15 01 00 00 00 00 02 60 73 - 15 01 00 00 00 00 02 63 22 - 15 01 00 00 00 00 02 64 00 - 15 01 00 00 00 00 02 67 08 - 15 01 00 00 00 00 02 68 04 - /* Resolution:1440x2560*/ - 15 01 00 00 00 00 02 72 02 - /* mux */ - 15 01 00 00 00 00 02 7a 80 - 15 01 00 00 00 00 02 7b 91 - 15 01 00 00 00 00 02 7c d8 - 15 01 00 00 00 00 02 7d 60 - 15 01 00 00 00 00 02 7f 15 - 15 01 00 00 00 00 02 75 15 - /* ABOFF */ - 15 01 00 00 00 00 02 b3 c0 - 15 01 00 00 00 00 02 b4 00 - 15 01 00 00 00 00 02 b5 00 - /* Source EQ */ - 15 01 00 00 00 00 02 78 00 - 15 01 00 00 00 00 02 79 00 - 15 01 00 00 00 00 02 80 00 - 15 01 00 00 00 00 02 83 00 - /* FP BP */ - 15 01 00 00 00 00 02 93 0a - 15 01 00 00 00 00 02 94 0a - /* Inversion Type */ - 15 01 00 00 00 00 02 8a 00 - 15 01 00 00 00 00 02 9b ff - /* IMGSWAP =1 @PortSwap=1 */ - 15 01 00 00 00 00 02 9d b0 - 15 01 00 00 00 00 02 9f 63 - 15 01 00 00 00 00 02 98 10 - /* FRM */ - 15 01 00 00 00 00 02 ec 00 - /* CMD1 */ - 15 01 00 00 00 00 02 ff 10 - /* VESA DSC PPS settings(1440x2560 slide 16H) */ - 39 01 00 00 00 00 11 c1 09 20 00 10 02 00 02 68 01 - bb 00 0a 06 67 04 c5 - 39 01 00 00 00 00 03 c2 10 f0 - /* C0h = 0x00(2 Port SDC); 0x01(1 PortA FBC); - * 0x02(MTK); 0x03(1 PortA VESA) - */ - 15 01 00 00 00 00 02 c0 03 - /* VBP+VSA=,VFP = 10H */ - 39 01 00 00 00 00 04 3b 03 0a 0a - /* FTE on */ - 15 01 00 00 00 00 02 35 00 - /* EN_BK =1(auto black) */ - 15 01 00 00 00 00 02 e5 01 - /* CMD mode(10) VDO mode(03) */ - 15 01 00 00 00 00 02 bb 03 - /* Non Reload MTP */ - 15 01 00 00 00 00 02 fb 01 - /* SlpOut + DispOn */ - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 78 00 02 29 00 - ]; - qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -207,42 +38,195 @@ qcom,mdss-pan-physical-width-dimension = <74>; qcom,mdss-pan-physical-height-dimension = <131>; - qcom,compression-mode = "dsc"; - qcom,config-select = <&dsi_nt35597_truly_dsc_video_config0>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 - dsi_nt35597_truly_dsc_video_config0: config0 { - qcom,mdss-dsc-encoders = <1>; - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <720>; - qcom,mdss-dsc-slice-per-pkt = <2>; - - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - }; - - dsi_nt35597_truly_dsc_video_config1: config1 { - qcom,lm-split = <720 720>; - qcom,mdss-dsc-encoders = <1>; /* 3D Mux */ - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <720>; - qcom,mdss-dsc-slice-per-pkt = <2>; - - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; - }; - - dsi_nt35597_truly_dsc_video_config2: config2 { - qcom,lm-split = <720 720>; - qcom,mdss-dsc-encoders = <2>; /* DSC Merge */ - qcom,mdss-dsc-slice-height = <16>; - qcom,mdss-dsc-slice-width = <720>; - qcom,mdss-dsc-slice-per-pkt = <2>; - - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x00(2 Port SDC); + * 0x01(1 PortA FBC); + * 0x02(MTK); 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 39 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 03 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi index e4a037082fe36466681eb6c2f17955ddbdb972a2..1a8ce910fc2adee4fad59ee4448411d0a281139d 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -15,27 +15,12 @@ qcom,mdss-dsi-panel-name = "Dual nt35597 cmd mode dsi truly panel without DSC"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <2560>; - qcom,mdss-dsi-h-front-porch = <100>; - qcom,mdss-dsi-h-back-porch = <32>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <7>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <1>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -45,6 +30,8 @@ qcom,mdss-dsi-lane-3-state; qcom,adjust-timer-wakeup-ms = <1>; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; @@ -54,167 +41,191 @@ qcom,mdss-dsi-te-dcs-command = <1>; qcom,mdss-dsi-te-check-enable; qcom,mdss-dsi-te-using-te-pin; - qcom,mdss-dsi-on-command = [ - /* CMD2_P0 */ - 15 01 00 00 00 00 02 FF 20 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 01 - 15 01 00 00 00 00 02 01 55 - 15 01 00 00 00 00 02 02 45 - 15 01 00 00 00 00 02 05 40 - 15 01 00 00 00 00 02 06 19 - 15 01 00 00 00 00 02 07 1E - 15 01 00 00 00 00 02 0B 73 - 15 01 00 00 00 00 02 0C 73 - 15 01 00 00 00 00 02 0E B0 - 15 01 00 00 00 00 02 0F AE - 15 01 00 00 00 00 02 11 B8 - 15 01 00 00 00 00 02 13 00 - 15 01 00 00 00 00 02 58 80 - 15 01 00 00 00 00 02 59 01 - 15 01 00 00 00 00 02 5A 00 - 15 01 00 00 00 00 02 5B 01 - 15 01 00 00 00 00 02 5C 80 - 15 01 00 00 00 00 02 5D 81 - 15 01 00 00 00 00 02 5E 00 - 15 01 00 00 00 00 02 5F 01 - 15 01 00 00 00 00 02 72 31 - 15 01 00 00 00 00 02 68 03 - /* CMD2_P4 */ - 15 01 00 00 00 00 02 ff 24 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 1C - 15 01 00 00 00 00 02 01 0B - 15 01 00 00 00 00 02 02 0C - 15 01 00 00 00 00 02 03 01 - 15 01 00 00 00 00 02 04 0F - 15 01 00 00 00 00 02 05 10 - 15 01 00 00 00 00 02 06 10 - 15 01 00 00 00 00 02 07 10 - 15 01 00 00 00 00 02 08 89 - 15 01 00 00 00 00 02 09 8A - 15 01 00 00 00 00 02 0A 13 - 15 01 00 00 00 00 02 0B 13 - 15 01 00 00 00 00 02 0C 15 - 15 01 00 00 00 00 02 0D 15 - 15 01 00 00 00 00 02 0E 17 - 15 01 00 00 00 00 02 0F 17 - 15 01 00 00 00 00 02 10 1C - 15 01 00 00 00 00 02 11 0B - 15 01 00 00 00 00 02 12 0C - 15 01 00 00 00 00 02 13 01 - 15 01 00 00 00 00 02 14 0F - 15 01 00 00 00 00 02 15 10 - 15 01 00 00 00 00 02 16 10 - 15 01 00 00 00 00 02 17 10 - 15 01 00 00 00 00 02 18 89 - 15 01 00 00 00 00 02 19 8A - 15 01 00 00 00 00 02 1A 13 - 15 01 00 00 00 00 02 1B 13 - 15 01 00 00 00 00 02 1C 15 - 15 01 00 00 00 00 02 1D 15 - 15 01 00 00 00 00 02 1E 17 - 15 01 00 00 00 00 02 1F 17 - /* STV */ - 15 01 00 00 00 00 02 20 40 - 15 01 00 00 00 00 02 21 01 - 15 01 00 00 00 00 02 22 00 - 15 01 00 00 00 00 02 23 40 - 15 01 00 00 00 00 02 24 40 - 15 01 00 00 00 00 02 25 6D - 15 01 00 00 00 00 02 26 40 - 15 01 00 00 00 00 02 27 40 - /* Vend */ - 15 01 00 00 00 00 02 E0 00 - 15 01 00 00 00 00 02 DC 21 - 15 01 00 00 00 00 02 DD 22 - 15 01 00 00 00 00 02 DE 07 - 15 01 00 00 00 00 02 DF 07 - 15 01 00 00 00 00 02 E3 6D - 15 01 00 00 00 00 02 E1 07 - 15 01 00 00 00 00 02 E2 07 - /* UD */ - 15 01 00 00 00 00 02 29 D8 - 15 01 00 00 00 00 02 2A 2A - /* CLK */ - 15 01 00 00 00 00 02 4B 03 - 15 01 00 00 00 00 02 4C 11 - 15 01 00 00 00 00 02 4D 10 - 15 01 00 00 00 00 02 4E 01 - 15 01 00 00 00 00 02 4F 01 - 15 01 00 00 00 00 02 50 10 - 15 01 00 00 00 00 02 51 00 - 15 01 00 00 00 00 02 52 80 - 15 01 00 00 00 00 02 53 00 - 15 01 00 00 00 00 02 56 00 - 15 01 00 00 00 00 02 54 07 - 15 01 00 00 00 00 02 58 07 - 15 01 00 00 00 00 02 55 25 - /* Reset XDONB */ - 15 01 00 00 00 00 02 5B 43 - 15 01 00 00 00 00 02 5C 00 - 15 01 00 00 00 00 02 5F 73 - 15 01 00 00 00 00 02 60 73 - 15 01 00 00 00 00 02 63 22 - 15 01 00 00 00 00 02 64 00 - 15 01 00 00 00 00 02 67 08 - 15 01 00 00 00 00 02 68 04 - /* Resolution:1440x2560*/ - 15 01 00 00 00 00 02 72 02 - /* mux */ - 15 01 00 00 00 00 02 7A 80 - 15 01 00 00 00 00 02 7B 91 - 15 01 00 00 00 00 02 7C D8 - 15 01 00 00 00 00 02 7D 60 - 15 01 00 00 00 00 02 7F 15 - 15 01 00 00 00 00 02 75 15 - /* ABOFF */ - 15 01 00 00 00 00 02 B3 C0 - 15 01 00 00 00 00 02 B4 00 - 15 01 00 00 00 00 02 B5 00 - /* Source EQ */ - 15 01 00 00 00 00 02 78 00 - 15 01 00 00 00 00 02 79 00 - 15 01 00 00 00 00 02 80 00 - 15 01 00 00 00 00 02 83 00 - /* FP BP */ - 15 01 00 00 00 00 02 93 0A - 15 01 00 00 00 00 02 94 0A - /* Inversion Type */ - 15 01 00 00 00 00 02 8A 00 - 15 01 00 00 00 00 02 9B FF - /* IMGSWAP =1 @PortSwap=1 */ - 15 01 00 00 00 00 02 9D B0 - 15 01 00 00 00 00 02 9F 63 - 15 01 00 00 00 00 02 98 10 - /* FRM */ - 15 01 00 00 00 00 02 EC 00 - /* CMD1 */ - 15 01 00 00 00 00 02 ff 10 - /* VBP+VSA=,VFP = 10H */ - 15 01 00 00 00 00 04 3B 03 0A 0A - /* FTE on */ - 15 01 00 00 00 00 02 35 00 - /* EN_BK =1(auto black) */ - 15 01 00 00 00 00 02 E5 01 - /* CMD mode(10) VDO mode(03) */ - 15 01 00 00 00 00 02 BB 10 - /* Non Reload MTP */ - 15 01 00 00 00 00 02 FB 01 - /* SlpOut + DispOn */ - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 78 00 02 29 00 - ]; - qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - - qcom,config-select = <&dsi_dual_nt35597_truly_cmd_config0>; - - dsi_dual_nt35597_truly_cmd_config0: config0 { - qcom,split-mode = "dualctl-split"; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-jitter = <0x1 0x1>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* NVT SDC */ + 15 01 00 00 00 00 02 C0 00 + /* GRAM Slide Parameter */ + 29 01 00 00 00 00 0C C9 01 01 70 + 00 0A 06 67 04 C5 12 18 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi index d6ef3d8235edfe07ed29e9ee7667cb0bb6737044..95e0e5ae1db80cc9a27a5bc4072db3b3c968d71e 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -15,177 +15,13 @@ qcom,mdss-dsi-panel-name = "Dual nt35597 video mode dsi truly panel without DSC"; qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <720>; - qcom,mdss-dsi-panel-height = <2560>; - qcom,mdss-dsi-h-front-porch = <100>; - qcom,mdss-dsi-h-back-porch = <32>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <7>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <1>; - qcom,mdss-dsi-bpp = <24>; - qcom,mdss-dsi-underflow-color = <0x3ff>; - qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command = [ - /* CMD2_P0 */ - 15 01 00 00 00 00 02 FF 20 - 15 01 00 00 00 00 02 FB 01 - 15 01 00 00 00 00 02 00 01 - 15 01 00 00 00 00 02 01 55 - 15 01 00 00 00 00 02 02 45 - 15 01 00 00 00 00 02 05 40 - 15 01 00 00 00 00 02 06 19 - 15 01 00 00 00 00 02 07 1E - 15 01 00 00 00 00 02 0B 73 - 15 01 00 00 00 00 02 0C 73 - 15 01 00 00 00 00 02 0E B0 - 15 01 00 00 00 00 02 0F AE - 15 01 00 00 00 00 02 11 B8 - 15 01 00 00 00 00 02 13 00 - 15 01 00 00 00 00 02 58 80 - 15 01 00 00 00 00 02 59 01 - 15 01 00 00 00 00 02 5A 00 - 15 01 00 00 00 00 02 5B 01 - 15 01 00 00 00 00 02 5C 80 - 15 01 00 00 00 00 02 5D 81 - 15 01 00 00 00 00 02 5E 00 - 15 01 00 00 00 00 02 5F 01 - 15 01 00 00 00 00 02 72 31 - 15 01 00 00 00 00 02 68 03 - /* CMD2_P4 */ - 15 01 00 00 00 00 02 FF 24 - 15 01 00 00 00 00 02 FB 01 - 15 01 00 00 00 00 02 00 1C - 15 01 00 00 00 00 02 01 0B - 15 01 00 00 00 00 02 02 0C - 15 01 00 00 00 00 02 03 01 - 15 01 00 00 00 00 02 04 0F - 15 01 00 00 00 00 02 05 10 - 15 01 00 00 00 00 02 06 10 - 15 01 00 00 00 00 02 07 10 - 15 01 00 00 00 00 02 08 89 - 15 01 00 00 00 00 02 09 8A - 15 01 00 00 00 00 02 0A 13 - 15 01 00 00 00 00 02 0B 13 - 15 01 00 00 00 00 02 0C 15 - 15 01 00 00 00 00 02 0D 15 - 15 01 00 00 00 00 02 0E 17 - 15 01 00 00 00 00 02 0F 17 - 15 01 00 00 00 00 02 10 1C - 15 01 00 00 00 00 02 11 0B - 15 01 00 00 00 00 02 12 0C - 15 01 00 00 00 00 02 13 01 - 15 01 00 00 00 00 02 14 0F - 15 01 00 00 00 00 02 15 10 - 15 01 00 00 00 00 02 16 10 - 15 01 00 00 00 00 02 17 10 - 15 01 00 00 00 00 02 18 89 - 15 01 00 00 00 00 02 19 8A - 15 01 00 00 00 00 02 1A 13 - 15 01 00 00 00 00 02 1B 13 - 15 01 00 00 00 00 02 1C 15 - 15 01 00 00 00 00 02 1D 15 - 15 01 00 00 00 00 02 1E 17 - 15 01 00 00 00 00 02 1F 17 - /* STV */ - 15 01 00 00 00 00 02 20 40 - 15 01 00 00 00 00 02 21 01 - 15 01 00 00 00 00 02 22 00 - 15 01 00 00 00 00 02 23 40 - 15 01 00 00 00 00 02 24 40 - 15 01 00 00 00 00 02 25 6D - 15 01 00 00 00 00 02 26 40 - 15 01 00 00 00 00 02 27 40 - /* Vend */ - 15 01 00 00 00 00 02 E0 00 - 15 01 00 00 00 00 02 DC 21 - 15 01 00 00 00 00 02 DD 22 - 15 01 00 00 00 00 02 DE 07 - 15 01 00 00 00 00 02 DF 07 - 15 01 00 00 00 00 02 E3 6D - 15 01 00 00 00 00 02 E1 07 - 15 01 00 00 00 00 02 E2 07 - /* UD */ - 15 01 00 00 00 00 02 29 D8 - 15 01 00 00 00 00 02 2A 2A - /* CLK */ - 15 01 00 00 00 00 02 4B 03 - 15 01 00 00 00 00 02 4C 11 - 15 01 00 00 00 00 02 4D 10 - 15 01 00 00 00 00 02 4E 01 - 15 01 00 00 00 00 02 4F 01 - 15 01 00 00 00 00 02 50 10 - 15 01 00 00 00 00 02 51 00 - 15 01 00 00 00 00 02 52 80 - 15 01 00 00 00 00 02 53 00 - 15 01 00 00 00 00 02 56 00 - 15 01 00 00 00 00 02 54 07 - 15 01 00 00 00 00 02 58 07 - 15 01 00 00 00 00 02 55 25 - /* Reset XDONB */ - 15 01 00 00 00 00 02 5B 43 - 15 01 00 00 00 00 02 5C 00 - 15 01 00 00 00 00 02 5F 73 - 15 01 00 00 00 00 02 60 73 - 15 01 00 00 00 00 02 63 22 - 15 01 00 00 00 00 02 64 00 - 15 01 00 00 00 00 02 67 08 - 15 01 00 00 00 00 02 68 04 - /* Resolution:1440x2560*/ - 15 01 00 00 00 00 02 72 02 - /* mux */ - 15 01 00 00 00 00 02 7A 80 - 15 01 00 00 00 00 02 7B 91 - 15 01 00 00 00 00 02 7C D8 - 15 01 00 00 00 00 02 7D 60 - 15 01 00 00 00 00 02 7F 15 - 15 01 00 00 00 00 02 75 15 - /* ABOFF */ - 15 01 00 00 00 00 02 B3 C0 - 15 01 00 00 00 00 02 B4 00 - 15 01 00 00 00 00 02 B5 00 - /* Source EQ */ - 15 01 00 00 00 00 02 78 00 - 15 01 00 00 00 00 02 79 00 - 15 01 00 00 00 00 02 80 00 - 15 01 00 00 00 00 02 83 00 - /* FP BP */ - 15 01 00 00 00 00 02 93 0A - 15 01 00 00 00 00 02 94 0A - /* Inversion Type */ - 15 01 00 00 00 00 02 8A 00 - 15 01 00 00 00 00 02 9B FF - /* IMGSWAP =1 @PortSwap=1 */ - 15 01 00 00 00 00 02 9D B0 - 15 01 00 00 00 00 02 9F 63 - 15 01 00 00 00 00 02 98 10 - /* FRM */ - 15 01 00 00 00 00 02 EC 00 - /* CMD1 */ - 15 01 00 00 00 00 02 FF 10 - /* VBP+VSA=,VFP = 10H */ - 15 01 00 00 00 00 04 3B 03 0A 0A - /* FTE on */ - 15 01 00 00 00 00 02 35 00 - /* EN_BK =1(auto black) */ - 15 01 00 00 00 00 02 E5 01 - /* CMD mode(10) VDO mode(03) */ - 15 01 00 00 00 00 02 BB 03 - /* Non Reload MTP */ - 15 01 00 00 00 00 02 FB 01 - /* SlpOut + DispOn */ - 05 01 00 00 78 00 02 11 00 - 05 01 00 00 78 00 02 29 00 - ]; - qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -193,18 +29,185 @@ qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; qcom,mdss-dsi-lane-3-state; - qcom,cmd-sync-wait-broadcast; qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-underflow-color = <0x3ff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-bpp = <24>; - qcom,config-select = <&dsi_dual_nt35597_truly_video_config0>; - - dsi_dual_nt35597_truly_video_config0: config0 { - qcom,split-mode = "dualctl-split"; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 FF 24 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 FF 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 03 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; }; - - }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..32892a77a1c004ea52362f9ee15fb08f8b87a54f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi @@ -0,0 +1,196 @@ +/* Copyright (c) 2017-2018, 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. + */ + +&mdss_mdp { + dsi_nt35695b_truly_fhd_cmd: qcom,mdss_dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd command mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,ulps-enabled; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 + 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6e + 2a 3c 44 03 04 00]; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..720bb1dbc521974920b7c6c7c7eca674dda39136 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi @@ -0,0 +1,191 @@ +/* Copyright (c) 2017, 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. + */ + +&mdss_mdp { + dsi_nt35695b_truly_fhd_video: qcom,mdss_dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 03 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 14 00 02 28 00 05 01 00 00 78 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings = [e6 38 26 00 + 68 6e 2a 3c 44 03 04 00]; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1b38d06b20e4b74e6120dfa97b2da95ae397db05 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,88 @@ +/* Copyright (c) 2017-2018, 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. + */ + +&mdss_mdp { + dsi_dual_nt36850_truly_cmd: qcom,mdss_dsi_nt36850_truly_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual nt36850 cmd mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 50>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <140>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 44 03 e8 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 2c + 15 01 00 00 00 00 02 55 01 + 05 01 00 00 0a 00 02 20 00 + 15 01 00 00 00 00 02 bb 10 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a13486d5e60dceb11835606ced44d2b46294844a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi @@ -0,0 +1,137 @@ +/* Copyright (c) 2017, 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. + */ + +&mdss_mdp { + dsi_rm67195_amoled_fhd_cmd: qcom,mdss_dsi_rm67195_amoled_fhd_cmd{ + qcom,mdss-dsi-panel-name = + "rm67195 amoled fhd cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-pan-physical-width-dimension = <70>; + qcom,mdss-pan-physical-height-dimension = <125>; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-panel-orientation = "180"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 fe 0d + 15 01 00 00 00 00 02 0b c0 + 15 01 00 00 00 00 02 42 00 + 15 01 00 00 00 00 02 18 08 + 15 01 00 00 00 00 02 08 41 + 15 01 00 00 00 00 02 46 02 + 15 01 00 00 00 00 02 1e 04 + 15 01 00 00 02 00 02 1e 00 + 15 01 00 00 00 00 02 fe 0a + 15 01 00 00 00 00 02 24 17 + 15 01 00 00 00 00 02 04 07 + 15 01 00 00 00 00 02 1a 0c + 15 01 00 00 02 00 02 0f 44 + 15 01 00 00 00 00 02 fe 0b + 15 01 00 00 00 00 02 28 40 + 15 01 00 00 02 00 02 29 4f + 15 01 00 00 00 00 02 fe 04 + 15 01 00 00 00 00 02 0a d8 + 15 01 00 00 00 00 02 0c e6 + 15 01 00 00 00 00 02 4e 20 + 15 01 00 00 00 00 02 4f 1b + 15 01 00 00 00 00 02 50 2f + 15 01 00 00 02 00 02 51 08 + 15 01 00 00 00 00 02 fe 09 + 15 01 00 00 00 00 02 00 08 + 15 01 00 00 00 00 02 01 08 + 15 01 00 00 00 00 02 02 00 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 04 10 + 15 01 00 00 00 00 02 05 00 + 15 01 00 00 00 00 02 06 08 + 15 01 00 00 00 00 02 07 08 + 15 01 00 00 00 00 02 08 00 + 15 01 00 00 00 00 02 12 24 + 15 01 00 00 00 00 02 13 49 + 15 01 00 00 00 00 02 14 92 + 15 01 00 00 00 00 02 15 49 + 15 01 00 00 00 00 02 16 92 + 15 01 00 00 00 00 02 17 24 + 15 01 00 00 00 00 02 18 24 + 15 01 00 00 00 00 02 19 49 + 15 01 00 00 00 00 02 1a 92 + 15 01 00 00 00 00 02 1b 49 + 15 01 00 00 00 00 02 1c 92 + 15 01 00 00 00 00 02 1d 24 + 15 01 00 00 00 00 02 1e 24 + 15 01 00 00 00 00 02 1f 49 + 15 01 00 00 00 00 02 20 92 + 15 01 00 00 00 00 02 21 49 + 15 01 00 00 00 00 02 22 92 + 15 01 00 00 00 00 02 23 24 + 15 01 00 00 00 00 02 9b 07 + 15 01 00 00 02 00 02 9c a5 + 15 01 00 00 00 00 02 fe 00 + 15 01 00 00 00 00 02 c2 08 + 15 01 00 00 02 00 02 35 00 + 39 01 00 00 00 00 03 44 03 e8 + 05 01 00 00 82 00 02 11 00 + 05 01 00 00 14 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 14 + 00 02 28 00 05 01 00 00 82 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi index aa52083ec3ba49318860af303a4a5030d5bb54b4..aebc8b924182d2e5c2724c4e723e8ebb964a20e1 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi @@ -16,47 +16,15 @@ qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; qcom,mdss-dsi-panel-destination = "display_1"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-panel-clockrate = <850000000>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1080>; - qcom,mdss-dsi-panel-height = <1920>; - qcom,mdss-dsi-h-front-porch = <0>; - qcom,mdss-dsi-h-back-porch = <0>; - qcom,mdss-dsi-h-pulse-width = <0>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <0>; - qcom,mdss-dsi-v-front-porch = <0>; - qcom,mdss-dsi-v-pulse-width = <0>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; - qcom,mdss-dsi-on-command = [ - 15 01 00 00 00 00 02 bb 10 - 15 01 00 00 00 00 02 b0 03 - 05 01 00 00 78 00 01 11 - 15 01 00 00 00 00 02 51 ff - 15 01 00 00 00 00 02 53 24 - 15 01 00 00 00 00 02 ff 23 - 15 01 00 00 00 00 02 08 05 - 15 01 00 00 00 00 02 46 90 - 15 01 00 00 00 00 02 ff 10 - 15 01 00 00 00 00 02 ff f0 - 15 01 00 00 00 00 02 92 01 - 15 01 00 00 00 00 02 ff 10 - 05 01 00 00 28 00 01 29]; - qcom,mdss-dsi-off-command = [ - 05 01 00 00 10 00 01 28 - 05 01 00 00 40 00 01 10]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-pan-physical-width-dimension = <64>; + qcom,mdss-pan-physical-height-dimension = <117>; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -73,5 +41,46 @@ qcom,mdss-dsi-te-dcs-command = <1>; qcom,mdss-dsi-te-check-enable; qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi index 25c949c0e67e790e2cba496a640c9383ebdc2c07..86c8836ca51809e129f2cf908f80cee875229b0f 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -14,23 +14,10 @@ dsi_sharp_4k_dsc_cmd: qcom,mdss_dsi_sharp_4k_dsc_cmd { qcom,mdss-dsi-panel-name = "Sharp 4k cmd mode dsc dsi panel"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1080>; - qcom,mdss-dsi-panel-height = <3840>; - qcom,mdss-dsi-h-front-porch = <30>; - qcom,mdss-dsi-h-back-porch = <100>; - qcom,mdss-dsi-h-pulse-width = <4>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <7>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <1>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -40,7 +27,9 @@ qcom,mdss-dsi-lane-3-state; qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <129>; qcom,mdss-dsi-te-pin-select = <1>; qcom,mdss-dsi-wr-mem-start = <0x2c>; qcom,mdss-dsi-wr-mem-continue = <0x3c>; @@ -49,45 +38,66 @@ qcom,mdss-dsi-te-using-te-pin; qcom,dcs-cmd-by-left; qcom,mdss-dsi-tx-eot-append; - qcom,adjust-timer-wakeup-ms = <1>; - qcom,mdss-dsi-on-command = [ - 39 01 00 00 00 00 11 91 09 20 00 20 02 00 03 1c 04 21 00 - 0f 03 19 01 97 - 39 01 00 00 00 00 03 92 10 f0 - 15 01 00 00 00 00 02 90 03 - 15 01 00 00 00 00 02 03 01 - 39 01 00 00 00 00 06 f0 55 aa 52 08 04 - 15 01 00 00 00 00 02 c0 03 - 39 01 00 00 00 00 06 f0 55 aa 52 08 07 - 15 01 00 00 00 00 02 ef 01 - 39 01 00 00 00 00 06 f0 55 aa 52 08 00 - 15 01 00 00 00 00 02 b4 01 - 15 01 00 00 00 00 02 35 00 - 39 01 00 00 00 00 06 f0 55 aa 52 08 01 - 39 01 00 00 00 00 05 ff aa 55 a5 80 - 15 01 00 00 00 00 02 6f 01 - 15 01 00 00 00 00 02 f3 10 - 39 01 00 00 00 00 05 ff aa 55 a5 00 - 05 01 00 00 78 00 01 11 /* sleep out + delay 120ms */ - 05 01 00 00 78 00 01 29 /* display on + delay 120ms */ - ]; - - qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; - qcom,compression-mode = "dsc"; - qcom,config-select = <&dsi_sharp_dsc_cmd_config0>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x8 0xa>; - dsi_sharp_dsc_cmd_config0: config0 { - qcom,mdss-dsc-encoders = <1>; - qcom,mdss-dsc-slice-height = <32>; - qcom,mdss-dsc-slice-width = <1080>; - qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi index cc093d6e503f9c7e771e70991abf1c5a2a67abb6..66beead39bed59916868b8c32ff0d7e78f4d42ee 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi @@ -14,23 +14,10 @@ dsi_sharp_4k_dsc_video: qcom,mdss_dsi_sharp_4k_dsc_video { qcom,mdss-dsi-panel-name = "Sharp 4k video mode dsc dsi panel"; qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1080>; - qcom,mdss-dsi-panel-height = <3840>; - qcom,mdss-dsi-h-front-porch = <30>; - qcom,mdss-dsi-h-back-porch = <100>; - qcom,mdss-dsi-h-pulse-width = <4>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <7>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <1>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -40,47 +27,70 @@ qcom,mdss-dsi-lane-3-state; qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <129>; qcom,mdss-dsi-tx-eot-append; qcom,adjust-timer-wakeup-ms = <1>; - qcom,mdss-dsi-on-command = [ - 39 01 00 00 00 00 11 91 09 20 00 20 02 00 03 1c 04 21 00 - 0f 03 19 01 97 - 39 01 00 00 00 00 03 92 10 f0 - 15 01 00 00 00 00 02 90 03 - 15 01 00 00 00 00 02 03 01 - 39 01 00 00 00 00 06 f0 55 aa 52 08 04 - 15 01 00 00 00 00 02 c0 03 - 39 01 00 00 00 00 06 f0 55 aa 52 08 07 - 15 01 00 00 00 00 02 ef 01 - 39 01 00 00 00 00 06 f0 55 aa 52 08 00 - 15 01 00 00 00 00 02 b4 10 - 15 01 00 00 00 00 02 35 00 - 39 01 00 00 00 00 06 f0 55 aa 52 08 01 - 39 01 00 00 00 00 05 ff aa 55 a5 80 - 15 01 00 00 00 00 02 6f 01 - 15 01 00 00 00 00 02 f3 10 - 39 01 00 00 00 00 05 ff aa 55 a5 00 - 05 01 00 00 78 00 01 11 /* sleep out + delay 120ms */ - 05 01 00 00 78 00 01 29 /* display on + delay 120ms */ - ]; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; - qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; - qcom,compression-mode = "dsc"; - qcom,config-select = <&dsi_sharp_dsc_video_config0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 10 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - dsi_sharp_dsc_video_config0: config0 { - qcom,mdss-dsc-encoders = <1>; - qcom,mdss-dsc-slice-height = <32>; - qcom,mdss-dsc-slice-width = <1080>; - qcom,mdss-dsc-slice-per-pkt = <1>; - - qcom,mdss-dsc-bit-per-component = <8>; - qcom,mdss-dsc-bit-per-pixel = <8>; - qcom,mdss-dsc-block-prediction-enable; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi index 20716497adfe656005e0baab454a6fcb807ef487..6dc621ed8922b8123fc87b0833327a967bb88884 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi @@ -15,595 +15,12 @@ qcom,mdss-dsi-panel-name = "sharp 1080p 120hz dual dsi cmd mode panel"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <120>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <540>; - qcom,mdss-dsi-panel-height = <1920>; - qcom,mdss-dsi-h-front-porch = <28>; - qcom,mdss-dsi-h-back-porch = <4>; - qcom,mdss-dsi-h-pulse-width = <4>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <12>; - qcom,mdss-dsi-v-front-porch = <12>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 10>; - qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 ff 10 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 ba 07 - 15 01 00 00 00 00 02 c0 00 - 15 01 00 00 00 00 02 bb 10 - 15 01 00 00 00 00 02 d9 00 - 15 01 00 00 00 00 02 ef 70 - 15 01 00 00 00 00 02 f7 80 - 39 01 00 00 00 00 06 3b 03 0e 0c 08 1c - 15 01 00 00 00 00 02 e9 0e - 15 01 00 00 00 00 02 ea 0c - 15 01 00 00 00 00 02 35 00 - 15 01 00 00 00 00 02 c0 00 - 15 01 00 00 00 00 02 ff 20 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 59 6a - 15 01 00 00 00 00 02 0b 1b - 15 01 00 00 00 00 02 61 f7 - 15 01 00 00 00 00 02 62 6c - 15 01 00 00 00 00 02 00 01 - 15 01 00 00 00 00 02 01 55 - 15 01 00 00 00 00 02 04 c8 - 15 01 00 00 00 00 02 05 1a - 15 01 00 00 00 00 02 0d 93 - 15 01 00 00 00 00 02 0e 93 - 15 01 00 00 00 00 02 0f 7e - 15 01 00 00 00 00 02 06 69 - 15 01 00 00 00 00 02 07 bc - 15 01 00 00 00 00 02 10 03 - 15 01 00 00 00 00 02 11 64 - 15 01 00 00 00 00 02 12 5a - 15 01 00 00 00 00 02 13 40 - 15 01 00 00 00 00 02 14 40 - 15 01 00 00 00 00 02 15 00 - 15 01 00 00 00 00 02 33 13 - 15 01 00 00 00 00 02 5a 40 - 15 01 00 00 00 00 02 5b 40 - 15 01 00 00 00 00 02 5e 80 - 15 01 00 00 00 00 02 ff 24 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 80 - 15 01 00 00 00 00 02 14 80 - 15 01 00 00 00 00 02 01 80 - 15 01 00 00 00 00 02 15 80 - 15 01 00 00 00 00 02 02 80 - 15 01 00 00 00 00 02 16 80 - 15 01 00 00 00 00 02 03 0a - 15 01 00 00 00 00 02 17 0c - 15 01 00 00 00 00 02 04 06 - 15 01 00 00 00 00 02 18 08 - 15 01 00 00 00 00 02 05 80 - 15 01 00 00 00 00 02 19 80 - 15 01 00 00 00 00 02 06 80 - 15 01 00 00 00 00 02 1a 80 - 15 01 00 00 00 00 02 07 80 - 15 01 00 00 00 00 02 1b 80 - 15 01 00 00 00 00 02 08 80 - 15 01 00 00 00 00 02 1c 80 - 15 01 00 00 00 00 02 09 80 - 15 01 00 00 00 00 02 1d 80 - 15 01 00 00 00 00 02 0a 80 - 15 01 00 00 00 00 02 1e 80 - 15 01 00 00 00 00 02 0b 1a - 15 01 00 00 00 00 02 1f 1b - 15 01 00 00 00 00 02 0c 16 - 15 01 00 00 00 00 02 20 17 - 15 01 00 00 00 00 02 0d 1c - 15 01 00 00 00 00 02 21 1d - 15 01 00 00 00 00 02 0e 18 - 15 01 00 00 00 00 02 22 19 - 15 01 00 00 00 00 02 0f 0e - 15 01 00 00 00 00 02 23 10 - 15 01 00 00 00 00 02 10 80 - 15 01 00 00 00 00 02 24 80 - 15 01 00 00 00 00 02 11 80 - 15 01 00 00 00 00 02 25 80 - 15 01 00 00 00 00 02 12 80 - 15 01 00 00 00 00 02 26 80 - 15 01 00 00 00 00 02 13 80 - 15 01 00 00 00 00 02 27 80 - 15 01 00 00 00 00 02 74 ff - 15 01 00 00 00 00 02 75 ff - 15 01 00 00 00 00 02 8d 00 - 15 01 00 00 00 00 02 8e 00 - 15 01 00 00 00 00 02 8f 9c - 15 01 00 00 00 00 02 90 0c - 15 01 00 00 00 00 02 91 0e - 15 01 00 00 00 00 02 d6 00 - 15 01 00 00 00 00 02 d7 20 - 15 01 00 00 00 00 02 d8 00 - 15 01 00 00 00 00 02 d9 88 - 15 01 00 00 00 00 02 e5 05 - 15 01 00 00 00 00 02 e6 10 - 15 01 00 00 00 00 02 54 06 - 15 01 00 00 00 00 02 55 05 - 15 01 00 00 00 00 02 56 04 - 15 01 00 00 00 00 02 58 03 - 15 01 00 00 00 00 02 59 33 - 15 01 00 00 00 00 02 5a 33 - 15 01 00 00 00 00 02 5b 01 - 15 01 00 00 00 00 02 5c 00 - 15 01 00 00 00 00 02 5d 01 - 15 01 00 00 00 00 02 5e 0a - 15 01 00 00 00 00 02 5f 0a - 15 01 00 00 00 00 02 60 0a - 15 01 00 00 00 00 02 61 0a - 15 01 00 00 00 00 02 62 10 - 15 01 00 00 00 00 02 63 01 - 15 01 00 00 00 00 02 64 00 - 15 01 00 00 00 00 02 65 00 - 15 01 00 00 00 00 02 ef 00 - 15 01 00 00 00 00 02 f0 00 - 15 01 00 00 00 00 02 6d 20 - 15 01 00 00 00 00 02 66 44 - 15 01 00 00 00 00 02 68 01 - 15 01 00 00 00 00 02 69 00 - 15 01 00 00 00 00 02 67 11 - 15 01 00 00 00 00 02 6a 06 - 15 01 00 00 00 00 02 6b 31 - 15 01 00 00 00 00 02 6c 90 - 15 01 00 00 00 00 02 ab c3 - 15 01 00 00 00 00 02 b1 49 - 15 01 00 00 00 00 02 aa 80 - 15 01 00 00 00 00 02 b0 90 - 15 01 00 00 00 00 02 b2 a4 - 15 01 00 00 00 00 02 b3 00 - 15 01 00 00 00 00 02 b4 23 - 15 01 00 00 00 00 02 b5 00 - 15 01 00 00 00 00 02 b6 00 - 15 01 00 00 00 00 02 b7 00 - 15 01 00 00 00 00 02 b8 00 - 15 01 00 00 00 00 02 b9 00 - 15 01 00 00 00 00 02 ba 00 - 15 01 00 00 00 00 02 bb 00 - 15 01 00 00 00 00 02 bc 00 - 15 01 00 00 00 00 02 bd 00 - 15 01 00 00 00 00 02 be 00 - 15 01 00 00 00 00 02 bf 00 - 15 01 00 00 00 00 02 c0 00 - 15 01 00 00 00 00 02 c7 40 - 15 01 00 00 00 00 02 c9 00 - 15 01 00 00 00 00 02 c1 2a - 15 01 00 00 00 00 02 c2 2a - 15 01 00 00 00 00 02 c3 00 - 15 01 00 00 00 00 02 c4 00 - 15 01 00 00 00 00 02 c5 00 - 15 01 00 00 00 00 02 c6 00 - 15 01 00 00 00 00 02 c8 ab - 15 01 00 00 00 00 02 ca 00 - 15 01 00 00 00 00 02 cb 00 - 15 01 00 00 00 00 02 cc 20 - 15 01 00 00 00 00 02 cd 40 - 15 01 00 00 00 00 02 ce a8 - 15 01 00 00 00 00 02 cf a8 - 15 01 00 00 00 00 02 d0 00 - 15 01 00 00 00 00 02 d1 00 - 15 01 00 00 00 00 02 d2 00 - 15 01 00 00 00 00 02 d3 00 - 15 01 00 00 00 00 02 af 01 - 15 01 00 00 00 00 02 a4 1e - 15 01 00 00 00 00 02 95 41 - 15 01 00 00 00 00 02 96 03 - 15 01 00 00 00 00 02 98 00 - 15 01 00 00 00 00 02 9a 9a - 15 01 00 00 00 00 02 9b 03 - 15 01 00 00 00 00 02 9d 80 - 15 01 00 00 00 00 02 ff 26 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 fa d0 - 15 01 00 00 00 00 02 6b 80 - 15 01 00 00 00 00 02 6c 5c - 15 01 00 00 00 00 02 6d 0c - 15 01 00 00 00 00 02 6e 0e - 15 01 00 00 00 00 02 58 01 - 15 01 00 00 00 00 02 59 15 - 15 01 00 00 00 00 02 5a 01 - 15 01 00 00 00 00 02 5b 00 - 15 01 00 00 00 00 02 5c 01 - 15 01 00 00 00 00 02 5d 2b - 15 01 00 00 00 00 02 74 00 - 15 01 00 00 00 00 02 75 ba - 15 01 00 00 00 00 02 81 0a - 15 01 00 00 00 00 02 4e 81 - 15 01 00 00 00 00 02 4f 83 - 15 01 00 00 00 00 02 51 00 - 15 01 00 00 00 00 02 53 4d - 15 01 00 00 00 00 02 54 03 - 15 01 00 00 00 00 02 ff e0 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 b2 81 - 15 01 00 00 00 00 02 62 28 - 15 01 00 00 00 00 02 a2 09 - 15 01 00 00 00 00 02 b3 01 - 15 01 00 00 00 00 02 ed 00 - 15 01 00 00 00 00 02 ff 10 - 05 01 00 00 78 00 01 11 - 15 01 00 00 00 00 02 ff 20 - 15 01 00 00 00 00 02 75 00 - 15 01 00 00 00 00 02 76 71 - 15 01 00 00 00 00 02 77 00 - 15 01 00 00 00 00 02 78 84 - 15 01 00 00 00 00 02 79 00 - 15 01 00 00 00 00 02 7a a5 - 15 01 00 00 00 00 02 7b 00 - 15 01 00 00 00 00 02 7c bb - 15 01 00 00 00 00 02 7d 00 - 15 01 00 00 00 00 02 7e ce - 15 01 00 00 00 00 02 7f 00 - 15 01 00 00 00 00 02 80 e0 - 15 01 00 00 00 00 02 81 00 - 15 01 00 00 00 00 02 82 ef - 15 01 00 00 00 00 02 83 00 - 15 01 00 00 00 00 02 84 ff - 15 01 00 00 00 00 02 85 01 - 15 01 00 00 00 00 02 86 0b - 15 01 00 00 00 00 02 87 01 - 15 01 00 00 00 00 02 88 38 - 15 01 00 00 00 00 02 89 01 - 15 01 00 00 00 00 02 8a 5b - 15 01 00 00 00 00 02 8b 01 - 15 01 00 00 00 00 02 8c 95 - 15 01 00 00 00 00 02 8d 01 - 15 01 00 00 00 00 02 8e c4 - 15 01 00 00 00 00 02 8f 02 - 15 01 00 00 00 00 02 90 0d - 15 01 00 00 00 00 02 91 02 - 15 01 00 00 00 00 02 92 4a - 15 01 00 00 00 00 02 93 02 - 15 01 00 00 00 00 02 94 4c - 15 01 00 00 00 00 02 95 02 - 15 01 00 00 00 00 02 96 85 - 15 01 00 00 00 00 02 97 02 - 15 01 00 00 00 00 02 98 c3 - 15 01 00 00 00 00 02 99 02 - 15 01 00 00 00 00 02 9a e9 - 15 01 00 00 00 00 02 9b 03 - 15 01 00 00 00 00 02 9c 16 - 15 01 00 00 00 00 02 9d 03 - 15 01 00 00 00 00 02 9e 34 - 15 01 00 00 00 00 02 9f 03 - 15 01 00 00 00 00 02 a0 56 - 15 01 00 00 00 00 02 a2 03 - 15 01 00 00 00 00 02 a3 62 - 15 01 00 00 00 00 02 a4 03 - 15 01 00 00 00 00 02 a5 6c - 15 01 00 00 00 00 02 a6 03 - 15 01 00 00 00 00 02 a7 74 - 15 01 00 00 00 00 02 a9 03 - 15 01 00 00 00 00 02 aa 80 - 15 01 00 00 00 00 02 ab 03 - 15 01 00 00 00 00 02 ac 89 - 15 01 00 00 00 00 02 ad 03 - 15 01 00 00 00 00 02 ae 8b - 15 01 00 00 00 00 02 af 03 - 15 01 00 00 00 00 02 b0 8d - 15 01 00 00 00 00 02 b1 03 - 15 01 00 00 00 00 02 b2 8e - 15 01 00 00 00 00 02 b3 00 - 15 01 00 00 00 00 02 b4 71 - 15 01 00 00 00 00 02 b5 00 - 15 01 00 00 00 00 02 b6 84 - 15 01 00 00 00 00 02 b7 00 - 15 01 00 00 00 00 02 b8 a5 - 15 01 00 00 00 00 02 b9 00 - 15 01 00 00 00 00 02 ba bb - 15 01 00 00 00 00 02 bb 00 - 15 01 00 00 00 00 02 bc ce - 15 01 00 00 00 00 02 bd 00 - 15 01 00 00 00 00 02 be e0 - 15 01 00 00 00 00 02 bf 00 - 15 01 00 00 00 00 02 c0 ef - 15 01 00 00 00 00 02 c1 00 - 15 01 00 00 00 00 02 c2 ff - 15 01 00 00 00 00 02 c3 01 - 15 01 00 00 00 00 02 c4 0b - 15 01 00 00 00 00 02 c5 01 - 15 01 00 00 00 00 02 c6 38 - 15 01 00 00 00 00 02 c7 01 - 15 01 00 00 00 00 02 c8 5b - 15 01 00 00 00 00 02 c9 01 - 15 01 00 00 00 00 02 ca 95 - 15 01 00 00 00 00 02 cb 01 - 15 01 00 00 00 00 02 cc c4 - 15 01 00 00 00 00 02 cd 02 - 15 01 00 00 00 00 02 ce 0d - 15 01 00 00 00 00 02 cf 02 - 15 01 00 00 00 00 02 d0 4a - 15 01 00 00 00 00 02 d1 02 - 15 01 00 00 00 00 02 d2 4c - 15 01 00 00 00 00 02 d3 02 - 15 01 00 00 00 00 02 d4 85 - 15 01 00 00 00 00 02 d5 02 - 15 01 00 00 00 00 02 d6 c3 - 15 01 00 00 00 00 02 d7 02 - 15 01 00 00 00 00 02 d8 e9 - 15 01 00 00 00 00 02 d9 03 - 15 01 00 00 00 00 02 da 16 - 15 01 00 00 00 00 02 db 03 - 15 01 00 00 00 00 02 dc 34 - 15 01 00 00 00 00 02 dd 03 - 15 01 00 00 00 00 02 de 56 - 15 01 00 00 00 00 02 df 03 - 15 01 00 00 00 00 02 e0 62 - 15 01 00 00 00 00 02 e1 03 - 15 01 00 00 00 00 02 e2 6c - 15 01 00 00 00 00 02 e3 03 - 15 01 00 00 00 00 02 e4 74 - 15 01 00 00 00 00 02 e5 03 - 15 01 00 00 00 00 02 e6 80 - 15 01 00 00 00 00 02 e7 03 - 15 01 00 00 00 00 02 e8 89 - 15 01 00 00 00 00 02 e9 03 - 15 01 00 00 00 00 02 ea 8b - 15 01 00 00 00 00 02 eb 03 - 15 01 00 00 00 00 02 ec 8d - 15 01 00 00 00 00 02 ed 03 - 15 01 00 00 00 00 02 ee 8e - 15 01 00 00 00 00 02 ef 00 - 15 01 00 00 00 00 02 f0 71 - 15 01 00 00 00 00 02 f1 00 - 15 01 00 00 00 00 02 f2 84 - 15 01 00 00 00 00 02 f3 00 - 15 01 00 00 00 00 02 f4 a5 - 15 01 00 00 00 00 02 f5 00 - 15 01 00 00 00 00 02 f6 bb - 15 01 00 00 00 00 02 f7 00 - 15 01 00 00 00 00 02 f8 ce - 15 01 00 00 00 00 02 f9 00 - 15 01 00 00 00 00 02 fa e0 - 15 01 00 00 00 00 02 ff 21 - 15 01 00 00 00 00 02 fb 01 - 15 01 00 00 00 00 02 00 00 - 15 01 00 00 00 00 02 01 ef - 15 01 00 00 00 00 02 02 00 - 15 01 00 00 00 00 02 03 ff - 15 01 00 00 00 00 02 04 01 - 15 01 00 00 00 00 02 05 0b - 15 01 00 00 00 00 02 06 01 - 15 01 00 00 00 00 02 07 38 - 15 01 00 00 00 00 02 08 01 - 15 01 00 00 00 00 02 09 5b - 15 01 00 00 00 00 02 0a 01 - 15 01 00 00 00 00 02 0b 95 - 15 01 00 00 00 00 02 0c 01 - 15 01 00 00 00 00 02 0d c4 - 15 01 00 00 00 00 02 0e 02 - 15 01 00 00 00 00 02 0f 0d - 15 01 00 00 00 00 02 10 02 - 15 01 00 00 00 00 02 11 4a - 15 01 00 00 00 00 02 12 02 - 15 01 00 00 00 00 02 13 4c - 15 01 00 00 00 00 02 14 02 - 15 01 00 00 00 00 02 15 85 - 15 01 00 00 00 00 02 16 02 - 15 01 00 00 00 00 02 17 c3 - 15 01 00 00 00 00 02 18 02 - 15 01 00 00 00 00 02 19 e9 - 15 01 00 00 00 00 02 1a 03 - 15 01 00 00 00 00 02 1b 16 - 15 01 00 00 00 00 02 1c 03 - 15 01 00 00 00 00 02 1d 34 - 15 01 00 00 00 00 02 1e 03 - 15 01 00 00 00 00 02 1f 56 - 15 01 00 00 00 00 02 20 03 - 15 01 00 00 00 00 02 21 62 - 15 01 00 00 00 00 02 22 03 - 15 01 00 00 00 00 02 23 6c - 15 01 00 00 00 00 02 24 03 - 15 01 00 00 00 00 02 25 74 - 15 01 00 00 00 00 02 26 03 - 15 01 00 00 00 00 02 27 80 - 15 01 00 00 00 00 02 28 03 - 15 01 00 00 00 00 02 29 89 - 15 01 00 00 00 00 02 2a 03 - 15 01 00 00 00 00 02 2b 8b - 15 01 00 00 00 00 02 2d 03 - 15 01 00 00 00 00 02 2f 8d - 15 01 00 00 00 00 02 30 03 - 15 01 00 00 00 00 02 31 8e - 15 01 00 00 00 00 02 32 00 - 15 01 00 00 00 00 02 33 71 - 15 01 00 00 00 00 02 34 00 - 15 01 00 00 00 00 02 35 84 - 15 01 00 00 00 00 02 36 00 - 15 01 00 00 00 00 02 37 a5 - 15 01 00 00 00 00 02 38 00 - 15 01 00 00 00 00 02 39 bb - 15 01 00 00 00 00 02 3a 00 - 15 01 00 00 00 00 02 3b ce - 15 01 00 00 00 00 02 3d 00 - 15 01 00 00 00 00 02 3f e0 - 15 01 00 00 00 00 02 40 00 - 15 01 00 00 00 00 02 41 ef - 15 01 00 00 00 00 02 42 00 - 15 01 00 00 00 00 02 43 ff - 15 01 00 00 00 00 02 44 01 - 15 01 00 00 00 00 02 45 0b - 15 01 00 00 00 00 02 46 01 - 15 01 00 00 00 00 02 47 38 - 15 01 00 00 00 00 02 48 01 - 15 01 00 00 00 00 02 49 5b - 15 01 00 00 00 00 02 4a 01 - 15 01 00 00 00 00 02 4b 95 - 15 01 00 00 00 00 02 4c 01 - 15 01 00 00 00 00 02 4d c4 - 15 01 00 00 00 00 02 4e 02 - 15 01 00 00 00 00 02 4f 0d - 15 01 00 00 00 00 02 50 02 - 15 01 00 00 00 00 02 51 4a - 15 01 00 00 00 00 02 52 02 - 15 01 00 00 00 00 02 53 4c - 15 01 00 00 00 00 02 54 02 - 15 01 00 00 00 00 02 55 85 - 15 01 00 00 00 00 02 56 02 - 15 01 00 00 00 00 02 58 c3 - 15 01 00 00 00 00 02 59 02 - 15 01 00 00 00 00 02 5a e9 - 15 01 00 00 00 00 02 5b 03 - 15 01 00 00 00 00 02 5c 16 - 15 01 00 00 00 00 02 5d 03 - 15 01 00 00 00 00 02 5e 34 - 15 01 00 00 00 00 02 5f 03 - 15 01 00 00 00 00 02 60 56 - 15 01 00 00 00 00 02 61 03 - 15 01 00 00 00 00 02 62 62 - 15 01 00 00 00 00 02 63 03 - 15 01 00 00 00 00 02 64 6c - 15 01 00 00 00 00 02 65 03 - 15 01 00 00 00 00 02 66 74 - 15 01 00 00 00 00 02 67 03 - 15 01 00 00 00 00 02 68 80 - 15 01 00 00 00 00 02 69 03 - 15 01 00 00 00 00 02 6a 89 - 15 01 00 00 00 00 02 6b 03 - 15 01 00 00 00 00 02 6c 8b - 15 01 00 00 00 00 02 6d 03 - 15 01 00 00 00 00 02 6e 8d - 15 01 00 00 00 00 02 6f 03 - 15 01 00 00 00 00 02 70 8e - 15 01 00 00 00 00 02 71 00 - 15 01 00 00 00 00 02 72 71 - 15 01 00 00 00 00 02 73 00 - 15 01 00 00 00 00 02 74 84 - 15 01 00 00 00 00 02 75 00 - 15 01 00 00 00 00 02 76 a5 - 15 01 00 00 00 00 02 77 00 - 15 01 00 00 00 00 02 78 bb - 15 01 00 00 00 00 02 79 00 - 15 01 00 00 00 00 02 7a ce - 15 01 00 00 00 00 02 7b 00 - 15 01 00 00 00 00 02 7c e0 - 15 01 00 00 00 00 02 7d 00 - 15 01 00 00 00 00 02 7e ef - 15 01 00 00 00 00 02 7f 00 - 15 01 00 00 00 00 02 80 ff - 15 01 00 00 00 00 02 81 01 - 15 01 00 00 00 00 02 82 0b - 15 01 00 00 00 00 02 83 01 - 15 01 00 00 00 00 02 84 38 - 15 01 00 00 00 00 02 85 01 - 15 01 00 00 00 00 02 86 5b - 15 01 00 00 00 00 02 87 01 - 15 01 00 00 00 00 02 88 95 - 15 01 00 00 00 00 02 89 01 - 15 01 00 00 00 00 02 8a c4 - 15 01 00 00 00 00 02 8b 02 - 15 01 00 00 00 00 02 8c 0d - 15 01 00 00 00 00 02 8d 02 - 15 01 00 00 00 00 02 8e 4a - 15 01 00 00 00 00 02 8f 02 - 15 01 00 00 00 00 02 90 4c - 15 01 00 00 00 00 02 91 02 - 15 01 00 00 00 00 02 92 85 - 15 01 00 00 00 00 02 93 02 - 15 01 00 00 00 00 02 94 c3 - 15 01 00 00 00 00 02 95 02 - 15 01 00 00 00 00 02 96 e9 - 15 01 00 00 00 00 02 97 03 - 15 01 00 00 00 00 02 98 16 - 15 01 00 00 00 00 02 99 03 - 15 01 00 00 00 00 02 9a 34 - 15 01 00 00 00 00 02 9b 03 - 15 01 00 00 00 00 02 9c 56 - 15 01 00 00 00 00 02 9d 03 - 15 01 00 00 00 00 02 9e 62 - 15 01 00 00 00 00 02 9f 03 - 15 01 00 00 00 00 02 a0 6c - 15 01 00 00 00 00 02 a2 03 - 15 01 00 00 00 00 02 a3 74 - 15 01 00 00 00 00 02 a4 03 - 15 01 00 00 00 00 02 a5 80 - 15 01 00 00 00 00 02 a6 03 - 15 01 00 00 00 00 02 a7 89 - 15 01 00 00 00 00 02 a9 03 - 15 01 00 00 00 00 02 aa 8b - 15 01 00 00 00 00 02 ab 03 - 15 01 00 00 00 00 02 ac 8d - 15 01 00 00 00 00 02 ad 03 - 15 01 00 00 00 00 02 ae 8e - 15 01 00 00 00 00 02 af 00 - 15 01 00 00 00 00 02 b0 71 - 15 01 00 00 00 00 02 b1 00 - 15 01 00 00 00 00 02 b2 84 - 15 01 00 00 00 00 02 b3 00 - 15 01 00 00 00 00 02 b4 a5 - 15 01 00 00 00 00 02 b5 00 - 15 01 00 00 00 00 02 b6 bb - 15 01 00 00 00 00 02 b7 00 - 15 01 00 00 00 00 02 b8 ce - 15 01 00 00 00 00 02 b9 00 - 15 01 00 00 00 00 02 ba e0 - 15 01 00 00 00 00 02 bb 00 - 15 01 00 00 00 00 02 bc ef - 15 01 00 00 00 00 02 bd 00 - 15 01 00 00 00 00 02 be ff - 15 01 00 00 00 00 02 bf 01 - 15 01 00 00 00 00 02 c0 0b - 15 01 00 00 00 00 02 c1 01 - 15 01 00 00 00 00 02 c2 38 - 15 01 00 00 00 00 02 c3 01 - 15 01 00 00 00 00 02 c4 5b - 15 01 00 00 00 00 02 c5 01 - 15 01 00 00 00 00 02 c6 95 - 15 01 00 00 00 00 02 c7 01 - 15 01 00 00 00 00 02 c8 c4 - 15 01 00 00 00 00 02 c9 02 - 15 01 00 00 00 00 02 ca 0d - 15 01 00 00 00 00 02 cb 02 - 15 01 00 00 00 00 02 cc 4a - 15 01 00 00 00 00 02 cd 02 - 15 01 00 00 00 00 02 ce 4c - 15 01 00 00 00 00 02 cf 02 - 15 01 00 00 00 00 02 d0 85 - 15 01 00 00 00 00 02 d1 02 - 15 01 00 00 00 00 02 d2 c3 - 15 01 00 00 00 00 02 d3 02 - 15 01 00 00 00 00 02 d4 e9 - 15 01 00 00 00 00 02 d5 03 - 15 01 00 00 00 00 02 d6 16 - 15 01 00 00 00 00 02 d7 03 - 15 01 00 00 00 00 02 d8 34 - 15 01 00 00 00 00 02 d9 03 - 15 01 00 00 00 00 02 da 56 - 15 01 00 00 00 00 02 db 03 - 15 01 00 00 00 00 02 dc 62 - 15 01 00 00 00 00 02 dd 03 - 15 01 00 00 00 00 02 de 6c - 15 01 00 00 00 00 02 df 03 - 15 01 00 00 00 00 02 e0 74 - 15 01 00 00 00 00 02 e1 03 - 15 01 00 00 00 00 02 e2 80 - 15 01 00 00 00 00 02 e3 03 - 15 01 00 00 00 00 02 e4 89 - 15 01 00 00 00 00 02 e5 03 - 15 01 00 00 00 00 02 e6 8b - 15 01 00 00 00 00 02 e7 03 - 15 01 00 00 00 00 02 e8 8d - 15 01 00 00 00 00 02 e9 03 - 15 01 00 00 00 00 02 ea 8e - 15 01 00 00 00 00 02 FF 10 - 05 01 00 00 00 00 01 29]; - qcom,mdss-dsi-off-command = [15 01 00 00 00 00 02 ff 10 - 05 01 00 00 10 00 01 28 - 15 01 00 00 00 00 02 b0 00 - 05 01 00 00 40 00 01 10 - 15 01 00 00 00 00 02 4f 01]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "burst_mode"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -623,10 +40,594 @@ qcom,mdss-dsi-te-check-enable; qcom,mdss-dsi-te-using-te-pin; - qcom,config-select = <&dsi_dual_sharp_cmd_config0>; - - dsi_dual_sharp_cmd_config0: config0 { - qcom,split-mode = "dualctl-split"; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 ba 07 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 d9 00 + 15 01 00 00 00 00 02 ef 70 + 15 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 06 3b 03 0e 0c 08 1c + 15 01 00 00 00 00 02 e9 0e + 15 01 00 00 00 00 02 ea 0c + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 59 6a + 15 01 00 00 00 00 02 0b 1b + 15 01 00 00 00 00 02 61 f7 + 15 01 00 00 00 00 02 62 6c + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 04 c8 + 15 01 00 00 00 00 02 05 1a + 15 01 00 00 00 00 02 0d 93 + 15 01 00 00 00 00 02 0e 93 + 15 01 00 00 00 00 02 0f 7e + 15 01 00 00 00 00 02 06 69 + 15 01 00 00 00 00 02 07 bc + 15 01 00 00 00 00 02 10 03 + 15 01 00 00 00 00 02 11 64 + 15 01 00 00 00 00 02 12 5a + 15 01 00 00 00 00 02 13 40 + 15 01 00 00 00 00 02 14 40 + 15 01 00 00 00 00 02 15 00 + 15 01 00 00 00 00 02 33 13 + 15 01 00 00 00 00 02 5a 40 + 15 01 00 00 00 00 02 5b 40 + 15 01 00 00 00 00 02 5e 80 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 80 + 15 01 00 00 00 00 02 14 80 + 15 01 00 00 00 00 02 01 80 + 15 01 00 00 00 00 02 15 80 + 15 01 00 00 00 00 02 02 80 + 15 01 00 00 00 00 02 16 80 + 15 01 00 00 00 00 02 03 0a + 15 01 00 00 00 00 02 17 0c + 15 01 00 00 00 00 02 04 06 + 15 01 00 00 00 00 02 18 08 + 15 01 00 00 00 00 02 05 80 + 15 01 00 00 00 00 02 19 80 + 15 01 00 00 00 00 02 06 80 + 15 01 00 00 00 00 02 1a 80 + 15 01 00 00 00 00 02 07 80 + 15 01 00 00 00 00 02 1b 80 + 15 01 00 00 00 00 02 08 80 + 15 01 00 00 00 00 02 1c 80 + 15 01 00 00 00 00 02 09 80 + 15 01 00 00 00 00 02 1d 80 + 15 01 00 00 00 00 02 0a 80 + 15 01 00 00 00 00 02 1e 80 + 15 01 00 00 00 00 02 0b 1a + 15 01 00 00 00 00 02 1f 1b + 15 01 00 00 00 00 02 0c 16 + 15 01 00 00 00 00 02 20 17 + 15 01 00 00 00 00 02 0d 1c + 15 01 00 00 00 00 02 21 1d + 15 01 00 00 00 00 02 0e 18 + 15 01 00 00 00 00 02 22 19 + 15 01 00 00 00 00 02 0f 0e + 15 01 00 00 00 00 02 23 10 + 15 01 00 00 00 00 02 10 80 + 15 01 00 00 00 00 02 24 80 + 15 01 00 00 00 00 02 11 80 + 15 01 00 00 00 00 02 25 80 + 15 01 00 00 00 00 02 12 80 + 15 01 00 00 00 00 02 26 80 + 15 01 00 00 00 00 02 13 80 + 15 01 00 00 00 00 02 27 80 + 15 01 00 00 00 00 02 74 ff + 15 01 00 00 00 00 02 75 ff + 15 01 00 00 00 00 02 8d 00 + 15 01 00 00 00 00 02 8e 00 + 15 01 00 00 00 00 02 8f 9c + 15 01 00 00 00 00 02 90 0c + 15 01 00 00 00 00 02 91 0e + 15 01 00 00 00 00 02 d6 00 + 15 01 00 00 00 00 02 d7 20 + 15 01 00 00 00 00 02 d8 00 + 15 01 00 00 00 00 02 d9 88 + 15 01 00 00 00 00 02 e5 05 + 15 01 00 00 00 00 02 e6 10 + 15 01 00 00 00 00 02 54 06 + 15 01 00 00 00 00 02 55 05 + 15 01 00 00 00 00 02 56 04 + 15 01 00 00 00 00 02 58 03 + 15 01 00 00 00 00 02 59 33 + 15 01 00 00 00 00 02 5a 33 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5d 01 + 15 01 00 00 00 00 02 5e 0a + 15 01 00 00 00 00 02 5f 0a + 15 01 00 00 00 00 02 60 0a + 15 01 00 00 00 00 02 61 0a + 15 01 00 00 00 00 02 62 10 + 15 01 00 00 00 00 02 63 01 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 65 00 + 15 01 00 00 00 00 02 ef 00 + 15 01 00 00 00 00 02 f0 00 + 15 01 00 00 00 00 02 6d 20 + 15 01 00 00 00 00 02 66 44 + 15 01 00 00 00 00 02 68 01 + 15 01 00 00 00 00 02 69 00 + 15 01 00 00 00 00 02 67 11 + 15 01 00 00 00 00 02 6a 06 + 15 01 00 00 00 00 02 6b 31 + 15 01 00 00 00 00 02 6c 90 + 15 01 00 00 00 00 02 ab c3 + 15 01 00 00 00 00 02 b1 49 + 15 01 00 00 00 00 02 aa 80 + 15 01 00 00 00 00 02 b0 90 + 15 01 00 00 00 00 02 b2 a4 + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 23 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 00 + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 00 + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba 00 + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc 00 + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be 00 + 15 01 00 00 00 00 02 bf 00 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 c7 40 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c1 2a + 15 01 00 00 00 00 02 c2 2a + 15 01 00 00 00 00 02 c3 00 + 15 01 00 00 00 00 02 c4 00 + 15 01 00 00 00 00 02 c5 00 + 15 01 00 00 00 00 02 c6 00 + 15 01 00 00 00 00 02 c8 ab + 15 01 00 00 00 00 02 ca 00 + 15 01 00 00 00 00 02 cb 00 + 15 01 00 00 00 00 02 cc 20 + 15 01 00 00 00 00 02 cd 40 + 15 01 00 00 00 00 02 ce a8 + 15 01 00 00 00 00 02 cf a8 + 15 01 00 00 00 00 02 d0 00 + 15 01 00 00 00 00 02 d1 00 + 15 01 00 00 00 00 02 d2 00 + 15 01 00 00 00 00 02 d3 00 + 15 01 00 00 00 00 02 af 01 + 15 01 00 00 00 00 02 a4 1e + 15 01 00 00 00 00 02 95 41 + 15 01 00 00 00 00 02 96 03 + 15 01 00 00 00 00 02 98 00 + 15 01 00 00 00 00 02 9a 9a + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9d 80 + 15 01 00 00 00 00 02 ff 26 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 fa d0 + 15 01 00 00 00 00 02 6b 80 + 15 01 00 00 00 00 02 6c 5c + 15 01 00 00 00 00 02 6d 0c + 15 01 00 00 00 00 02 6e 0e + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 59 15 + 15 01 00 00 00 00 02 5a 01 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 01 + 15 01 00 00 00 00 02 5d 2b + 15 01 00 00 00 00 02 74 00 + 15 01 00 00 00 00 02 75 ba + 15 01 00 00 00 00 02 81 0a + 15 01 00 00 00 00 02 4e 81 + 15 01 00 00 00 00 02 4f 83 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 53 4d + 15 01 00 00 00 00 02 54 03 + 15 01 00 00 00 00 02 ff e0 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 b2 81 + 15 01 00 00 00 00 02 62 28 + 15 01 00 00 00 00 02 a2 09 + 15 01 00 00 00 00 02 b3 01 + 15 01 00 00 00 00 02 ed 00 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 75 00 + 15 01 00 00 00 00 02 76 71 + 15 01 00 00 00 00 02 77 00 + 15 01 00 00 00 00 02 78 84 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 7a a5 + 15 01 00 00 00 00 02 7b 00 + 15 01 00 00 00 00 02 7c bb + 15 01 00 00 00 00 02 7d 00 + 15 01 00 00 00 00 02 7e ce + 15 01 00 00 00 00 02 7f 00 + 15 01 00 00 00 00 02 80 e0 + 15 01 00 00 00 00 02 81 00 + 15 01 00 00 00 00 02 82 ef + 15 01 00 00 00 00 02 83 00 + 15 01 00 00 00 00 02 84 ff + 15 01 00 00 00 00 02 85 01 + 15 01 00 00 00 00 02 86 0b + 15 01 00 00 00 00 02 87 01 + 15 01 00 00 00 00 02 88 38 + 15 01 00 00 00 00 02 89 01 + 15 01 00 00 00 00 02 8a 5b + 15 01 00 00 00 00 02 8b 01 + 15 01 00 00 00 00 02 8c 95 + 15 01 00 00 00 00 02 8d 01 + 15 01 00 00 00 00 02 8e c4 + 15 01 00 00 00 00 02 8f 02 + 15 01 00 00 00 00 02 90 0d + 15 01 00 00 00 00 02 91 02 + 15 01 00 00 00 00 02 92 4a + 15 01 00 00 00 00 02 93 02 + 15 01 00 00 00 00 02 94 4c + 15 01 00 00 00 00 02 95 02 + 15 01 00 00 00 00 02 96 85 + 15 01 00 00 00 00 02 97 02 + 15 01 00 00 00 00 02 98 c3 + 15 01 00 00 00 00 02 99 02 + 15 01 00 00 00 00 02 9a e9 + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9c 16 + 15 01 00 00 00 00 02 9d 03 + 15 01 00 00 00 00 02 9e 34 + 15 01 00 00 00 00 02 9f 03 + 15 01 00 00 00 00 02 a0 56 + 15 01 00 00 00 00 02 a2 03 + 15 01 00 00 00 00 02 a3 62 + 15 01 00 00 00 00 02 a4 03 + 15 01 00 00 00 00 02 a5 6c + 15 01 00 00 00 00 02 a6 03 + 15 01 00 00 00 00 02 a7 74 + 15 01 00 00 00 00 02 a9 03 + 15 01 00 00 00 00 02 aa 80 + 15 01 00 00 00 00 02 ab 03 + 15 01 00 00 00 00 02 ac 89 + 15 01 00 00 00 00 02 ad 03 + 15 01 00 00 00 00 02 ae 8b + 15 01 00 00 00 00 02 af 03 + 15 01 00 00 00 00 02 b0 8d + 15 01 00 00 00 00 02 b1 03 + 15 01 00 00 00 00 02 b2 8e + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 71 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 84 + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 a5 + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba bb + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc ce + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be e0 + 15 01 00 00 00 00 02 bf 00 + 15 01 00 00 00 00 02 c0 ef + 15 01 00 00 00 00 02 c1 00 + 15 01 00 00 00 00 02 c2 ff + 15 01 00 00 00 00 02 c3 01 + 15 01 00 00 00 00 02 c4 0b + 15 01 00 00 00 00 02 c5 01 + 15 01 00 00 00 00 02 c6 38 + 15 01 00 00 00 00 02 c7 01 + 15 01 00 00 00 00 02 c8 5b + 15 01 00 00 00 00 02 c9 01 + 15 01 00 00 00 00 02 ca 95 + 15 01 00 00 00 00 02 cb 01 + 15 01 00 00 00 00 02 cc c4 + 15 01 00 00 00 00 02 cd 02 + 15 01 00 00 00 00 02 ce 0d + 15 01 00 00 00 00 02 cf 02 + 15 01 00 00 00 00 02 d0 4a + 15 01 00 00 00 00 02 d1 02 + 15 01 00 00 00 00 02 d2 4c + 15 01 00 00 00 00 02 d3 02 + 15 01 00 00 00 00 02 d4 85 + 15 01 00 00 00 00 02 d5 02 + 15 01 00 00 00 00 02 d6 c3 + 15 01 00 00 00 00 02 d7 02 + 15 01 00 00 00 00 02 d8 e9 + 15 01 00 00 00 00 02 d9 03 + 15 01 00 00 00 00 02 da 16 + 15 01 00 00 00 00 02 db 03 + 15 01 00 00 00 00 02 dc 34 + 15 01 00 00 00 00 02 dd 03 + 15 01 00 00 00 00 02 de 56 + 15 01 00 00 00 00 02 df 03 + 15 01 00 00 00 00 02 e0 62 + 15 01 00 00 00 00 02 e1 03 + 15 01 00 00 00 00 02 e2 6c + 15 01 00 00 00 00 02 e3 03 + 15 01 00 00 00 00 02 e4 74 + 15 01 00 00 00 00 02 e5 03 + 15 01 00 00 00 00 02 e6 80 + 15 01 00 00 00 00 02 e7 03 + 15 01 00 00 00 00 02 e8 89 + 15 01 00 00 00 00 02 e9 03 + 15 01 00 00 00 00 02 ea 8b + 15 01 00 00 00 00 02 eb 03 + 15 01 00 00 00 00 02 ec 8d + 15 01 00 00 00 00 02 ed 03 + 15 01 00 00 00 00 02 ee 8e + 15 01 00 00 00 00 02 ef 00 + 15 01 00 00 00 00 02 f0 71 + 15 01 00 00 00 00 02 f1 00 + 15 01 00 00 00 00 02 f2 84 + 15 01 00 00 00 00 02 f3 00 + 15 01 00 00 00 00 02 f4 a5 + 15 01 00 00 00 00 02 f5 00 + 15 01 00 00 00 00 02 f6 bb + 15 01 00 00 00 00 02 f7 00 + 15 01 00 00 00 00 02 f8 ce + 15 01 00 00 00 00 02 f9 00 + 15 01 00 00 00 00 02 fa e0 + 15 01 00 00 00 00 02 ff 21 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 00 + 15 01 00 00 00 00 02 01 ef + 15 01 00 00 00 00 02 02 00 + 15 01 00 00 00 00 02 03 ff + 15 01 00 00 00 00 02 04 01 + 15 01 00 00 00 00 02 05 0b + 15 01 00 00 00 00 02 06 01 + 15 01 00 00 00 00 02 07 38 + 15 01 00 00 00 00 02 08 01 + 15 01 00 00 00 00 02 09 5b + 15 01 00 00 00 00 02 0a 01 + 15 01 00 00 00 00 02 0b 95 + 15 01 00 00 00 00 02 0c 01 + 15 01 00 00 00 00 02 0d c4 + 15 01 00 00 00 00 02 0e 02 + 15 01 00 00 00 00 02 0f 0d + 15 01 00 00 00 00 02 10 02 + 15 01 00 00 00 00 02 11 4a + 15 01 00 00 00 00 02 12 02 + 15 01 00 00 00 00 02 13 4c + 15 01 00 00 00 00 02 14 02 + 15 01 00 00 00 00 02 15 85 + 15 01 00 00 00 00 02 16 02 + 15 01 00 00 00 00 02 17 c3 + 15 01 00 00 00 00 02 18 02 + 15 01 00 00 00 00 02 19 e9 + 15 01 00 00 00 00 02 1a 03 + 15 01 00 00 00 00 02 1b 16 + 15 01 00 00 00 00 02 1c 03 + 15 01 00 00 00 00 02 1d 34 + 15 01 00 00 00 00 02 1e 03 + 15 01 00 00 00 00 02 1f 56 + 15 01 00 00 00 00 02 20 03 + 15 01 00 00 00 00 02 21 62 + 15 01 00 00 00 00 02 22 03 + 15 01 00 00 00 00 02 23 6c + 15 01 00 00 00 00 02 24 03 + 15 01 00 00 00 00 02 25 74 + 15 01 00 00 00 00 02 26 03 + 15 01 00 00 00 00 02 27 80 + 15 01 00 00 00 00 02 28 03 + 15 01 00 00 00 00 02 29 89 + 15 01 00 00 00 00 02 2a 03 + 15 01 00 00 00 00 02 2b 8b + 15 01 00 00 00 00 02 2d 03 + 15 01 00 00 00 00 02 2f 8d + 15 01 00 00 00 00 02 30 03 + 15 01 00 00 00 00 02 31 8e + 15 01 00 00 00 00 02 32 00 + 15 01 00 00 00 00 02 33 71 + 15 01 00 00 00 00 02 34 00 + 15 01 00 00 00 00 02 35 84 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 37 a5 + 15 01 00 00 00 00 02 38 00 + 15 01 00 00 00 00 02 39 bb + 15 01 00 00 00 00 02 3a 00 + 15 01 00 00 00 00 02 3b ce + 15 01 00 00 00 00 02 3d 00 + 15 01 00 00 00 00 02 3f e0 + 15 01 00 00 00 00 02 40 00 + 15 01 00 00 00 00 02 41 ef + 15 01 00 00 00 00 02 42 00 + 15 01 00 00 00 00 02 43 ff + 15 01 00 00 00 00 02 44 01 + 15 01 00 00 00 00 02 45 0b + 15 01 00 00 00 00 02 46 01 + 15 01 00 00 00 00 02 47 38 + 15 01 00 00 00 00 02 48 01 + 15 01 00 00 00 00 02 49 5b + 15 01 00 00 00 00 02 4a 01 + 15 01 00 00 00 00 02 4b 95 + 15 01 00 00 00 00 02 4c 01 + 15 01 00 00 00 00 02 4d c4 + 15 01 00 00 00 00 02 4e 02 + 15 01 00 00 00 00 02 4f 0d + 15 01 00 00 00 00 02 50 02 + 15 01 00 00 00 00 02 51 4a + 15 01 00 00 00 00 02 52 02 + 15 01 00 00 00 00 02 53 4c + 15 01 00 00 00 00 02 54 02 + 15 01 00 00 00 00 02 55 85 + 15 01 00 00 00 00 02 56 02 + 15 01 00 00 00 00 02 58 c3 + 15 01 00 00 00 00 02 59 02 + 15 01 00 00 00 00 02 5a e9 + 15 01 00 00 00 00 02 5b 03 + 15 01 00 00 00 00 02 5c 16 + 15 01 00 00 00 00 02 5d 03 + 15 01 00 00 00 00 02 5e 34 + 15 01 00 00 00 00 02 5f 03 + 15 01 00 00 00 00 02 60 56 + 15 01 00 00 00 00 02 61 03 + 15 01 00 00 00 00 02 62 62 + 15 01 00 00 00 00 02 63 03 + 15 01 00 00 00 00 02 64 6c + 15 01 00 00 00 00 02 65 03 + 15 01 00 00 00 00 02 66 74 + 15 01 00 00 00 00 02 67 03 + 15 01 00 00 00 00 02 68 80 + 15 01 00 00 00 00 02 69 03 + 15 01 00 00 00 00 02 6a 89 + 15 01 00 00 00 00 02 6b 03 + 15 01 00 00 00 00 02 6c 8b + 15 01 00 00 00 00 02 6d 03 + 15 01 00 00 00 00 02 6e 8d + 15 01 00 00 00 00 02 6f 03 + 15 01 00 00 00 00 02 70 8e + 15 01 00 00 00 00 02 71 00 + 15 01 00 00 00 00 02 72 71 + 15 01 00 00 00 00 02 73 00 + 15 01 00 00 00 00 02 74 84 + 15 01 00 00 00 00 02 75 00 + 15 01 00 00 00 00 02 76 a5 + 15 01 00 00 00 00 02 77 00 + 15 01 00 00 00 00 02 78 bb + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 7a ce + 15 01 00 00 00 00 02 7b 00 + 15 01 00 00 00 00 02 7c e0 + 15 01 00 00 00 00 02 7d 00 + 15 01 00 00 00 00 02 7e ef + 15 01 00 00 00 00 02 7f 00 + 15 01 00 00 00 00 02 80 ff + 15 01 00 00 00 00 02 81 01 + 15 01 00 00 00 00 02 82 0b + 15 01 00 00 00 00 02 83 01 + 15 01 00 00 00 00 02 84 38 + 15 01 00 00 00 00 02 85 01 + 15 01 00 00 00 00 02 86 5b + 15 01 00 00 00 00 02 87 01 + 15 01 00 00 00 00 02 88 95 + 15 01 00 00 00 00 02 89 01 + 15 01 00 00 00 00 02 8a c4 + 15 01 00 00 00 00 02 8b 02 + 15 01 00 00 00 00 02 8c 0d + 15 01 00 00 00 00 02 8d 02 + 15 01 00 00 00 00 02 8e 4a + 15 01 00 00 00 00 02 8f 02 + 15 01 00 00 00 00 02 90 4c + 15 01 00 00 00 00 02 91 02 + 15 01 00 00 00 00 02 92 85 + 15 01 00 00 00 00 02 93 02 + 15 01 00 00 00 00 02 94 c3 + 15 01 00 00 00 00 02 95 02 + 15 01 00 00 00 00 02 96 e9 + 15 01 00 00 00 00 02 97 03 + 15 01 00 00 00 00 02 98 16 + 15 01 00 00 00 00 02 99 03 + 15 01 00 00 00 00 02 9a 34 + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9c 56 + 15 01 00 00 00 00 02 9d 03 + 15 01 00 00 00 00 02 9e 62 + 15 01 00 00 00 00 02 9f 03 + 15 01 00 00 00 00 02 a0 6c + 15 01 00 00 00 00 02 a2 03 + 15 01 00 00 00 00 02 a3 74 + 15 01 00 00 00 00 02 a4 03 + 15 01 00 00 00 00 02 a5 80 + 15 01 00 00 00 00 02 a6 03 + 15 01 00 00 00 00 02 a7 89 + 15 01 00 00 00 00 02 a9 03 + 15 01 00 00 00 00 02 aa 8b + 15 01 00 00 00 00 02 ab 03 + 15 01 00 00 00 00 02 ac 8d + 15 01 00 00 00 00 02 ad 03 + 15 01 00 00 00 00 02 ae 8e + 15 01 00 00 00 00 02 af 00 + 15 01 00 00 00 00 02 b0 71 + 15 01 00 00 00 00 02 b1 00 + 15 01 00 00 00 00 02 b2 84 + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 a5 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 bb + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 ce + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba e0 + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc ef + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be ff + 15 01 00 00 00 00 02 bf 01 + 15 01 00 00 00 00 02 c0 0b + 15 01 00 00 00 00 02 c1 01 + 15 01 00 00 00 00 02 c2 38 + 15 01 00 00 00 00 02 c3 01 + 15 01 00 00 00 00 02 c4 5b + 15 01 00 00 00 00 02 c5 01 + 15 01 00 00 00 00 02 c6 95 + 15 01 00 00 00 00 02 c7 01 + 15 01 00 00 00 00 02 c8 c4 + 15 01 00 00 00 00 02 c9 02 + 15 01 00 00 00 00 02 ca 0d + 15 01 00 00 00 00 02 cb 02 + 15 01 00 00 00 00 02 cc 4a + 15 01 00 00 00 00 02 cd 02 + 15 01 00 00 00 00 02 ce 4c + 15 01 00 00 00 00 02 cf 02 + 15 01 00 00 00 00 02 d0 85 + 15 01 00 00 00 00 02 d1 02 + 15 01 00 00 00 00 02 d2 c3 + 15 01 00 00 00 00 02 d3 02 + 15 01 00 00 00 00 02 d4 e9 + 15 01 00 00 00 00 02 d5 03 + 15 01 00 00 00 00 02 d6 16 + 15 01 00 00 00 00 02 d7 03 + 15 01 00 00 00 00 02 d8 34 + 15 01 00 00 00 00 02 d9 03 + 15 01 00 00 00 00 02 da 56 + 15 01 00 00 00 00 02 db 03 + 15 01 00 00 00 00 02 dc 62 + 15 01 00 00 00 00 02 dd 03 + 15 01 00 00 00 00 02 de 6c + 15 01 00 00 00 00 02 df 03 + 15 01 00 00 00 00 02 e0 74 + 15 01 00 00 00 00 02 e1 03 + 15 01 00 00 00 00 02 e2 80 + 15 01 00 00 00 00 02 e3 03 + 15 01 00 00 00 00 02 e4 89 + 15 01 00 00 00 00 02 e5 03 + 15 01 00 00 00 00 02 e6 8b + 15 01 00 00 00 00 02 e7 03 + 15 01 00 00 00 00 02 e8 8d + 15 01 00 00 00 00 02 e9 03 + 15 01 00 00 00 00 02 ea 8e + 15 01 00 00 00 00 02 FF 10 + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = + [15 01 00 00 00 00 02 ff 10 + 05 01 00 00 10 00 01 28 + 15 01 00 00 00 00 02 b0 00 + 05 01 00 00 40 00 01 10 + 15 01 00 00 00 00 02 4f 01]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi index 241aa71cd477bec83547c1310b296217f106b361..45ac042199155b14744aa2e73062ab43b56410a1 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi @@ -14,27 +14,12 @@ dsi_sim_cmd: qcom,mdss_dsi_sim_cmd{ qcom,mdss-dsi-panel-name = "Simulator cmd mode dsi panel"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <640>; - qcom,mdss-dsi-panel-height = <480>; - qcom,mdss-dsi-h-front-porch = <20>; - qcom,mdss-dsi-h-back-porch = <20>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-front-porch = <4>; - qcom,mdss-dsi-v-pulse-width = <1>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -42,11 +27,6 @@ qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-hor-line-idle = <0 40 256>, - <40 120 128>, - <120 240 64>; - qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03 - 04 00]; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; qcom,mdss-dsi-t-clk-post = <0x03>; qcom,mdss-dsi-t-clk-pre = <0x27>; @@ -58,39 +38,182 @@ qcom,mdss-dsi-wr-mem-continue = <0x3c>; qcom,mdss-dsi-te-dcs-command = <1>; qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; qcom,mdss-dsi-te-using-te-pin; qcom,mdss-dsi-panel-hdr-enabled; + qcom,ulps-enabled; qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 17000 15500 30000 8000 3000>; qcom,mdss-dsi-panel-peak-brightness = <4200000>; qcom,mdss-dsi-panel-blackness-level = <3230>; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03 - 05 01 00 00 0a 00 01 00 - /* Soft reset, wait 10ms */ - 15 01 00 00 0a 00 02 3a 77 - /* Set Pixel format (24 bpp) */ - 39 01 00 00 0a 00 05 2a 00 00 04 ff - /* Set Column address */ - 39 01 00 00 0a 00 05 2b 00 00 05 9f - /* Set page address */ - 15 01 00 00 0a 00 02 35 00 - /* Set tear on */ - 39 01 00 00 0a 00 03 44 00 00 - /* Set tear scan line */ - 15 01 00 00 0a 00 02 51 ff - /* write display brightness */ - 15 01 00 00 0a 00 02 53 24 - /* write control brightness */ - 15 01 00 00 0a 00 02 55 00 - /* CABC brightness */ - 05 01 00 00 78 00 01 11 - /* exit sleep mode, wait 120ms */ - 05 01 00 00 10 00 01 29]; - /* Set display on, wait 16ms */ - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + timing@1{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <460>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <740>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + timing@2{ + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <840>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <1380>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ceb68568fa9f6f8ada4789798c2c6869e57fd3ca --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi @@ -0,0 +1,286 @@ +/* Copyright (c) 2015-2017, 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. + */ + +&mdss_mdp { + dsi_sim_dsc_375_cmd: qcom,mdss_dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-panel-name = + "Simulator cmd mode DSC 3.75:1 dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi index 509547f31371791b241cbaf43c4875602b6f9b37..9a4e318ba7564c6bb8b6e1eb2721c102f96aef19 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi @@ -14,27 +14,12 @@ dsi_dual_sim_cmd: qcom,mdss_dsi_dual_sim_cmd { qcom,mdss-dsi-panel-name = "Sim dual cmd mode dsi panel"; qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1280>; - qcom,mdss-dsi-panel-height = <1440>; - qcom,mdss-dsi-h-front-porch = <120>; - qcom,mdss-dsi-h-back-porch = <44>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <4>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <4>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-color-order = "rgb_swap_rgb"; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -55,34 +40,82 @@ qcom,mdss-dsi-wr-mem-continue = <0x3c>; qcom,mdss-dsi-te-dcs-command = <1>; qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; qcom,mdss-dsi-te-using-te-pin; - qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03 - 05 01 00 00 0a 00 01 00 - /* Soft reset, wait 10ms */ - 15 01 00 00 0a 00 02 3a 77 - /* Set Pixel format (24 bpp) */ - 39 01 00 00 0a 00 05 2a 00 00 04 ff - /* Set Column address */ - 39 01 00 00 0a 00 05 2b 00 00 05 9f - /* Set page address */ - 15 01 00 00 0a 00 02 35 00 - /* Set tear on */ - 39 01 00 00 0a 00 03 44 00 00 - /* Set tear scan line */ - 15 01 00 00 0a 00 02 51 ff - /* write display brightness */ - 15 01 00 00 0a 00 02 53 24 - /* write control brightness */ - 15 01 00 00 0a 00 02 55 00 - /* CABC brightness */ - 05 01 00 00 78 00 01 11 - /* exit sleep mode, wait 120ms */ - 05 01 00 00 10 00 01 29]; - /* Set display on, wait 16ms */ - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + timing@1{ + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + timing@2{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <40>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5d977e7cb675b492e720a3aa16890931f9c549a1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi @@ -0,0 +1,281 @@ +/* Copyright (c) 2016-2017, 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. + */ + +&mdss_mdp { + dsi_dual_sim_dsc_375_cmd: qcom,mdss_dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-panel-name = + "Sim dual cmd mode DSC 3.75:1 dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-hor-line-idle = <0 40 256>, + <40 120 128>, + <120 240 64>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + timing@1 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi index cca28c7037f2fa6cdadd4321dfa961c07d93f4e7..dbfedb92865adc5e0dad289febb40371d5b6a76c 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi @@ -14,26 +14,11 @@ dsi_dual_sim_vid: qcom,mdss_dsi_dual_sim_video { qcom,mdss-dsi-panel-name = "Sim dual video mode dsi panel"; qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <1280>; - qcom,mdss-dsi-panel-height = <1440>; - qcom,mdss-dsi-h-front-porch = <120>; - qcom,mdss-dsi-h-back-porch = <44>; - qcom,mdss-dsi-h-pulse-width = <16>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <4>; - qcom,mdss-dsi-v-front-porch = <8>; - qcom,mdss-dsi-v-pulse-width = <4>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -45,11 +30,32 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; - qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>; qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi index 98a1f6126c7420ec50ae8a8c9b30c308d7703efb..40bedd0e462c83dd590563dc02c9c54d813d3363 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi @@ -14,22 +14,8 @@ dsi_sim_vid: qcom,mdss_dsi_sim_video { qcom,mdss-dsi-panel-name = "Simulator video mode dsi panel"; qcom,mdss-dsi-panel-type = "dsi_video_mode"; - qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; - qcom,mdss-dsi-panel-width = <640>; - qcom,mdss-dsi-panel-height = <480>; - qcom,mdss-dsi-h-front-porch = <8>; - qcom,mdss-dsi-h-back-porch = <8>; - qcom,mdss-dsi-h-pulse-width = <8>; - qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <6>; - qcom,mdss-dsi-v-front-porch = <6>; - qcom,mdss-dsi-v-pulse-width = <2>; - qcom,mdss-dsi-h-left-border = <0>; - qcom,mdss-dsi-h-right-border = <0>; - qcom,mdss-dsi-v-top-border = <0>; - qcom,mdss-dsi-v-bottom-border = <0>; qcom,mdss-dsi-bpp = <24>; qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-border-color = <0>; @@ -38,11 +24,6 @@ 17000 15500 30000 8000 3000>; qcom,mdss-dsi-panel-peak-brightness = <4200000>; qcom,mdss-dsi-panel-blackness-level = <3230>; - qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00]; - qcom,mdss-dsi-off-command = [22 01 00 00 00 00 02 00 00]; - qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-bllp-eof-power-mode; qcom,mdss-dsi-bllp-power-mode; @@ -50,13 +31,39 @@ qcom,mdss-dsi-lane-1-state; qcom,mdss-dsi-lane-2-state; qcom,mdss-dsi-lane-3-state; - qcom,mdss-dsi-panel-timings = - [00 00 00 00 00 00 00 00 00 00 00 00]; qcom,mdss-dsi-t-clk-post = <0x04>; qcom,mdss-dsi-t-clk-pre = <0x1b>; qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 0>, <0 0>, <1 0>; qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <640>; + qcom,mdss-dsi-panel-height = <480>; + qcom,mdss-dsi-h-front-porch = <8>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <6>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 00 00 00 00 00 00 00 00 00 00 00]; + qcom,mdss-dsi-on-command = + [32 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-off-command = + [22 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/external-soc.dtsi b/arch/arm64/boot/dts/qcom/external-soc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e6609c0dc4869e03f4215f5ec7850a76dee3b600 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/external-soc.dtsi @@ -0,0 +1,37 @@ +/* Copyright (c) 2017-2018, 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 { + mdm3: qcom,mdm3 { + compatible = "qcom,ext-sdxpoorwills"; + cell-index = <0>; + #address-cells = <0>; + interrupt-parent = <&mdm3>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-names = + "err_fatal_irq", + "status_irq", + "mdm2ap_vddmin_irq"; + /* modem attributes */ + qcom,ramdump-delays-ms = <2000>; + qcom,ramdump-timeout-ms = <120000>; + qcom,vddmin-modes = "normal"; + qcom,vddmin-drive-strength = <8>; + qcom,sfr-query; + qcom,sysmon-id = <20>; + qcom,ssctl-instance-id = <0x10>; + qcom,support-shutdown; + qcom,pil-force-shutdown; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi index c7cecbca39298e74ef6c898232dc7c599bdf087d..a57ea7c9e3e00e066f7cf2693a3f49b5f19b9664 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi @@ -11,71 +11,80 @@ */ qcom,ascent_3450mah { - /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Jan6th2017 */ + /* Ascent_wConn_Aging_3450mAh_averaged_MasterSlave_Jul11th2017 */ qcom,max-voltage-uv = <4350000>; qcom,fg-cc-cv-threshold-mv = <4340>; qcom,fastchg-current-ma = <3450>; qcom,batt-id-kohm = <60>; + qcom,jeita-fcc-ranges = <0 100 1725000 + 101 400 3450000 + 401 450 2760000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 101 400 4350000 + 401 450 4250000>; + qcom,step-chg-ranges = <3600000 4200000 3450000 + 4201000 4300000 2760000 + 4301000 4350000 2070000>; qcom,battery-beta = <3435>; - qcom,battery-type = "ascent_3450mah_averaged_masterslave_jan6th2017"; - qcom,checksum = <0x96AC>; - qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_oct30th2017"; + qcom,checksum = <0xAAE2>; + qcom,gui-version = "PMI8998GUI - 2.0.0.58"; qcom,fg-profile-data = [ - 9C 1F 85 05 - 82 0A 73 FC - 2B 1D 72 EA - EE 03 66 0C - C8 17 F4 22 - E0 45 1F 52 - 5C 00 00 00 - 10 00 00 00 - 00 00 4A C4 - C7 BC 48 C2 - 0F 00 08 00 - E1 DA 5D ED - 8D FD B2 F3 - 96 E2 A7 12 - 7E F4 0E 3B - 24 06 09 20 - 27 00 14 00 - 83 1F EE 05 - 1F 0A 45 FD - 6B 1D 53 E5 - EC 0B 31 14 - 44 18 49 23 - 18 45 A6 53 - 55 00 00 00 - 0E 00 00 00 - 00 00 61 CC - B7 C3 0F BC - 0F 00 00 00 - 92 00 5D ED - E3 06 E0 00 - 75 FD 9C 03 - 47 DB B3 22 - CB 33 CC FF - 07 10 00 00 - 99 0D 99 45 - 0F 00 40 00 - AB 01 0A FA - FF 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 - 00 00 00 00 + 8F 1F 94 05 + 73 0A 4A 06 + 27 1D 21 EA + 16 0A 3A 0C + 07 18 97 22 + A5 3C EC 4A + 5C 00 00 00 + 10 00 00 00 + 00 00 43 C5 + 92 BC 89 BB + 11 00 08 00 + 69 DA AD 07 + 4B FD 19 FA + 7E 01 49 13 + EB F3 78 3B + 24 06 09 20 + 27 00 14 00 + 7E 1F F2 05 + 19 0A AB 06 + 6C 1D B9 07 + 1A 12 FF 1D + 6F 18 EB 22 + B9 45 6F 52 + 55 00 00 00 + 0E 00 00 00 + 00 00 33 CC + 72 CA B3 C4 + 0F 00 00 00 + 93 00 AD 07 + 8D FD F6 00 + 6F E3 44 0B + AB FC F9 1B + C3 33 CC FF + 07 10 00 00 + A4 0D 99 45 + 0F 00 40 00 + A4 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 ]; }; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..95dd07ec58587314a4758d82ecbff1a0544082e2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi @@ -0,0 +1,81 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,gt3746a6_2900mah { + /* #GT3746A6_2900mAh_averaged_MasterSlave_May11th2017*/ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <2900>; + qcom,batt-id-kohm = <121>; + qcom,battery-beta = <3435>; + qcom,battery-type = "GT3746A6_2900mah_averaged_masterslave_may11th2017"; + qcom,checksum = <0xDF27>; + qcom,gui-version = "PMI8998GUI - 2.0.0.57"; + qcom,fg-profile-data = [ + C9 1F 44 05 + A5 0A 27 06 + F0 1C 07 01 + 49 F2 91 05 + C3 17 42 23 + 69 45 E8 52 + 58 00 00 00 + 0E 00 00 00 + 00 00 DF A2 + 12 CD 0C C3 + 19 00 08 00 + 89 C2 A5 ED + DF 05 1A 01 + C0 05 10 12 + 03 CA C2 32 + 32 06 09 20 + 27 00 14 00 + 69 20 CD 04 + F1 0A E3 05 + 12 1D 59 01 + A3 ED D1 05 + 95 18 27 23 + 35 45 6D 53 + 5F 00 00 00 + 0E 00 00 00 + 00 00 0A D5 + A6 B5 D0 D2 + 14 00 00 00 + 52 F2 A5 ED + 57 06 AA F2 + 29 F4 A5 0B + 4D FD FA 1A + AD 33 CC FF + 07 10 00 00 + 27 0B 99 45 + 14 00 40 00 + 26 02 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp356477-2800mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp356477-2800mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4720238ac8fa19b39c02adf52f7806ed3c2fe596 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp356477-2800mah.dtsi @@ -0,0 +1,88 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,mlp356477_2800mah { + /* #mlp356477_2800mah_averaged_MasterSlave_Aug14th2017*/ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <4200>; + qcom,batt-id-kohm = <82>; + qcom,battery-beta = <4250>; + qcom,jeita-fcc-ranges = <0 150 560000 + 151 450 4200000 + 451 550 2380000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + qcom,battery-type = + "mlp356477_2800mah_averaged_masterslave_aug14th2017"; + qcom,checksum = <0x71B8>; + qcom,gui-version = "PM660GUI - 0.0.0.44"; + qcom,fg-profile-data = [ + 60 1F BE 05 + 75 0A 40 06 + 81 1D F1 06 + B4 12 CC 1D + CF 18 2A 22 + 49 3D 4B 4A + 52 00 00 00 + 18 00 00 00 + 00 00 00 9C + 0C CC BA CA + 2B 00 08 00 + C5 E2 F9 ED + 30 05 D5 01 + 9E 06 62 12 + 4E E2 82 2B + 2D 06 09 20 + 27 00 14 00 + DD 1F 70 05 + 9E 0A 23 06 + 81 1D DD EC + 4C 12 D2 1D + DB 18 1F 23 + 3E 45 5E 53 + 52 00 00 00 + 0D 00 00 00 + 00 00 B8 D5 + 37 CA 89 BB + 25 00 00 00 + AE EA F9 ED + BF 05 9D FA + DD 05 3E 01 + B7 F5 8A 22 + C9 33 CC FF + 07 10 00 00 + 34 0B 66 46 + 25 00 40 00 + 87 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp446579-3800mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp446579-3800mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..75504d41321651a913cd2cc20cf1b2f5b69bbd5b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-mlp446579-3800mah.dtsi @@ -0,0 +1,87 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,mlp446579_3800mah { + /* #MLP446579_3800mAh_averaged_MasterSlave_Oct9th2017*/ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <3800>; + qcom,batt-id-kohm = <91>; + qcom,battery-beta = <4250>; + qcom,jeita-fcc-ranges = <0 150 760000 + 151 450 3800000 + 451 550 1900000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + qcom,battery-type = "mlp446579_3800mah_averaged_masterslave_oct9th2017"; + qcom,checksum = <0x3F0A>; + qcom,gui-version = "PMI8998GUI - 2.0.0.58"; + qcom,fg-profile-data = [ + 64 1F B8 05 + 8F 0A 0F 06 + A0 1D F3 FC + 41 13 70 1D + 1E 18 1E 23 + 92 45 88 52 + 52 00 00 00 + 12 00 00 00 + 00 00 04 00 + FD D4 68 C3 + 23 00 08 00 + C3 D2 52 DC + 33 05 BB FB + 84 05 BE 13 + 18 07 9E 2B + 21 06 09 20 + 27 00 14 00 + B7 1F A2 05 + 8E 0A 1C 06 + 7F 1D D9 ED + 20 12 FE 1D + F4 18 0A 23 + 4C 45 49 53 + 54 00 00 00 + 0E 00 00 00 + 00 00 F8 07 + 03 00 27 B2 + 1A 00 00 00 + FE E2 52 DC + FE 05 79 FA + 56 05 D5 FA + 27 F5 5C 22 + BC 33 CC FF + 07 10 00 00 + F0 0E 66 46 + 1A 00 40 00 + A7 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-8953.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-8953.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..49e840bec42ad78e644291f1ea5aa180d614939e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-8953.dtsi @@ -0,0 +1,104 @@ +/* + *Copyright (c) 2015-2018, 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 + +&soc { + kgsl_smmu: arm,smmu-kgsl@1c40000 { + status = "ok"; + compatible = "qcom,smmu-v2"; + qcom,tz-device-id = "GPU"; + reg = <0x1c40000 0x10000>; + #iommu-cells = <1>; + #global-interrupts = <0>; + interrupts = , + , + , + ; + qcom,dynamic; + qcom,use-3-lvl-tables; + qcom,enable-static-cb; + qcom,enable-smmu-halt; + qcom,skip-init; + vdd-supply = <&gdsc_oxili_cx>; + qcom,regulator-names = "vdd"; + clocks = <&clock_gcc_gfx clk_gcc_oxili_ahb_clk>, + <&clock_gcc_gfx clk_gcc_bimc_gfx_clk>; + clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk"; + }; + + /* A test device to test the SMMU operation */ + kgsl_iommu_test_device0 { + status = "disabled"; + compatible = "iommu-debug-test"; + /* The SID should be valid one to get the proper + *SMR,S2CR indices. + */ + iommus = <&kgsl_smmu 0x0>; + }; + + apps_iommu: qcom,iommu@1e00000 { + status = "okay"; + compatible = "qcom,qsmmu-v500"; + reg = <0x1e00000 0x40000>, + <0x1ee2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,tz-device-id = "APPS"; + qcom,skip-init; + qcom,enable-static-cb; + qcom,use-3-lvl-tables; + qcom,disable-atos; + #global-interrupts = <0>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&clock_gcc clk_gcc_smmu_cfg_clk>, + <&clock_gcc clk_gcc_apss_tcu_async_clk>; + clock-names = "iface_clk", "core_clk"; + }; +}; + +#include "msm-arm-smmu-impl-defs-8953.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8953.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8953.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2122db9237215cf8cf755cedee5ad9bcafd7283a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-impl-defs-8953.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&kgsl_smmu { + attach-impl-defs = <0x6000 0x270>, + <0x6060 0x1055>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x10800>, + <0x6930 0x400>, + <0x6960 0xffffffff>, + <0x6b64 0xa0000>, + <0x6b68 0xaaab92a>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ab088b89359e7351bd2dc066872121d1ff78a837 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi @@ -0,0 +1,340 @@ +/* Copyright (c) 2017, 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 +#include + +&soc { + kgsl_smmu: arm,smmu-kgsl@5040000 { + status = "ok"; + compatible = "qcom,smmu-v2"; + reg = <0x5040000 0x10000>; + #iommu-cells = <1>; + qcom,dynamic; + qcom,use-3-lvl-tables; + qcom,disable-atos; + #global-interrupts = <2>; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + interrupts = , + , + , + , + , + , + , + , + , + ; + clock-names = "gcc_gpu_memnoc_gfx_clk"; + clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + attach-impl-defs = + <0x6000 0x2378>, + <0x6060 0x1055>, + <0x678c 0x8>, + <0x6794 0x28>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x11000>, + <0x6930 0x800>, + <0x6960 0xffffffff>, + <0x6b64 0x1a5551>, + <0x6b68 0x9a82a382>; + }; + + apps_smmu: apps-smmu@0x15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x80000>, + <0x150c2000 0x18>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,no-asid-retention; + qcom,disable-atos; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + anoc_1_tbu: anoc_1_tbu@0x150c5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150c5000 0x1000>, + <0x150c2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu1_gdsc>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + anoc_2_tbu: anoc_2_tbu@0x150c9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150c9000 0x1000>, + <0x150c2208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu2_gdsc>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_0_tbu: mnoc_hf_0_tbu@0x150cd000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150cd000 0x1000>, + <0x150c2210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>; + qcom,msm-bus,name = "mnoc_hf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_1_tbu: mnoc_hf_1_tbu@0x150d1000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d1000 0x1000>, + <0x150c2218 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0xc00 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc>; + qcom,msm-bus,name = "mnoc_hf_1_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_sf_0_tbu: mnoc_sf_0_tbu@0x150d5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d5000 0x1000>, + <0x150c2220 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1000 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; + qcom,msm-bus,name = "mnoc_sf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + compute_dsp_tbu: compute_dsp_tbu@0x150d9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d9000 0x1000>, + <0x150c2228 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1400 0x400>; + /* No GDSC */ + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + adsp_tbu: adsp_tbu@0x150dd000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150dd000 0x1000>, + <0x150c2230 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1800 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + }; + + kgsl_iommu_test_device { + status = "disabled"; + compatible = "iommu-debug-test"; + /* + * 0x7 isn't a valid sid, but should pass the sid sanity check. + * We just need _something_ here to get this node recognized by + * the SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&kgsl_smmu 0x7>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to TSIF. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x20 0xf>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to TSIF. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x20 0xf>; + dma-coherent; + }; +}; + +&apps_smmu { + qcom,actlr = <0x0880 0x8 0x103>, + <0x0881 0x8 0x103>, + <0x0c80 0x8 0x103>, + <0x0c81 0x8 0x103>, + <0x1090 0x0 0x103>, + <0x1091 0x0 0x103>, + <0x10a0 0x8 0x103>, + <0x10b0 0x0 0x103>, + <0x10a1 0x8 0x103>, + <0x10a3 0x8 0x103>, + <0x10a4 0x8 0x103>, + <0x10b4 0x0 0x103>, + <0x10a5 0x8 0x103>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi index f1501fa0695c401e2aaf7475f107e2196b66c4dd..e4fe2e392ea2fe76a26c47d1760875da7ffbd80e 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi @@ -20,6 +20,8 @@ reg = <0x5040000 0x10000>; #iommu-cells = <1>; qcom,dynamic; + qcom,use-3-lvl-tables; + qcom,disable-atos; #global-interrupts = <2>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -33,14 +35,8 @@ , , ; - clock-names = "gcc_ddrss_gpu_axi_clk", - "gcc_gpu_memnoc_gfx_clk", - "gpu_cc_ahb_clk", - "gpu_cc_cx_gmu_clk"; - clocks = <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, - <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, - <&clock_gpucc GPU_CC_AHB_CLK>, - <&clock_gpucc GPU_CC_CX_GMU_CLK>; + clock-names = "gcc_gpu_memnoc_gfx_clk"; + clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; attach-impl-defs = <0x6000 0x2378>, <0x6060 0x1055>, @@ -61,8 +57,11 @@ reg = <0x15000000 0x80000>, <0x150c2000 0x20>; reg-names = "base", "tcu-base"; - #iommu-cells = <1>; + #iommu-cells = <2>; qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,no-asid-retention; + qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; #address-cells = <1>; @@ -145,7 +144,6 @@ <0 1000>; anoc_1_tbu: anoc_1_tbu@0x150c5000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150c5000 0x1000>, <0x150c2200 0x8>; @@ -167,7 +165,6 @@ }; anoc_2_tbu: anoc_2_tbu@0x150c9000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150c9000 0x1000>, <0x150c2208 0x8>; @@ -189,7 +186,6 @@ }; mnoc_hf_0_tbu: mnoc_hf_0_tbu@0x150cd000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150cd000 0x1000>, <0x150c2210 0x8>; @@ -211,7 +207,6 @@ }; mnoc_hf_1_tbu: mnoc_hf_1_tbu@0x150d1000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150d1000 0x1000>, <0x150c2218 0x8>; @@ -233,7 +228,6 @@ }; mnoc_sf_0_tbu: mnoc_sf_0_tbu@0x150d5000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150d5000 0x1000>, <0x150c2220 0x8>; @@ -255,7 +249,6 @@ }; compute_dsp_tbu: compute_dsp_tbu@0x150d9000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150d9000 0x1000>, <0x150c2228 0x8>; @@ -276,7 +269,6 @@ }; adsp_tbu: adsp_tbu@0x150dd000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150dd000 0x1000>, <0x150c2230 0x8>; @@ -298,7 +290,6 @@ }; anoc_1_pcie_tbu: anoc_1_pcie_tbu@0x150e1000 { - status = "disabled"; compatible = "qcom,qsmmuv500-tbu"; reg = <0x150e1000 0x1000>, <0x150c2238 0x8>; @@ -323,6 +314,7 @@ }; kgsl_iommu_test_device { + status = "disabled"; compatible = "iommu-debug-test"; /* * 0x7 isn't a valid sid, but should pass the sid sanity check. @@ -336,9 +328,37 @@ apps_iommu_test_device { compatible = "iommu-debug-test"; /* - * This SID belongs to PCIE. We can't use a fake SID for + * This SID belongs to TSIF. We can't use a fake SID for * the apps_smmu device. */ - iommus = <&apps_smmu 0x1c03>; + iommus = <&apps_smmu 0x20 0>; }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to TSIF. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x20 0>; + dma-coherent; + }; +}; + +&apps_smmu { + qcom,actlr = <0x0880 0x8 0x103>, + <0x0881 0x8 0x103>, + <0x0c80 0x8 0x103>, + <0x0c81 0x8 0x103>, + <0x1090 0x0 0x103>, + <0x1091 0x0 0x103>, + <0x10a0 0x8 0x103>, + <0x10b0 0x0 0x103>, + <0x10a1 0x8 0x103>, + <0x10a3 0x8 0x103>, + <0x10a4 0x8 0x103>, + <0x10b4 0x0 0x103>, + <0x10a5 0x8 0x103>; + qcom,mmu500-errata-1 = <0x800 0x3ff>, + <0xc00 0x3ff>; }; diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 4036ce5e5315d606f2f774a288c4bf222b795cad..b20feef88c3614a64cd849662f073bb05cfc56b0 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -85,7 +85,7 @@ compatible = "qcom,msm-pcm-loopback"; }; - qcom,msm-dai-mi2s { + msm_dai_mi2s: qcom,msm-dai-mi2s { compatible = "qcom,msm-dai-mi2s"; dai_mi2s0: qcom,msm-dai-q6-mi2s-prim { compatible = "qcom,msm-dai-q6-mi2s"; @@ -117,7 +117,7 @@ dai_mi2s4: qcom,msm-dai-q6-mi2s-quin { compatible = "qcom,msm-dai-q6-mi2s"; - qcom,msm-dai-q6-mi2s-dev-id = <5>; + qcom,msm-dai-q6-mi2s-dev-id = <4>; qcom,msm-mi2s-rx-lines = <1>; qcom,msm-mi2s-tx-lines = <2>; }; @@ -353,6 +353,20 @@ qcom,msm-cpudai-afe-clk-ver = <2>; }; + dai_quin_auxpcm: qcom,msm-quin-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "quinary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + hdmi_dba: qcom,msm-hdmi-dba-codec-rx { compatible = "qcom,msm-hdmi-dba-codec-rx"; qcom,dba-bridge-chip = "adv7533"; @@ -362,7 +376,7 @@ compatible = "qcom,msm-audio-ion"; qcom,smmu-version = <2>; qcom,smmu-enabled; - iommus = <&apps_smmu 0x1821>; + iommus = <&apps_smmu 0x1821 0x0>; }; qcom,msm-adsp-loader { @@ -377,14 +391,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36864>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36864>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -395,14 +410,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36865>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36865>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -413,14 +429,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36880>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36880>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -431,14 +448,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36881>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36881>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -449,14 +467,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36896>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36896>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -467,14 +486,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36897 >; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36897 >; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -485,14 +505,15 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36912>; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36912>; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -503,14 +524,53 @@ qcom,msm-cpudai-tdm-group-num-ports = <1>; qcom,msm-cpudai-tdm-group-port-id = <36913 >; qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36913 >; - qcom,msm-cpudai-tdm-sync-mode = <1>; - qcom,msm-cpudai-tdm-sync-src = <1>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <1>; - qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quin-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37184>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36928>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36928>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quin-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37185>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36929>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36929>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..49e148cddd16301ce8d08ff3298d1efe41ccb393 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-gdsc-8916.dtsi @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013-2015, 2017 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 { + gdsc_venus: qcom,gdsc@184c018 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus"; + reg = <0x184c018 0x4>; + status = "disabled"; + }; + + gdsc_mdss: qcom,gdsc@184d078 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_mdss"; + reg = <0x184d078 0x4>; + status = "disabled"; + }; + + gdsc_jpeg: qcom,gdsc@185701c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_jpeg"; + reg = <0x185701c 0x4>; + status = "disabled"; + }; + + gdsc_vfe: qcom,gdsc@1858034 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vfe"; + reg = <0x1858034 0x4>; + status = "disabled"; + }; + + gdsc_vfe1: qcom,gdsc@185806c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vfe1"; + reg = <0x185806c 0x4>; + status = "disabled"; + }; + + gdsc_cpp: qcom,gdsc@1858078 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_cpp"; + reg = <0x1858078 0x4>; + status = "disabled"; + }; + + gdsc_oxili_gx: qcom,gdsc@185901c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_oxili_gx"; + reg = <0x185901c 0x4>; + status = "disabled"; + }; + + gdsc_venus_core0: qcom,gdsc@184c028 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core0"; + reg = <0x184c028 0x4>; + status = "disabled"; + }; + + gdsc_venus_core1: qcom,gdsc@184c030 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core1"; + reg = <0x184c030 0x4>; + status = "disabled"; + }; + + gdsc_oxili_cx: qcom,gdsc@185904c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_oxili_cx"; + reg = <0x185904c 0x4>; + status = "disabled"; + }; + + gdsc_usb30: qcom,gdsc@183f078 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_usb30"; + reg = <0x183f078 0x4>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi index 84a6a84c0b1d0f6654054c75cc9a0a03f93f46aa..b43c87633365c2c050c620ebe5a727ac6b9ebb1e 100644 --- a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi @@ -181,6 +181,8 @@ qcom,poll-cfg-gdscr; qcom,support-hw-trigger; status = "disabled"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; }; /* GDSCs in Graphics CC */ @@ -196,26 +198,14 @@ hw-ctrl-addr = <&gpu_cx_hw_ctrl>; qcom,no-status-check-on-disable; qcom,gds-timeout = <500>; + qcom,clk-dis-wait-val = <8>; status = "disabled"; }; - gpu_gx_domain_addr: syscon@0x5091508 { - compatible = "syscon"; - reg = <0x5091508 0x4>; - }; - - gpu_gx_sw_reset: syscon@0x5091008 { - compatible = "syscon"; - reg = <0x5091008 0x4>; - }; - gpu_gx_gdsc: qcom,gdsc@0x509100c { compatible = "qcom,gdsc"; regulator-name = "gpu_gx_gdsc"; reg = <0x509100c 0x4>; - domain-addr = <&gpu_gx_domain_addr>; - sw-reset = <&gpu_gx_sw_reset>; - qcom,reset-aon-logic; qcom,poll-cfg-gdscr; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d9d1be428c71b498e5d652bdd2621cd2f7e2e4f2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi @@ -0,0 +1,106 @@ +/* Copyright (c) 2017, 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 { + smp2pgpio_rdbg_2_in: qcom,smp2pgpio-rdbg-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_2_in { + compatible = "qcom,smp2pgpio_client_rdbg_2_in"; + gpios = <&smp2pgpio_rdbg_2_in 0 0>; + }; + + smp2pgpio_rdbg_2_out: qcom,smp2pgpio-rdbg-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_2_out { + compatible = "qcom,smp2pgpio_client_rdbg_2_out"; + gpios = <&smp2pgpio_rdbg_2_out 0 0>; + }; + + smp2pgpio_rdbg_1_in: qcom,smp2pgpio-rdbg-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_1_in { + compatible = "qcom,smp2pgpio_client_rdbg_1_in"; + gpios = <&smp2pgpio_rdbg_1_in 0 0>; + }; + + smp2pgpio_rdbg_1_out: qcom,smp2pgpio-rdbg-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_1_out { + compatible = "qcom,smp2pgpio_client_rdbg_1_out"; + gpios = <&smp2pgpio_rdbg_1_out 0 0>; + }; + + smp2pgpio_rdbg_5_in: qcom,smp2pgpio-rdbg-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_5_in { + compatible = "qcom,smp2pgpio_client_rdbg_5_in"; + gpios = <&smp2pgpio_rdbg_5_in 0 0>; + }; + + smp2pgpio_rdbg_5_out: qcom,smp2pgpio-rdbg-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_5_out { + compatible = "qcom,smp2pgpio_client_rdbg_5_out"; + gpios = <&smp2pgpio_rdbg_5_out 0 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..57272a49abb9ba05b79ebd95958b63ec9091a86e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8937-regulator.dtsi @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&rpm_bus { + rpm-regulator-smpa1 { + status = "okay"; + pm8937_s1: regulator-s1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1000000>; + status = "okay"; + }; + }; + + /* VDD_CX supply */ + rpm-regulator-smpa2 { + status = "okay"; + pm8937_s2_level: regulator-s2-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s2_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pm8937_s2_floor_level: regulator-s2-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s2_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + pm8937_s2_level_ao: regulator-s2-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s2_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + }; + + rpm-regulator-smpa3 { + status = "okay"; + pm8937_s3: regulator-s3 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + qcom,init-voltage = <1300000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa4 { + status = "okay"; + pm8937_s4: regulator-s4 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + qcom,init-voltage = <2050000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa2 { + status = "okay"; + pm8937_l2: regulator-l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + /* VDD_MX supply */ + rpm-regulator-ldoa3 { + status = "okay"; + pm8937_l3_level_ao: regulator-l3-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l3_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + qcom,always-send-voltage; + }; + + pm8937_l3_level_so: regulator-l3-level-so { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l3_level_so"; + qcom,set = <2>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,use-voltage-level; + }; + }; + + rpm-regulator-ldoa5 { + status = "okay"; + pm8937_l5: regulator-l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + pm8937_l6: regulator-l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa7 { + status = "okay"; + pm8937_l7: regulator-l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + + pm8937_l7_ao: regulator-l7-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l7_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpm-regulator-ldoa8 { + status = "okay"; + pm8937_l8: regulator-l8 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2900000>; + qcom,init-voltage = <2900000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa9 { + status = "okay"; + pm8937_l9: regulator-l9 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <3000000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + pm8937_l10: regulator-l10 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <2800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + pm8937_l11: regulator-l11 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <2950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + pm8937_l12: regulator-l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + pm8937_l13: regulator-l13 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + qcom,init-voltage = <3075000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa14 { + status = "okay"; + pm8937_l14: regulator-l14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa15 { + status = "okay"; + pm8937_l15: regulator-l15 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa16 { + status = "okay"; + pm8937_l16: regulator-l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa17 { + status = "okay"; + pm8937_l17: regulator-l17 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2900000>; + qcom,init-voltage = <2800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa19 { + status = "okay"; + pm8937_l19: regulator-l19 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1350000>; + qcom,init-voltage = <1225000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa22 { + status = "okay"; + pm8937_l22: regulator-l22 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,init-voltage = <2800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa23 { + status = "okay"; + pm8937_l23: regulator-l23 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; +}; + +/* SPM controlled regulators */ +&spmi_bus { + qcom,pm8937@1 { + /* PM8937 S5 + S6 = VDD_APC supply */ + pm8937_s5: spm-regulator@2000 { + compatible = "qcom,spm-regulator"; + reg = <0x2000 0x100>; + regulator-name = "pm8937_s5"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1350000>; + }; + }; +}; + +&soc { + mem_acc_vreg_corner: regulator@01946004 { + compatible = "qcom,mem-acc-regulator"; + regulator-name = "mem_acc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <3>; + + qcom,acc-reg-addr-list = + <0x01942138 0x01942130 0x01942120 + 0x01942124 0x01946000 0x01946004>; + + qcom,acc-init-reg-config = <1 0xff>, <2 0x5555>, <6 0x55>; + + qcom,num-acc-corners = <3>; + qcom,boot-acc-corner = <2>; + qcom,corner1-reg-config = + /* SVS+ => SVS+ */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* SVS+ => NOM */ + < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>, + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* SVS+ => TURBO/NOM+ */ + < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>, + < 3 0x0>, < 4 0x0>, < 5 0x0>; + + qcom,corner2-reg-config = + /* NOM => SVS+ */ + < 3 0x30c30c3>, < 4 0x30c3>, < 5 0x6060606>, + /* NOM => NOM */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* NOM => TURBO/NOM+ */ + < 3 0x0>, < 4 0x0>, < 5 0x0>; + + qcom,corner3-reg-config = + /* TURBO/NOM+ => SVS+ */ + < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>, + < 3 0x30c30c3>, < 4 0x30c3>, < 5 0x6060606>, + /* TURBO/NOM+ => NOM */ + < 3 0x1041041>, < 4 0x1041>, < 5 0x2020202>, + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* TURBO/NOM+ => TURBO/NOM+ */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>; + }; + + apc_vreg_corner: regulator@b018000 { + compatible = "qcom,cpr-regulator"; + reg = <0xb018000 0x1000>, <0xb011064 4>, <0xa4000 0x1000>; + reg-names = "rbcpr", "rbcpr_clk", "efuse_addr"; + interrupts = <0 15 0>; + regulator-name = "apc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,cpr-fuse-corners = <3>; + qcom,cpr-voltage-ceiling = <1155000 1225000 1350000>; + qcom,cpr-voltage-floor = <1050000 1050000 1090000>; + vdd-apc-supply = <&pm8937_s5>; + + mem-acc-supply = <&mem_acc_vreg_corner>; + + qcom,cpr-ref-clk = <19200>; + qcom,cpr-timer-delay = <5000>; + qcom,cpr-timer-cons-up = <0>; + qcom,cpr-timer-cons-down = <2>; + qcom,cpr-irq-line = <0>; + qcom,cpr-step-quotient = <10>; + qcom,cpr-up-threshold = <2>; + qcom,cpr-down-threshold = <4>; + qcom,cpr-idle-clocks = <15>; + qcom,cpr-gcnt-time = <1>; + qcom,vdd-apc-step-up-limit = <1>; + qcom,vdd-apc-step-down-limit = <1>; + qcom,cpr-apc-volt-step = <5000>; + + qcom,cpr-fuse-row = <67 0>; + qcom,cpr-fuse-target-quot = <42 24 6>; + qcom,cpr-fuse-ro-sel = <60 57 54>; + qcom,cpr-init-voltage-ref = <1155000 1225000 1350000>; + qcom,cpr-fuse-init-voltage = + <67 36 6 0>, + <67 18 6 0>, + <67 0 6 0>; + qcom,cpr-fuse-quot-offset = + <71 26 6 0>, + <71 20 6 0>, + <70 54 7 0>; + qcom,cpr-fuse-quot-offset-scale = <5 5 5>; + qcom,cpr-init-voltage-step = <10000>; + qcom,cpr-corner-map = <1 2 3 3 3 3 3>; + qcom,cpr-corner-frequency-map = + <1 960000000>, + <2 1094400000>, + <3 1209600000>, + <4 1248000000>, + <5 1344000000>, + <6 1401000000>, + <7 1497600000>; + qcom,speed-bin-fuse-sel = <37 34 3 0>; + qcom,cpr-speed-bin-max-corners = + <0 0 1 2 6>, + <1 0 1 2 7>, + <2 0 1 2 3>; + qcom,cpr-fuse-revision = <69 39 3 0>; + qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>; + qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>; + qcom,cpr-scaled-init-voltage-as-ceiling; + qcom,cpr-fuse-version-map = + <0 (-1) 1 (-1) (-1) (-1)>, + <(-1) (-1) 2 (-1) (-1) (-1)>, + <(-1) (-1) 3 (-1) (-1) (-1)>, + <(-1) (-1) (-1) (-1) (-1) (-1)>; + qcom,cpr-quotient-adjustment = + <(-20) (-40) (-20)>, + <0 (-40) (20)>, + <0 0 (20)>, + <0 0 0>; + qcom,cpr-init-voltage-adjustment = + <0 0 0>, + <(10000) (15000) (20000)>, + <0 0 0>, + <0 0 0>; + qcom,cpr-enable; + }; + + eldo2_pm8937: eldo2 { + compatible = "regulator-fixed"; + regulator-name = "eldo2_pm8937"; + startup-delay-us = <0>; + enable-active-high; + gpio = <&pm8937_gpios 7 0>; + regulator-always-on; + }; + + adv_vreg: adv_vreg { + compatible = "regulator-fixed"; + regulator-name = "adv_vreg"; + startup-delay-us = <400>; + enable-active-high; + gpio = <&pm8937_gpios 8 0>; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-bus.dtsi b/arch/arm64/boot/dts/qcom/msm8953-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d1654f3d3b0bcf29a7652a5e436a57f8d307c982 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-bus.dtsi @@ -0,0 +1,1002 @@ +/* Copyright (c) 2015-2017, 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 + +&soc { + /*Version = 11 */ + ad_hoc_bus: ad-hoc-bus@580000 { + compatible = "qcom,msm-bus-device"; + reg = <0x580000 0x16080>, + <0x580000 0x16080>, + <0x400000 0x5A000>, + <0x500000 0x12080>; + reg-names = "snoc-base", "snoc-mm-base", + "bimc-base", "pcnoc-base"; + + /*Buses*/ + + fab_bimc: fab-bimc { + cell-id = ; + label = "fab-bimc"; + qcom,fab-dev; + qcom,base-name = "bimc-base"; + qcom,bus-type = <2>; + qcom,util-fact = <153>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_gcc clk_bimc_msmbus_clk>, + <&clock_gcc clk_bimc_msmbus_a_clk>; + }; + + fab_pcnoc: fab-pcnoc { + cell-id = ; + label = "fab-pcnoc"; + qcom,fab-dev; + qcom,base-name = "pcnoc-base"; + qcom,base-offset = <0x7000>; + qcom,qos-off = <0x1000>; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_gcc clk_pcnoc_msmbus_clk>, + <&clock_gcc clk_pcnoc_msmbus_a_clk>; + + qcom,node-qos-clks { + clock-names = "pcnoc-usb3-axi-no-rate"; + clocks = + <&clock_gcc clk_gcc_pcnoc_usb3_axi_clk>; + }; + }; + + fab_snoc: fab-snoc { + cell-id = ; + label = "fab-snoc"; + qcom,fab-dev; + qcom,base-name = "snoc-base"; + qcom,base-offset = <0x7000>; + qcom,qos-off = <0x1000>; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_gcc clk_snoc_msmbus_clk>, + <&clock_gcc clk_snoc_msmbus_a_clk>; + }; + + fab_snoc_mm: fab-snoc-mm { + cell-id = ; + label = "fab-snoc-mm"; + qcom,fab-dev; + qcom,base-name = "snoc-mm-base"; + qcom,base-offset = <0x7000>; + qcom,qos-off = <0x1000>; + qcom,bus-type = <1>; + qcom,util-fact = <153>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_gcc clk_sysmmnoc_msmbus_clk>, + <&clock_gcc clk_sysmmnoc_msmbus_a_clk>; + }; + + /*Masters*/ + + mas_apps_proc: mas-apps-proc { + cell-id = ; + label = "mas-apps-proc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_oxili: mas-oxili { + cell-id = ; + label = "mas-oxili"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_0: mas-snoc-bimc-0 { + cell-id = ; + label = "mas-snoc-bimc-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <3>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_2: mas-snoc-bimc-2 { + cell-id = ; + label = "mas-snoc-bimc-2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_1: mas-snoc-bimc-1 { + cell-id = ; + label = "mas-snoc-bimc-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_tcu_0: mas-tcu-0 { + cell-id = ; + label = "mas-tcu-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <6>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <2>; + qcom,prio-rd = <2>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_spdm: mas-spdm { + cell-id = ; + label = "mas-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&pcnoc_m_0>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_blsp_1: mas-blsp-1 { + cell-id = ; + label = "mas-blsp-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&pcnoc_m_1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_blsp_2: mas-blsp-2 { + cell-id = ; + label = "mas-blsp-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&pcnoc_m_1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_usb3: mas-usb3 { + cell-id = ; + label = "mas-usb3"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <11>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_1>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_crypto: mas-crypto { + cell-id = ; + label = "mas-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_1>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_sdcc_1: mas-sdcc-1 { + cell-id = ; + label = "mas-sdcc-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_sdcc_2: mas-sdcc-2 { + cell-id = ; + label = "mas-sdcc-2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_pcnoc: mas-snoc-pcnoc { + cell-id = ; + label = "mas-snoc-pcnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <9>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_2>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + }; + + /*SNOC Masters*/ + mas_qdss_bam: mas-qdss-bam { + cell-id = ; + label = "mas-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <11>; + qcom,qos-mode = "fixed"; + qcom,connections = <&qdss_int>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_bimc_snoc: mas-bimc-snoc { + cell-id = ; + label = "mas-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&snoc_int_0 + &snoc_int_1 &snoc_int_2>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_jpeg: mas-jpeg { + cell-id = ; + label = "mas-jpeg"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <6>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_snoc_bimc_2>; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,mas-rpm-id = ; + }; + + mas_mdp: mas-mdp { + cell-id = ; + label = "mas-mdp"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <7>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_snoc_bimc_0>; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,mas-rpm-id = ; + }; + + mas_pcnoc_snoc: mas-pcnoc-snoc { + cell-id = ; + label = "mas-pcnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,qos-mode = "fixed"; + qcom,connections = <&snoc_int_0 + &snoc_int_1 &slv_snoc_bimc_1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + qcom,blacklist = <&slv_snoc_pcnoc>; + }; + + mas_venus: mas-venus { + cell-id = ; + label = "mas-venus"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <8>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_snoc_bimc_2>; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,mas-rpm-id = ; + }; + + mas_vfe0: mas-vfe0 { + cell-id = ; + label = "mas-vfe0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <9>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_snoc_bimc_0>; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,mas-rpm-id = ; + }; + + mas_vfe1: mas-vfe1 { + cell-id = ; + label = "mas-vfe1"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <13>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_snoc_bimc_0>; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,mas-rpm-id = ; + }; + + mas_cpp: mas-cpp { + cell-id = ; + label = "mas-cpp"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <12>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_snoc_bimc_2>; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,mas-rpm-id = ; + }; + + mas_ipa: mas-ipa { + cell-id = ; + label = "mas-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <14>; + qcom,qos-mode = "fixed"; + qcom,connections = <&snoc_int_0 + &snoc_int_1 &slv_snoc_bimc_1>; + qcom,prio1 = <0>; + qcom,prio0 = <0>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_qdss_etr: mas-qdss-etr { + cell-id = ; + label = "mas-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <10>; + qcom,qos-mode = "fixed"; + qcom,connections = <&qdss_int>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + /*Internal nodes*/ + pcnoc_m_0: pcnoc-m-0 { + cell-id = ; + label = "pcnoc-m-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <5>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_1>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_m_1: pcnoc-m-1 { + cell-id = ; + label = "pcnoc-m-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,qos-mode = "fixed"; + qcom,connections = <&pcnoc_int_1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_int_1: pcnoc-int-1 { + cell-id = ; + label = "pcnoc-int-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&pcnoc_int_2 &slv_pcnoc_snoc>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_int_2: pcnoc-int-2 { + cell-id = ; + label = "pcnoc-int-2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&pcnoc_s_1 &pcnoc_s_2 + &pcnoc_s_0 &pcnoc_s_4 &pcnoc_s_6 + &pcnoc_s_7 &pcnoc_s_8 &pcnoc_s_9 + &slv_tcu &slv_gpu_cfg &pcnoc_s_3>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_0: pcnoc-s-0 { + cell-id = ; + label = "pcnoc-s-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_pdm &slv_spdm>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_1: pcnoc-s-1 { + cell-id = ; + label = "pcnoc-s-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_tcsr>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_2: pcnoc-s-2 { + cell-id = ; + label = "pcnoc-s-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_snoc_cfg>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_3: pcnoc-s-3 { + cell-id = ; + label = "pcnoc-s-3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_tlmm &slv_prng &slv_blsp_1 + &slv_blsp_2 &slv_message_ram>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_4: pcnoc-s-4 { + cell-id = ; + label = "pcnoc-s-4"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_camera_ss_cfg + &slv_disp_ss_cfg &slv_venus_cfg>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_6: pcnoc-s-6 { + cell-id = ; + label = "pcnoc-s-6"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_crypto_0_cfg + &slv_sdcc_2 &slv_sdcc_1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_7: pcnoc-s-7 { + cell-id = ; + label = "pcnoc-s-7"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_pmic_arb>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_8: pcnoc-s-8 { + cell-id = ; + label = "pcnoc-s-8"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_usb3>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + pcnoc_s_9: pcnoc-s-9 { + cell-id = ; + label = "pcnoc-s-9"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_ipa_cfg>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + qdss_int: qdss-int { + cell-id = ; + label = "qdss-int"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&snoc_int_1 &slv_snoc_bimc_1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + snoc_int_0: snoc-int-0 { + cell-id = ; + label = "snoc-int-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_lpass + &slv_wcss &slv_kpss_ahb>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + snoc_int_1: snoc-int-1 { + cell-id = ; + label = "snoc-int-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qdss_stm &slv_imem + &slv_snoc_pcnoc>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + snoc_int_2: snoc-int-2 { + cell-id = ; + label = "snoc-int-2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_cats_0 &slv_cats_1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + qcom,slv-rpm-id = ; + }; + + /*Slaves*/ + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_bimc_snoc:slv-bimc-snoc { + cell-id = ; + label = "slv-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,connections = <&mas_bimc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_spdm:slv-spdm { + cell-id = ; + label = "slv-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_pdm:slv-pdm { + cell-id = ; + label = "slv-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tcsr:slv-tcsr { + cell-id = ; + label = "slv-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cfg:slv-snoc-cfg { + cell-id = ; + label = "slv-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tlmm:slv-tlmm { + cell-id = ; + label = "slv-tlmm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_message_ram:slv-message-ram { + cell-id = ; + label = "slv-message-ram"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_blsp_1:slv-blsp-1 { + cell-id = ; + label = "slv-blsp-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_blsp_2:slv-blsp-2 { + cell-id = ; + label = "slv-blsp-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_prng:slv-prng { + cell-id = ; + label = "slv-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_camera_ss_cfg:slv-camera-ss-cfg { + cell-id = ; + label = "slv-camera-ss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_disp_ss_cfg:slv-disp-ss-cfg { + cell-id = ; + label = "slv-disp-ss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_venus_cfg:slv-venus-cfg { + cell-id = ; + label = "slv-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_gpu_cfg:slv-gpu-cfg { + cell-id = ; + label = "slv-gpu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_sdcc_1:slv-sdcc-1 { + cell-id = ; + label = "slv-sdcc-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_sdcc_2:slv-sdcc-2 { + cell-id = ; + label = "slv-sdcc-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_crypto_0_cfg:slv-crypto-0-cfg { + cell-id = ; + label = "slv-crypto-0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_pmic_arb:slv-pmic-arb { + cell-id = ; + label = "slv-pmic-arb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_usb3:slv-usb3 { + cell-id = ; + label = "slv-usb3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_ipa_cfg:slv-ipa-cfg { + cell-id = ; + label = "slv-ipa-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tcu:slv-tcu { + cell-id = ; + label = "slv-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_pcnoc_snoc:slv-pcnoc-snoc { + cell-id = ; + label = "slv-pcnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_pcnoc>; + qcom,connections = <&mas_pcnoc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_kpss_ahb:slv-kpss-ahb { + cell-id = ; + label = "slv-kpss-ahb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_wcss:slv-wcss { + cell-id = ; + label = "slv-wcss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_0:slv-snoc-bimc-0 { + cell-id = ; + label = "slv-snoc-bimc-0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,connections = <&mas_snoc_bimc_0>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_1:slv-snoc-bimc-1 { + cell-id = ; + label = "slv-snoc-bimc-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,connections = <&mas_snoc_bimc_1>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_2:slv-snoc-bimc-2 { + cell-id = ; + label = "slv-snoc-bimc-2"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,connections = <&mas_snoc_bimc_2>; + qcom,slv-rpm-id = ; + }; + + slv_imem:slv-imem { + cell-id = ; + label = "slv-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_pcnoc:slv-snoc-pcnoc { + cell-id = ; + label = "slv-snoc-pcnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,connections = <&mas_snoc_pcnoc>; + qcom,slv-rpm-id = ; + }; + + slv_qdss_stm:slv-qdss-stm { + cell-id = ; + label = "slv-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_cats_0:slv-cats-0 { + cell-id = ; + label = "slv-cats-0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc_mm>; + qcom,slv-rpm-id = ; + }; + + slv_cats_1:slv-cats-1 { + cell-id = ; + label = "slv-cats-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_lpass:slv-lpass { + cell-id = ; + label = "slv-lpass"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + }; + + devfreq_spdm_cpu { + compatible = "qcom,devfreq_spdm"; + qcom,msm-bus,name = "devfreq_spdm"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 512 0 0>, + <1 512 0 0>; + qcom,msm-bus,active-only; + qcom,spdm-client = <0>; + + clock-names = "cci_clk"; + clocks = <&clock_cpu clk_cci_clk>; + + qcom,bw-upstep = <400>; + qcom,bw-dwnstep = <4200>; + qcom,max-vote = <4200>; + qcom,up-step-multp = <2>; + qcom,spdm-interval = <30>; + + qcom,ports = <11>; + qcom,alpha-up = <8>; + qcom,alpha-down = <15>; + qcom,bucket-size = <8>; + + /*max pl1 freq, max pl2 freq*/ + qcom,pl-freqs = <230000 770000>; + + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,reject-rate = <5000 5000 5000 5000 5000 5000>; + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,response-time-us = <6000 6000 4000 4000 2000 2000>; + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,cci-response-time-us = <4000 4000 3000 3000 2000 2000>; + qcom,max-cci-freq = <870000>; + }; + + devfreq_spdm_gov { + compatible = "qcom,gov_spdm_hyp"; + interrupt-names = "spdm-irq"; + interrupts = <0 192 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..03ec7b5756184ed0379a2f9c95e3bb35f54595dd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-cdp.dtsi" + +/ { + model = "CDP 1200P"; + qcom,board-id = <1 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p.dts new file mode 100644 index 0000000000000000000000000000000000000000..96e364fc4375620fb007b27f41f229977fb1242b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 CDP 1200P"; + compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp"; + qcom,board-id= <1 1>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm830-cdp.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts similarity index 68% rename from arch/arm64/boot/dts/qcom/sdm830-cdp.dts rename to arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts index dab4a9d122eda47760015c0548e8f2734c25bd3d..145a40c164d77eacbb0b040f29749e8fe90fe94a 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-cdp.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,14 +11,12 @@ * GNU General Public License for more details. */ - /dts-v1/; +/plugin/; -#include "sdm830.dtsi" -#include "sdm830-cdp.dtsi" +#include "msm8953-cdp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM bat v1 CDP"; - compatible = "qcom,sdm830-cdp", "qcom,sdm830", "qcom,cdp"; + model = "CDP"; qcom,board-id = <1 0>; }; diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..34c5f8f746ebdd5246ed146fe9b3e5e1d41a14a2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 CDP"; + compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..87b8c7439af028138e87a0ec0eef75156aaccb2c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&blsp1_uart0 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm8953_l8>; + qcom,vdd-voltage-level = <2900000 2900000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8953_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 + 384000000>; + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm8953_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8953_l12>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 133 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 133 0x1>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..55914d00a6cfa90e08de57df714b08d15b3433c3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-coresight.dtsi @@ -0,0 +1,1240 @@ +/* + * Copyright (c) 2015-2017, 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 an + * 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 { + tmc_etr: tmc@6028000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6028000 0x1000>, + <0x6044000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + interrupts = <0 166 0>; + interrupt-names = "byte-cntr-irq"; + + arm,buffer-size = <0x100000>; + arm,sg-enable; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti8>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6027000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6027000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + + arm,default-sink; + coresight-ctis = <&cti0 &cti8>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + tmc_etf_out_replicator:endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_tmc_etf>; + }; + }; + }; + }; + + replicator: replicator@6026000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6026000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + replicator_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + funnel_in0: funnel@6021000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6021000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_in0_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_in0>; + }; + }; + + port@1 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + + port@2 { + reg = <6>; + funnel_in0_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_in0>; + }; + }; + + port@3 { + reg = <3>; + funnel_in0_in_funnel_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_center_out_funnel_in0>; + }; + }; + + port@4 { + reg = <4>; + funnel_in0_in_funnel_right: endpoint { + slave-mode; + remote-endpoint = + <&funnel_right_out_funnel_in0>; + }; + }; + + port@5 { + reg = <5>; + funnel_in0_in_funnel_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_mm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_center: funnel@6100000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6100000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-center"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_center_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_center>; + }; + }; + + port@1 { + reg = <0>; + funnel_center_in_rpm_etm0: endpoint { + slave-mode; + remote-endpoint = + <&rpm_etm0_out_funnel_center>; + }; + }; + + port@2 { + reg = <2>; + funnel_center_in_dbgui: endpoint { + slave-mode; + remote-endpoint = + <&dbgui_out_funnel_center>; + }; + }; + }; + }; + + funnel_right: funnel@6120000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6120000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-right"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_right_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_right>; + }; + }; + + port@1 { + reg = <1>; + funnel_right_in_modem_etm1: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm1_out_funnel_right>; + }; + }; + + port@2 { + reg = <2>; + funnel_right_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_right>; + }; + }; + + port@3 { + reg = <3>; + funnel_right_in_funnel_apss1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss1_out_funnel_right>; + }; + }; + }; + }; + + funnel_mm: funnel@6130000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6130000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-mm"; + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_mm_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_mm_in_wcn_etm0: endpoint { + slave-mode; + remote-endpoint = + <&wcn_etm0_out_funnel_mm>; + }; + }; + + port@2 { + reg = <4>; + funnel_mm_in_funnel_cam: endpoint { + slave-mode; + remote-endpoint = + <&funnel_cam_out_funnel_mm>; + }; + }; + + port@3 { + reg = <5>; + funnel_mm_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_mm>; + }; + }; + }; + }; + + funnel_cam: funnel@6132000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6132000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-cam"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + funnel_cam_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_mm_in_funnel_cam>; + }; + }; + }; + + funnel_apss1: funnel@61d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x61d0000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss1"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_apss1_out_funnel_right: endpoint { + remote-endpoint = + <&funnel_right_in_funnel_apss1>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss1_in_funnel_apss0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss0_out_funnel_apss1>; + }; + }; + }; + }; + + funnel_apss0: funnel@61a1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x61a1000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_apss0_out_funnel_apss1: endpoint { + remote-endpoint = + <&funnel_apss1_in_funnel_apss0>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss0_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss0>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss0_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss0>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss0_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss0>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss0_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss0>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss0_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss0>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss0_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss0>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss0_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss0>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss0_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss0>; + }; + }; + }; + }; + + etm0: etm@619c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x619c000 0x1000>; + cpu = <&CPU0>; + coresight-name = "coresight-etm0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm0>; + }; + }; + }; + + etm1: etm@619d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x619d000 0x1000>; + cpu = <&CPU1>; + coresight-name = "coresight-etm1"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm1>; + }; + }; + }; + + etm2: etm@619e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x619e000 0x1000>; + cpu = <&CPU2>; + coresight-name = "coresight-etm2"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm2>; + }; + }; + }; + + etm3: etm@619f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x619f000 0x1000>; + cpu = <&CPU3>; + coresight-name = "coresight-etm3"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm3>; + }; + }; + }; + + etm4: etm@61bc000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bc000 0x1000>; + cpu = <&CPU4>; + coresight-name = "coresight-etm4"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm4>; + }; + }; + }; + + etm5: etm@61bd000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bd000 0x1000>; + cpu = <&CPU5>; + coresight-name = "coresight-etm5"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm5>; + }; + }; + }; + + etm6: etm@61be000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61be000 0x1000>; + cpu = <&CPU6>; + coresight-name = "coresight-etm6"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm6>; + }; + }; + }; + + etm7: etm@61bf000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bf000 0x1000>; + coresight-name = "coresight-etm7"; + cpu = <&CPU7>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm7>; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x9280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti1"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti2"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti3"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti4"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti5"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti6"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti7"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti8"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti9"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti10"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti11"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti12"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti13"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti14"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti15"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu0: cti@6198000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6198000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu1: cti@6199000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6199000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@619a000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x619a000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@619b000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x619b000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu4: cti@61b8000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b8000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@61b9000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b9000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@61ba000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61ba000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@61bb000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61bb000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_modem_cpu0: cti@6128000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6128000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-modem-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_modem_cpu1: cti@6124000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6124000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-modem-cpu1"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* Venus CTI */ + cti_video_cpu0: cti@6134000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6134000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-video-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* Pronto CTI */ + cti_wcn_cpu0: cti@6139000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6139000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-wcn-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* LPASS CTI */ + cti_audio_cpu0: cti@613c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x613c000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-audio-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_rpm_cpu0: cti@610c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x610c000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-rpm-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* Pronto ETM */ + wcn_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-wcn-etm0"; + qcom,inst-id = <3>; + + port { + wcn_etm0_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_mm_in_wcn_etm0>; + }; + }; + }; + + rpm_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-rpm-etm0"; + qcom,inst-id = <4>; + + port { + rpm_etm0_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_rpm_etm0>; + }; + }; + }; + + /* LPASS ETM */ + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_mm_in_audio_etm0>; + }; + }; + }; + + /* MSS_SCL */ + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <11>; + + port { + modem_etm0_out_funnel_right: endpoint { + remote-endpoint = <&funnel_right_in_modem_etm0>; + }; + }; + }; + + /* MSS_VEC */ + modem_etm1 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm1"; + qcom,inst-id = <2>; + + port { + modem_etm1_out_funnel_right: endpoint { + remote-endpoint = <&funnel_right_in_modem_etm1>; + }; + }; + }; + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + coresight-name = "coresight-csr"; + + qcom,blk-size = <1>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + dbgui: dbgui@6108000 { + compatible = "qcom,coresight-dbgui"; + reg = <0x6108000 0x1000>; + reg-names = "dbgui-base"; + coresight-name = "coresight-dbgui"; + + qcom,dbgui-addr-offset = <0x30>; + qcom,dbgui-data-offset = <0x130>; + qcom,dbgui-size = <64>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + dbgui_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_dbgui>; + }; + }; + }; + + tpda: tpda@6003000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + + reg = <0x6003000 0x1000>; + reg-names = "tpda-base"; + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <64>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + tpda_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_tpda>; + }; + }; + + port@1 { + reg = <0>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + }; + }; + + tpdm_dcc: tpdm@6110000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6110000 0x1000>; + reg-names = "tpdm-base"; + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + hwevent: hwevent@6101000 { + compatible = "qcom,coresight-hwevent"; + + reg = <0x6101000 0x148>, + <0x6101fb0 0x4>, + <0x6121000 0x148>, + <0x6121fb0 0x4>, + <0x6131000 0x148>, + <0x6131fb0 0x4>, + <0x7105010 0x4>, + <0x7885010 0x4>; + + reg-names = "center-wrapper-mux", "center-wrapper-lockaccess", + "right-wrapper-mux", "right-wrapper-lockaccess", + "mm-wrapper-mux", "mm-wrapper-lockaccess", + "usbbam-mux", "blsp-mux"; + + coresight-name = "coresight-hwevent"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..42d21f42e52dfe626039bbae0ad7947c8c99205c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2015-2018, 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. + */ + +/ { + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + core1 { + cpu = <&CPU5>; + }; + core2 { + cpu = <&CPU6>; + }; + core3 { + cpu = <&CPU7>; + }; + }; + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0>; + enable-method = "psci"; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + /* A53 L2 dump not supported */ + qcom,dump-size = <0x0>; + }; + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x1>; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L1_I_1: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_1: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x2>; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L1_I_2: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_2: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x3>; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L1_I_3: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_3: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x100>; + efficiency = <1126>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + #cooling-cells = <2>; + L2_1: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + /* A53 L2 dump not supported */ + qcom,dump-size = <0x0>; + }; + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x101>; + efficiency = <1126>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + #cooling-cells = <2>; + L1_I_101: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_101: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x102>; + efficiency = <1126>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + #cooling-cells = <2>; + L1_I_102: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_102: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x103>; + efficiency = <1126>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + #cooling-cells = <2>; + L1_I_103: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x8800>; + }; + L1_D_103: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9000>; + }; + }; + }; + + energy_costs: energy-costs { + compatible = "sched-energy"; + + CPU_COST_0: core-cost0 { + busy-cost-data = < + 652800 5 + 883200 8 + 1036800 10 + 1248000 13 + 1401600 16 + 1536000 19 + 1689600 22 + 1804800 26 + 1843200 27 + 1958400 33 + 2016000 36 + 2150400 43 + 2208000 44 + 2304000 54 + 2400000 65 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 652800 69 + 883200 72 + 1036800 74 + 1248000 77 + 1401600 80 + 1536000 90 + 1689600 100 + 1804800 110 + 1843200 120 + 1958400 130 + 2016000 140 + 2150400 150 + 2208000 160 + 2304000 170 + 2400000 180 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 652800 5 + 883200 8 + 1036800 10 + 1248000 13 + 1401600 16 + 1536000 85 + 1689600 95 + 1804800 105 + 1843200 115 + 1958400 125 + 2016000 135 + 2150400 145 + 2208000 155 + 2304000 165 + 2400000 175 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + }; +}; + +&soc { + cpuss_dump: cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,l2_dump0 { + /* L2 cache dump for A53 cluster */ + qcom,dump-node = <&L2_0>; + qcom,dump-id = <0xC0>; + }; + qcom,l2_dump1 { + /* L2 cache dump for A53 cluster */ + qcom,dump-node = <&L2_1>; + qcom,dump-id = <0xC1>; + }; + qcom,l1_i_cache0 { + qcom,dump-node = <&L1_I_0>; + qcom,dump-id = <0x60>; + }; + qcom,l1_i_cache1 { + qcom,dump-node = <&L1_I_1>; + qcom,dump-id = <0x61>; + }; + qcom,l1_i_cache2 { + qcom,dump-node = <&L1_I_2>; + qcom,dump-id = <0x62>; + }; + qcom,l1_i_cache3 { + qcom,dump-node = <&L1_I_3>; + qcom,dump-id = <0x63>; + }; + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x64>; + }; + qcom,l1_i_cache101 { + qcom,dump-node = <&L1_I_101>; + qcom,dump-id = <0x65>; + }; + qcom,l1_i_cache102 { + qcom,dump-node = <&L1_I_102>; + qcom,dump-id = <0x66>; + }; + qcom,l1_i_cache103 { + qcom,dump-node = <&L1_I_103>; + qcom,dump-id = <0x67>; + }; + qcom,l1_d_cache0 { + qcom,dump-node = <&L1_D_0>; + qcom,dump-id = <0x80>; + }; + qcom,l1_d_cache1 { + qcom,dump-node = <&L1_D_1>; + qcom,dump-id = <0x81>; + }; + qcom,l1_d_cache2 { + qcom,dump-node = <&L1_D_2>; + qcom,dump-id = <0x82>; + }; + qcom,l1_d_cache3 { + qcom,dump-node = <&L1_D_3>; + qcom,dump-id = <0x83>; + }; + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x84>; + }; + qcom,l1_d_cache101 { + qcom,dump-node = <&L1_D_101>; + qcom,dump-id = <0x85>; + }; + qcom,l1_d_cache102 { + qcom,dump-node = <&L1_D_102>; + qcom,dump-id = <0x86>; + }; + qcom,l1_d_cache103 { + qcom,dump-node = <&L1_D_103>; + qcom,dump-id = <0x87>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..08a343ed3182f1d027cc733feffa93d1f010500f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-mtp.dtsi" + +/ { + model = "Ext Codec MTP"; + qcom,board-id= <8 1>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..b80583e6907a6ce45f3af3f58d0f7051390c5386 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 Ext Codec MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 1>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..45fdf06fdf3ff1568c0d2a31c8cb4eb79b5c72d6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-cdp.dtsi" + +/ { + model = "Ext Codec RCM"; + qcom,board-id = <21 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..d4224a4ba6fbf267489a396f0bb45a90b9d7aeb7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 Ext Codec RCM"; + compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp"; + qcom,board-id= <21 1>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5cf6eb2f489090c97a7932b245d6ebfd4aba2ea3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi @@ -0,0 +1,273 @@ +/* Copyright (c) 2018, 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 { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a506_zap"; + memory-region = <&gpu_mem>; + qcom,mas-crypto = <&mas_crypto>; + clocks = <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>, + <&clock_gcc clk_crypto_clk_src>; + clock-names = "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,scm_core_clk_src-freq = <80000000>; + }; + + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + /* + * active-only flag is used while registering the bus + * governor.It helps release the bus vote when the CPU + * subsystem is inactiv3 + */ + qcom,active-only; + qcom,bw-tbl = + < 0 >, /* off */ + < 1611 >, /* 1. DDR:211.20 MHz BIMC: 105.60 MHz */ + < 2124 >, /* 2. DDR:278.40 MHz BIMC: 139.20 MHz */ + < 2929 >, /* 3. DDR:384.00 MHz BIMC: 192.00 MHz */ + < 3222 >, /* 4. DDR:422.40 MHz BIMC: 211.20 MHz */ + < 4248 >, /* 5. DDR:556.80 MHz BIMC: 278.40 MHz */ + < 5126 >, /* 6. DDR:672.00 MHz BIMC: 336.00 MHz */ + < 5859 >, /* 7. DDR:768.00 MHz BIMC: 384.00 MHz */ + < 6152 >, /* 8. DDR:806.40 MHz BIMC: 403.20 MHz */ + < 6445 >, /* 9. DDR:844.80 MHz BIMC: 422.40 MHz */ + < 7104 >; /*10. DDR:931.20 MHz BIMC: 465.60 MHz */ + }; + + msm_gpu: qcom,kgsl-3d0@1c00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x1c00000 0x40000>; + reg-names = "kgsl_3d0_reg_memory"; + interrupts = <0 33 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + qcom,chipid = <0x05000600>; + + qcom,initial-pwrlevel = <4>; + + qcom,idle-timeout = <80>; //msecs + qcom,deep-nap-timeout = <100>; //msecs + qcom,strtstp-sleepwake; + + qcom,highest-bank-bit = <14>; + + qcom,snapshot-size = <1048576>; //bytes + + clocks = <&clock_gcc_gfx clk_gcc_oxili_gfx3d_clk>, + <&clock_gcc_gfx clk_gcc_oxili_ahb_clk>, + <&clock_gcc_gfx clk_gcc_bimc_gfx_clk>, + <&clock_gcc_gfx clk_gcc_bimc_gpu_clk>, + <&clock_gcc_gfx clk_gcc_oxili_timer_clk>, + <&clock_gcc_gfx clk_gcc_oxili_aon_clk>; + + clock-names = "core_clk", "iface_clk", + "mem_iface_clk", "alt_mem_iface_clk", + "rbbmtimer_clk", "alwayson_clk"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,bus-width = <16>; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <11>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, /* off */ + <26 512 0 1689600>, /* 1. 211.20 MHz */ + <26 512 0 2227200>, /* 2. 278.40 MHz */ + <26 512 0 3072000>, /* 3. 384.00 MHz */ + <26 512 0 3379200>, /* 4. 422.40 MHz */ + <26 512 0 4454400>, /* 5. 556.80 MHz */ + <26 512 0 5376000>, /* 6. 672.00 MHz */ + <26 512 0 6144000>, /* 7. 768.00 MHz */ + <26 512 0 6451200>, /* 8. 806.40 MHz */ + <26 512 0 6758400>, /* 9. 844.80 MHz */ + <26 512 0 7449600>; /*10. 931.20 MHz */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gdsc_oxili_cx>; + vdd-supply = <&gdsc_oxili_gx>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <213>; + qcom,pm-qos-wakeup-latency = <213>; + + /* Quirks */ + qcom,gpu-quirk-two-pass-use-wfi; + qcom,gpu-quirk-dp2clockgating-disable; + qcom,gpu-quirk-lmloadkill-disable; + + /* Trace bus */ + coresight-id = <67>; + coresight-name = "coresight-gfx"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_mm>; + coresight-child-ports = <6>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <3>; + + /* Enable gpu cooling device */ + #cooling-cells = <2>; + + /* 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>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <10>; + }; + + /* NOM+ */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <560000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <6>; + qcom,bus-max = <10>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <2>; + qcom,bus-max = <6>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <216000000>; + qcom,bus-freq = <1>; + qcom,bus-min = <1>; + qcom,bus-max = <4>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <133300000>; + qcom,bus-freq = <1>; + qcom,bus-min = <1>; + qcom,bus-max = <4>; + }; + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@1c40000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x1c40000 0x10000>; + qcom,protect = <0x40000 0x10000>; + qcom,micro-mmu-control = <0x6000>; + + clocks = <&clock_gcc_gfx clk_gcc_oxili_ahb_clk>, + <&clock_gcc_gfx clk_gcc_bimc_gfx_clk>; + + clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,gpu-offset = <0x48000>; + }; + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 2>; + memory-region = <&secure_mem>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..34004b021431b83b98ab729b50aa737d01b34faf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ion.dtsi @@ -0,0 +1,36 @@ +/* Copyright (c) 2015-2017, 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 { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@8 { /* CP_MM HEAP */ + reg = <8>; + memory-region = <&secure_mem>; + qcom,ion-heap-type = "SECURE_DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..fec135d835e7d4aff982993d66dbe37ed9618994 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-mtp.dtsi" + +/ { + model = "IOT MTP"; + qcom,board-id = <8 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..39c76cc4da5252c29a8e357ac8e43b1e72dadb6f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 IOT MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 2>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3f957da5bfef6ddb676f85881c81a9fa69d6e505 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-ipc.dtsi" + +/ { + model = "IPC"; + qcom,board-id = <12 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc.dts b/arch/arm64/boot/dts/qcom/msm8953-ipc.dts new file mode 100644 index 0000000000000000000000000000000000000000..89a54afa64a3bdb8deffa74e4432116d82dd2d48 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ipc.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016-2017, 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 "msm8953.dtsi" +#include "msm8953-ipc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 IPC"; + compatible = "qcom,msm8953-ipc", "qcom,msm8953", "qcom,ipc"; + qcom,board-id= <12 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..26f4338d4560f3029c142bd7d0b9e5ed477eb5cc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-ipc.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016-2017, 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. + */ + +&blsp1_uart0 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm830-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts similarity index 68% rename from arch/arm64/boot/dts/qcom/sdm830-mtp.dts rename to arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts index 5da16e685a86786fd1b0f400c7fbf1e19fa5034f..49956dfaad9f56b7445fe00509126375da22d798 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-mtp.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,14 +11,12 @@ * GNU General Public License for more details. */ - /dts-v1/; +/plugin/; -#include "sdm830.dtsi" -#include "sdm830-mtp.dtsi" +#include "msm8953-mtp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM bat v1 MTP"; - compatible = "qcom,sdm830-mtp", "qcom,sdm830", "qcom,mtp"; + model = "MTP"; qcom,board-id = <8 0>; }; diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..b53f7b8c8590cfc693b7ee7e562da6531bd9e3bf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015-2017, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + +/{ + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "batterydata-itech-3000mah.dtsi" + #include "batterydata-ascent-3450mAh.dtsi" + }; +}; + +&pmi8950_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&pmi8950_charger { + qcom,battery-data = <&mtp_batterydata>; + qcom,chg-led-sw-controls; + qcom,chg-led-support; +}; + +&usb3 { + extcon = <&pmi8950_charger>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..87b8c7439af028138e87a0ec0eef75156aaccb2c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&blsp1_uart0 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm8953_l8>; + qcom,vdd-voltage-level = <2900000 2900000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8953_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 + 384000000>; + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm8953_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8953_l12>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 133 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 133 0x1>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eec350d5f8224e55e23c337b2bd3851b1eeca182 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi @@ -0,0 +1,1557 @@ +/* + * Copyright (c) 2015-2018, 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@1000000 { + compatible = "qcom,msm8953-pinctrl"; + reg = <0x1000000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + pmx-uartconsole { + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + uart_console_sleep: uart_console_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + uart1_console_active: uart1_console_active { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart6"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + + uart1_console_sleep: uart1_console_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart6"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + cci { + cci0_active: cci0_active { + /* cci0 active state */ + mux { + /* CLK, DATA */ + pins = "gpio29", "gpio30"; + function = "cci_i2c"; + }; + + config { + pins = "gpio29", "gpio30"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + cci0_suspend: cci0_suspend { + /* cci0 suspended state */ + mux { + /* CLK, DATA */ + pins = "gpio29", "gpio30"; + function = "cci_i2c"; + }; + + config { + pins = "gpio29", "gpio30"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + cci1_active: cci1_active { + /* cci1 active state */ + mux { + /* CLK, DATA */ + pins = "gpio31", "gpio32"; + function = "cci_i2c"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + + cci1_suspend: cci1_suspend { + /* cci1 suspended state */ + mux { + /* CLK, DATA */ + pins = "gpio31", "gpio32"; + function = "cci_i2c"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; /* 2 MA */ + bias-disable; /* No PULL */ + }; + }; + }; + + /*sensors */ + cam_sensor_mclk0_default: cam_sensor_mclk0_default { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio26"; + function = "cam_mclk"; + }; + + config { + pins = "gpio26"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio26"; + function = "cam_mclk"; + }; + + config { + pins = "gpio26"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_default: cam_sensor_rear_default { + /* RESET, STANDBY */ + mux { + pins = "gpio40", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio40","gpio39"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_sleep: cam_sensor_rear_sleep { + /* RESET, STANDBY */ + mux { + pins = "gpio40","gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio40","gpio39"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_vana: cam_sensor_rear_vdig { + /* VDIG */ + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_vana_sleep: cam_sensor_rear_vdig_sleep { + /* VDIG */ + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_default: cam_sensor_mclk1_default { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_default: cam_sensor_front_default { + /* RESET, STANDBY */ + mux { + pins = "gpio131","gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio131","gpio132"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_sleep: cam_sensor_front_sleep { + /* RESET, STANDBY */ + mux { + pins = "gpio131","gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio131","gpio132"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_default: cam_sensor_mclk2_default { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_sleep: cam_sensor_mclk2_sleep { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front1_default: cam_sensor_front1_default { + /* RESET, STANDBY */ + mux { + pins = "gpio129", "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio129", "gpio130"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front1_sleep: cam_sensor_front1_sleep { + /* RESET, STANDBY */ + mux { + pins = "gpio129", "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio129", "gpio130"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + pmx_adv7533_int: pmx_adv7533_int { + adv7533_int_active: adv7533_int_active { + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <16>; + bias-disable; + }; + }; + + adv7533_int_suspend: adv7533_int_suspend { + mux { + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <16>; + bias-disable; + }; + }; + + }; + + pmx_mdss: pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio61", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio61", "gpio59"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + output-high; + }; + }; + + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio61", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio61", "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + }; + + pmx_mdss_te { + mdss_te_active: mdss_te_active { + mux { + pins = "gpio24"; + function = "mdp_vsync"; + }; + config { + pins = "gpio24"; + drive-strength = <2>; /* 8 mA */ + bias-pull-down; /* pull down*/ + }; + }; + + mdss_te_suspend: mdss_te_suspend { + mux { + pins = "gpio24"; + function = "mdp_vsync"; + }; + config { + pins = "gpio24"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + }; + + hsuart_active: default { + mux { + pins = "gpio12", "gpio13", "gpio14", "gpio15"; + function = "blsp_uart4"; + }; + + config { + pins = "gpio12", "gpio13", "gpio14", "gpio15"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio12", "gpio13", "gpio14", "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio13", "gpio14", "gpio15"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart0_active: blsp2_uart0_active { + mux { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + drive-strength = <16>; + bias-disable; + }; + }; + + blsp2_uart0_sleep: blsp2_uart0_sleep { + mux { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + drive-strength = <16>; /* 16 MA */ + bias-disable; /* NO pull */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_2 { + i2c_2_active: i2c_2_active { + /* active state */ + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_2_sleep: i2c_2_sleep { + /* suspended state */ + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_3 { + i2c_3_active: i2c_3_active { + /* active state */ + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_3_sleep: i2c_3_sleep { + /* suspended state */ + mux { + pins = "gpio10", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_5 { + i2c_5_active: i2c_5_active { + /* active state */ + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_5_sleep: i2c_5_sleep { + /* suspended state */ + mux { + pins = "gpio18", "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pmx_rd_nfc_int { + /*qcom,pins = <&gp 17>;*/ + pins = "gpio17"; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_nfc_int"; + + nfc_int_active: active { + drive-strength = <6>; + bias-pull-up; + }; + + nfc_int_suspend: suspend { + drive-strength = <6>; + bias-pull-up; + }; + }; + + pmx_nfc_reset { + /*qcom,pins = <&gp 16>;*/ + pins = "gpio16"; + qcom,pin-func = <0>; + qcom,num-grp-pins = <1>; + label = "pmx_nfc_disable"; + + nfc_disable_active: active { + drive-strength = <6>; + bias-pull-up; + }; + + nfc_disable_suspend: suspend { + drive-strength = <6>; + bias-disable; + }; + }; + + wcnss_pmux_5wire { + /* Active configuration of bus pins */ + wcnss_default: wcnss_default { + wcss_wlan2 { + pins = "gpio76"; + function = "wcss_wlan2"; + }; + wcss_wlan1 { + pins = "gpio77"; + function = "wcss_wlan1"; + }; + wcss_wlan0 { + pins = "gpio78"; + function = "wcss_wlan0"; + }; + wcss_wlan { + pins = "gpio79", "gpio80"; + function = "wcss_wlan"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + + wcnss_sleep: wcnss_sleep { + wcss_wlan2 { + pins = "gpio76"; + function = "wcss_wlan2"; + }; + wcss_wlan1 { + pins = "gpio77"; + function = "wcss_wlan1"; + }; + wcss_wlan0 { + pins = "gpio78"; + function = "wcss_wlan0"; + }; + wcss_wlan { + pins = "gpio79", "gpio80"; + function = "wcss_wlan"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + }; + + wcnss_pmux_gpio: wcnss_pmux_gpio { + wcnss_gpio_default: wcnss_gpio_default { + /* Active configuration of bus pins */ + mux { + /* Uses general purpose pins */ + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + }; + + wcd9xxx_intr { + wcd_intr_default: wcd_intr_default{ + mux { + pins = "gpio73"; + function = "gpio"; + }; + + config { + pins = "gpio73"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-enable; + }; + }; + }; + + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio67"; + function = "gpio"; + }; + config { + pins = "gpio67"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio67"; + function = "gpio"; + }; + config { + pins = "gpio67"; + drive-strength = <16>; + bias-pull-down; + output-high; + }; + }; + }; + + cdc_mclk2_pin { + cdc_mclk2_sleep: cdc_mclk2_sleep { + mux { + pins = "gpio66"; + function = "pri_mi2s"; + }; + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + cdc_mclk2_active: cdc_mclk2_active { + mux { + pins = "gpio66"; + function = "pri_mi2s"; + }; + config { + pins = "gpio66"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + cdc-pdm-2-lines { + cdc_pdm_lines_2_act: pdm_lines_2_on { + mux { + pins = "gpio70", "gpio71", "gpio72"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio70", "gpio71", "gpio72"; + drive-strength = <8>; + }; + }; + + cdc_pdm_lines_2_sus: pdm_lines_2_off { + mux { + pins = "gpio70", "gpio71", "gpio72"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio70", "gpio71", "gpio72"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + cdc-pdm-lines { + cdc_pdm_lines_act: pdm_lines_on { + mux { + pins = "gpio69", "gpio73", "gpio74"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio69", "gpio73", "gpio74"; + drive-strength = <8>; + }; + }; + cdc_pdm_lines_sus: pdm_lines_off { + mux { + pins = "gpio69", "gpio73", "gpio74"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio69", "gpio73", "gpio74"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + cdc-pdm-comp-lines { + cdc_pdm_comp_lines_act: pdm_comp_lines_on { + mux { + pins = "gpio67", "gpio68"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio67", "gpio68"; + drive-strength = <8>; + }; + }; + + cdc_pdm_comp_lines_sus: pdm_comp_lines_off { + mux { + pins = "gpio67", "gpio68"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio67", "gpio68"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + cross-conn-det { + cross_conn_det_act: lines_on { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <8>; + output-low; + bias-pull-down; + }; + }; + + cross_conn_det_sus: lines_off { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + /* WSA VI sense */ + wsa-vi { + wsa_vi_on: wsa_vi_on { + mux { + pins = "gpio94", "gpio95"; + function = "wsa_io"; + }; + + config { + pins = "gpio94", "gpio95"; + drive-strength = <8>; /* 8 MA */ + bias-disable; /* NO pull */ + }; + }; + + wsa_vi_off: wsa_vi_off { + mux { + pins = "gpio94", "gpio95"; + function = "wsa_io"; + }; + + config { + pins = "gpio94", "gpio95"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; + }; + }; + }; + + /* WSA Reset */ + wsa_reset { + wsa_reset_on: wsa_reset_on { + mux { + pins = "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio96"; + drive-strength = <2>; /* 2 MA */ + output-high; + }; + }; + + wsa_reset_off: wsa_reset_off { + mux { + pins = "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio96"; + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + }; + + /* WSA CLK */ + wsa_clk { + wsa_clk_on: wsa_clk_on { + mux { + pins = "gpio25"; + function = "pri_mi2s_mclk_a"; + }; + + config { + pins = "gpio25"; + drive-strength = <8>; /* 8 MA */ + output-high; + }; + }; + + wsa_clk_off: wsa_clk_off { + mux { + pins = "gpio25"; + function = "pri_mi2s_mclk_a"; + }; + + config { + pins = "gpio25"; + drive-strength = <2>; /* 2 MA */ + output-low; + bias-pull-down; + }; + }; + }; + + pri-tlmm-lines { + pri_tlmm_lines_act: pri_tlmm_lines_act { + mux { + pins = "gpio91", "gpio93"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio91", "gpio93"; + drive-strength = <8>; + }; + }; + + pri_tlmm_lines_sus: pri_tlmm_lines_sus { + mux { + pins = "gpio91", "gpio93"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio91", "gpio93"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pri-tlmm-ws-lines { + pri_tlmm_ws_act: pri_tlmm_ws_act { + mux { + pins = "gpio92"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio92"; + drive-strength = <8>; + }; + }; + + pri_tlmm_ws_sus: pri_tlmm_ws_sus { + mux { + pins = "gpio92"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + spi3 { + spi3_default: spi3_default { + /* active state */ + mux { + /* MOSI, MISO, CLK */ + pins = "gpio8", "gpio9", "gpio11"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio8", "gpio9", "gpio11"; + drive-strength = <12>; /* 12 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + spi3_sleep: spi3_sleep { + /* suspended state */ + mux { + /* MOSI, MISO, CLK */ + pins = "gpio8", "gpio9", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9", "gpio11"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + + spi3_cs0_active: cs0_active { + /* CS */ + mux { + pins = "gpio10"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + + spi3_cs0_sleep: cs0_sleep { + /* CS */ + mux { + pins = "gpio10"; + function = "gpio"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + }; + + /* add pingrp for touchscreen */ + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio65", "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + tlmm_gpio_key { + gpio_key_active: gpio_key_active { + mux { + pins = "gpio85", "gpio86", "gpio87"; + function = "gpio"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + gpio_key_suspend: gpio_key_suspend { + mux { + pins = "gpio85", "gpio86", "gpio87"; + function = "gpio"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + pmx_qdsd_clk { + qdsd_clk_sdcard: clk_sdcard { + config { + pins = "qdsd_clk"; + bias-disable;/* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + qdsd_clk_trace: clk_trace { + config { + pins = "qdsd_clk"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_clk_swdtrc: clk_swdtrc { + config { + pins = "qdsd_clk"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_clk_spmi: clk_spmi { + config { + pins = "qdsd_clk"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + }; + + pmx_qdsd_cmd { + qdsd_cmd_sdcard: cmd_sdcard { + config { + pins = "qdsd_cmd"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_cmd_trace: cmd_trace { + config { + pins = "qdsd_cmd"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_cmd_swduart: cmd_uart { + config { + pins = "qdsd_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_cmd_swdtrc: cmd_swdtrc { + config { + pins = "qdsd_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_cmd_jtag: cmd_jtag { + config { + pins = "qdsd_cmd"; + bias-disable; /* NO pull */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_cmd_spmi: cmd_spmi { + config { + pins = "qdsd_cmd"; + bias-pull-down; /* pull down */ + drive-strength = <10>; /* 10 MA */ + }; + }; + }; + + pmx_qdsd_data0 { + qdsd_data0_sdcard: data0_sdcard { + config { + pins = "qdsd_data0"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data0_trace: data0_trace { + config { + pins = "qdsd_data0"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data0_swduart: data0_uart { + config { + pins = "qdsd_data0"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data0_swdtrc: data0_swdtrc { + config { + pins = "qdsd_data0"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data0_jtag: data0_jtag { + config { + pins = "qdsd_data0"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data0_spmi: data0_spmi { + config { + pins = "qdsd_data0"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + }; + + pmx_qdsd_data1 { + qdsd_data1_sdcard: data1_sdcard { + config { + pins = "qdsd_data1"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data1_trace: data1_trace { + config { + pins = "qdsd_data1"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data1_swduart: data1_uart { + config { + pins = "qdsd_data1"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data1_swdtrc: data1_swdtrc { + config { + pins = "qdsd_data1"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data1_jtag: data1_jtag { + config { + pins = "qdsd_data1"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + }; + + pmx_qdsd_data2 { + qdsd_data2_sdcard: data2_sdcard { + config { + pins = "qdsd_data2"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data2_trace: data2_trace { + config { + pins = "qdsd_data2"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data2_swduart: data2_uart { + config { + pins = "qdsd_data2"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data2_swdtrc: data2_swdtrc { + config { + pins = "qdsd_data2"; + bias-pull-down; /* pull down */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data2_jtag: data2_jtag { + config { + pins = "qdsd_data2"; + bias-pull-up; /* pull up */ + drive-strength = <8>; /* 8 MA */ + }; + }; + }; + + pmx_qdsd_data3 { + qdsd_data3_sdcard: data3_sdcard { + config { + pins = "qdsd_data3"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data3_trace: data3_trace { + config { + pins = "qdsd_data3"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + qdsd_data3_swduart: data3_uart { + config { + pins = "qdsd_data3"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data3_swdtrc: data3_swdtrc { + config { + pins = "qdsd_data3"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data3_jtag: data3_jtag { + config { + pins = "qdsd_data3"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + qdsd_data3_spmi: data3_spmi { + config { + pins = "qdsd_data3"; + bias-pull-down; /* pull down */ + drive-strength = <8>; /* 8 MA */ + }; + }; + }; + + typec_ssmux_config: typec_ssmux_config { + mux { + pins = "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio139"; + drive-strength = <2>; + bias-disable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..da4f4df01ce2bd32bf219776b8366d60f1236042 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pm.dtsi @@ -0,0 +1,282 @@ +/* Copyright (c) 2015-2017, 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 + +&soc { + qcom,spm@b1d2000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb1d2000 0x1000>; + reg-names = "saw-base"; + qcom,name = "system-cci"; + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x14>; + qcom,saw2-spm-dly= <0x3C102800>; + qcom,saw2-spm-ctl = <0xe>; + qcom,saw2-avs-ctl = <0x10>; + qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3 + &CPU4 &CPU5 &CPU6 &CPU7>; + qcom,vctl-timeout-us = <500>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,pfm-port = <0x2>; + }; + + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "system"; + qcom,psci-mode-shift = <8>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0 { + reg = <0>; + label = "system-active"; + qcom,psci-mode = <0>; + qcom,latency-us = <423>; + qcom,ss-power = <349>; + qcom,energy-overhead = <299110>; + qcom,time-overhead = <719>; + }; + + qcom,pm-cluster-level@1 { + reg = <1>; + label = "system-wfi"; + qcom,psci-mode = <1>; + qcom,latency-us = <480>; + qcom,ss-power = <348>; + qcom,energy-overhead = <313989>; + qcom,time-overhead = <753>; + qcom,min-child-idx = <3>; + }; + + qcom,pm-cluster-level@2 { + reg = <2>; + label = "system-pc"; + qcom,psci-mode = <3>; + qcom,latency-us = <11027>; + qcom,ss-power = <340>; + qcom,energy-overhead = <616035>; + qcom,time-overhead = <1495>; + qcom,min-child-idx = <3>; + qcom,notify-rpm; + qcom,is-reset; + qcom,reset-level = ; + }; + + qcom,pm-cluster@0{ + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "pwr"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0{ + reg = <0>; + label = "pwr-l2-wfi"; + qcom,psci-mode = <1>; + qcom,latency-us = <180>; + qcom,ss-power = <361>; + qcom,energy-overhead = <113215>; + qcom,time-overhead = <270>; + }; + + qcom,pm-cluster-level@1{ + reg = <1>; + label = "pwr-l2-retention"; + qcom,psci-mode = <3>; + qcom,latency-us = <188>; + qcom,ss-power = <360>; + qcom,energy-overhead = <121271>; + qcom,time-overhead = <307>; + qcom,min-child-idx = <1>; + qcom,reset-level = + ; + }; + + qcom,pm-cluster-level@2{ + reg = <2>; + label = "pwr-l2-gdhs"; + qcom,psci-mode = <4>; + qcom,latency-us = <212>; + qcom,ss-power = <354>; + qcom,energy-overhead = <150748>; + qcom,time-overhead = <363>; + qcom,min-child-idx = <1>; + qcom,reset-level = + ; + }; + + qcom,pm-cluster-level@3{ + reg = <3>; + label = "pwr-l2-pc"; + qcom,psci-mode = <5>; + qcom,latency-us = <421>; + qcom,ss-power = <350>; + qcom,energy-overhead = <277479>; + qcom,time-overhead = <690>; + qcom,min-child-idx = <1>; + qcom,is-reset; + qcom,reset-level = + ; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <1>; + qcom,latency-us = <1>; + qcom,ss-power = <395>; + qcom,energy-overhead = <30424>; + qcom,time-overhead = <61>; + }; + + qcom,pm-cpu-level@1 { + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <3>; + qcom,latency-us = <180>; + qcom,ss-power = <361>; + qcom,energy-overhead = <113215>; + qcom,time-overhead = <270>; + qcom,use-broadcast-timer; + qcom,is-reset; + qcom,reset-level = + ; + }; + }; + }; + + qcom,pm-cluster@1{ + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + label = "perf"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0{ + reg = <0>; + label = "perf-l2-wfi"; + qcom,psci-mode = <1>; + qcom,latency-us = <179>; + qcom,ss-power = <362>; + qcom,energy-overhead = <113242>; + qcom,time-overhead = <268>; + }; + + qcom,pm-cluster-level@1{ + reg = <1>; + label = "perf-l2-retention"; + qcom,psci-mode = <3>; + qcom,latency-us = <186>; + qcom,ss-power = <361>; + qcom,energy-overhead = <125982>; + qcom,time-overhead = <306>; + qcom,min-child-idx = <1>; + qcom,reset-level = + ; + }; + + qcom,pm-cluster-level@2{ + reg = <2>; + label = "perf-l2-gdhs"; + qcom,psci-mode = <4>; + qcom,latency-us = <210>; + qcom,ss-power = <355>; + qcom,energy-overhead = <155728>; + qcom,time-overhead = <361>; + qcom,min-child-idx = <1>; + qcom,reset-level = + ; + }; + + qcom,pm-cluster-level@3{ + reg = <3>; + label = "perf-l2-pc"; + qcom,psci-mode = <5>; + qcom,latency-us = <423>; + qcom,ss-power = <349>; + qcom,energy-overhead = <299110>; + qcom,time-overhead = <719>; + qcom,min-child-idx = <1>; + qcom,is-reset; + qcom,reset-level = + ; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <1>; + qcom,latency-us = <1>; + qcom,ss-power = <397>; + qcom,energy-overhead = <30424>; + qcom,time-overhead = <61>; + }; + + qcom,pm-cpu-level@1 { + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <3>; + qcom,latency-us = <179>; + qcom,ss-power = <362>; + qcom,energy-overhead = <113242>; + qcom,time-overhead = <268>; + qcom,use-broadcast-timer; + qcom,is-reset; + qcom,reset-level = + ; + }; + }; + }; + }; + }; + + qcom,rpm-stats@200000 { + compatible = "qcom,rpm-stats"; + reg = <0x200000 0x1000>, <0x290014 0x4>, <0x29001c 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; + + qcom,rpm-master-stats@60150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x60150 0x5000>; + qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ad3d3edf2d167f3e1949803ccfea3b3dd9016400 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937-cdp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "msm8953.dtsi" +#include "pmi8937.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 CDP"; + compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x010016 0x020037 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937-ext-codec-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937-ext-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..5abf19847f324b638a5b0b51625492b0a4c691b0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937-ext-codec-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +#include "pmi8937.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 Ext Codec MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 1>; + qcom,pmic-id = <0x010016 0x020037 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ee1c2a0903e5e85ad21324bf77e08c33b7276b07 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "msm8953.dtsi" +#include "pmi8937.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 0>; + qcom,pmic-id = <0x010016 0x020037 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm830-rumi.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts similarity index 62% rename from arch/arm64/boot/dts/qcom/sdm830-rumi.dtsi rename to arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts index 2bc5f3f11a132b6a89991b6b1c171c5ca78e78ba..a9f64a49e522a051a2008be666ef6a8917d0a86e 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,11 +11,13 @@ * GNU General Public License for more details. */ -/* - * As a general rule, only version-specific property overrides should be placed - * inside this file. Common device definitions should be placed inside the - * sdm845-rumi.dtsi file. - */ +/dts-v1/; - #include "sdm845-rumi.dtsi" +#include "msm8953.dtsi" +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC"; + compatible = "qcom,msm8953"; + qcom,pmic-id = <0x010016 0x020037 0x0 0x0>; + qcom,pmic-name = "PMI8937"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a178aa11fcc2756b55d35d0c2799e9c0f39e05fd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016-2018, 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 { + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8937_flash0 &pmi8937_flash1>; + qcom,torch-source = <&pmi8937_torch0 &pmi8937_torch1>; + qcom,switch-source = <&pmi8937_switch>; + }; +}; + +&usb3 { + vbus_dwc3-supply = <&smbcharger_charger_otg>; +}; + +&pmi8937_charger { + qcom,external-typec; + qcom,typec-psy-name = "typec"; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940-cdp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..51622e037b93aa539f07290135c3780f891dd10d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940-cdp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "msm8953.dtsi" +#include "pmi8940.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8940.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 CDP"; + compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x010016 0x020040 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940-ext-codec-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940-ext-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..92c67faf6fcf5fa087148636b529049cbff2e753 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940-ext-codec-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +#include "pmi8940.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8940.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 Ext Codec MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 1>; + qcom,pmic-id = <0x010016 0x020040 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..cb379b9af1f68e5e1a1b7f5e9d8bbb8ef977545d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940-mtp.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016-2018, 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 "msm8953.dtsi" +#include "pmi8940.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8940.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 MTP"; + compatible = "qcom,msm8953-mtp", "qcom,msm8953", "qcom,mtp"; + qcom,board-id= <8 0>; + qcom,pmic-id = <0x010016 0x020040 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts new file mode 100644 index 0000000000000000000000000000000000000000..e9c80a0d359b4e40357d5bf94c7297f1ed9fda30 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, 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 "msm8953.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC"; + compatible = "qcom,msm8953"; + qcom,pmic-id = <0x010016 0x020040 0x0 0x0>; + qcom,pmic-name = "PMI8940"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..71d69412ef8320f0cece55be5dabbb0d940740f5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-2018, 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 { + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8940_flash0 &pmi8940_flash1>; + qcom,torch-source = <&pmi8940_torch0 &pmi8940_torch1>; + qcom,switch-source = <&pmi8940_switch>; + }; +}; + +&usb3 { + vbus_dwc3-supply = <&smbcharger_charger_otg>; +}; + +&labibb { + status = "ok"; + qpnp,qpnp-labibb-mode = "lcd"; +}; + +&ibb_regulator { + qcom,qpnp-ibb-discharge-resistor = <32>; +}; + +&pmi8940_charger { + qcom,external-typec; + qcom,typec-psy-name = "typec"; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b9c2a1834d14132fc3ae0c3aa134fceed11a1015 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017-2018, 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 { + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>; + qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>; + qcom,switch-source = <&pmi8950_switch>; + }; +}; + +&labibb { + status = "ok"; + qpnp,qpnp-labibb-mode = "lcd"; +}; + +&usb3 { + vbus_dwc3-supply = <&smbcharger_charger_otg>; +}; + +&pmi8950_charger { + qcom,external-typec; + qcom,typec-psy-name = "typec"; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7f5fc4e4c678d4f64c282567ae4f3ba2c594c204 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-qrd-sku3.dtsi" + +/ { + model = "QRD SKU3"; + qcom,board-id = <0xb 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd-sku3.dts b/arch/arm64/boot/dts/qcom/msm8953-qrd-sku3.dts new file mode 100644 index 0000000000000000000000000000000000000000..5d892fd2e835d2ce1b462fa01d53763f9cd05fc9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-qrd-sku3.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015-2017, 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 "msm8953.dtsi" +#include "msm8953-qrd-sku3.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 QRD SKU3"; + compatible = "qcom,msm8953-qrd-sku3", + "qcom,msm8953-qrd", "qcom,msm8953", "qcom,qrd"; + qcom,board-id= <0x2000b 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm830-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-qrd-sku3.dtsi similarity index 79% rename from arch/arm64/boot/dts/qcom/sdm830-mtp.dtsi rename to arch/arm64/boot/dts/qcom/msm8953-qrd-sku3.dtsi index b2d607dadc3b1672a62c7f095a80a4edf09b1b26..96e185bfff035e6a88952929fb37b7a4fa287004 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-qrd-sku3.dtsi @@ -1,4 +1,5 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,5 +11,5 @@ * GNU General Public License for more details. */ -#include "sdm845-mtp.dtsi" -#include "sdm830-pinctrl.dtsi" +#include "msm8953-qrd.dtsi" + diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..87b8c7439af028138e87a0ec0eef75156aaccb2c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&blsp1_uart0 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm8953_l8>; + qcom,vdd-voltage-level = <2900000 2900000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8953_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 + 384000000>; + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm8953_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8953_l12>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 133 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 133 0x1>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..dbb7f57788615a35478a6fa147030d8e41787c99 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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/; +/plugin/; + +#include "msm8953-cdp.dtsi" + +/ { + model = "RCM"; + qcom,board-id = <21 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-rcm.dts b/arch/arm64/boot/dts/qcom/msm8953-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..625a4d6b53cccb3c275605bbcac0938aeb6aa320 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-rcm.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2018, 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 "msm8953.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 RCM"; + compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp"; + qcom,board-id= <21 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9468181061531a03b8bb107dbc53db5942e7c8be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi @@ -0,0 +1,936 @@ +/* + * Copyright (c) 2015-2018, 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 + +&rpm_bus { + rpm-regulator-smpa1 { + status = "okay"; + pm8953_s1: regulator-s1 { + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <1156000>; + qcom,init-voltage = <1000000>; + status = "okay"; + }; + }; + + /* PM8953 S2 - VDD_CX supply */ + rpm-regulator-smpa2 { + status = "okay"; + pm8953_s2_level: regulator-s2-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s2_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pm8953_s2_floor_level: regulator-s2-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s2_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + pm8953_s2_level_ao: regulator-s2-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s2_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + cx_cdev: regulator-cx-cdev { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pm8953_s2_floor_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpm-regulator-smpa3 { + status = "okay"; + pm8953_s3: regulator-s3 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa4 { + status = "okay"; + pm8953_s4: regulator-s4 { + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <2050000>; + qcom,init-voltage = <1900000>; + status = "okay"; + }; + }; + + /* VDD_MX supply */ + rpm-regulator-smpa7 { + status = "okay"; + pm8953_s7_level: regulator-s7-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s7_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,use-voltage-level; + qcom,always-send-voltage; + }; + + pm8953_s7_level_ao: regulator-s7-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s7_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + qcom,always-send-voltage; + }; + + pm8953_s7_level_so: regulator-s7-level-so { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s7_level_so"; + qcom,set = <2>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,use-voltage-level; + }; + }; + + rpm-regulator-ldoa1 { + status = "okay"; + pm8953_l1: regulator-l1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + qcom,init-voltage = <1000000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa2 { + status = "okay"; + pm8953_l2: regulator-l2 { + regulator-min-microvolt = <975000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <975000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa3 { + status = "okay"; + pm8953_l3: regulator-l3 { + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <925000>; + qcom,init-voltage = <925000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa5 { + status = "okay"; + pm8953_l5: regulator-l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + pm8953_l6: regulator-l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa7 { + status = "okay"; + pm8953_l7: regulator-l7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + + pm8953_l7_ao: regulator-l7-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l7_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpm-regulator-ldoa8 { + status = "okay"; + pm8953_l8: regulator-l8 { + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + qcom,init-voltage = <2900000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa9 { + status = "okay"; + pm8953_l9: regulator-l9 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <3000000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + pm8953_l10: regulator-l10 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + qcom,init-voltage = <2850000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + pm8953_l11: regulator-l11 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <2950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + pm8953_l12: regulator-l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + pm8953_l13: regulator-l13 { + regulator-min-microvolt = <3125000>; + regulator-max-microvolt = <3125000>; + qcom,init-voltage = <3125000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa16 { + status = "okay"; + pm8953_l16: regulator-l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa17 { + status = "okay"; + pm8953_l17: regulator-l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + qcom,init-voltage = <2850000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa19 { + status = "okay"; + pm8953_l19: regulator-l19 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa22 { + status = "okay"; + pm8953_l22: regulator-l22 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2850000>; + qcom,init-voltage = <2800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa23 { + status = "okay"; + pm8953_l23: regulator-l23 { + regulator-min-microvolt = <975000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <975000>; + status = "okay"; + }; + }; +}; + +&spmi_bus { + qcom,pm8953@1 { + /* PM8953 S5 + S6 = VDD_APC supply */ + pm8953_s5: spm-regulator@2000 { + compatible = "qcom,spm-regulator"; + reg = <0x2000 0x100>; + regulator-name = "pm8953_s5"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1140000>; + + pm8953_s5_limit: avs-limit-regulator { + regulator-name = "pm8953_s5_avs_limit"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1140000>; + }; + }; + }; +}; + +&soc { + apc_mem_acc_vreg: regulator@19461d4 { + compatible = "qcom,mem-acc-regulator"; + reg = <0x019461d4 0x4>, <0x019461d8 0x4>; + reg-names = "acc-sel-l1", "acc-sel-l2"; + regulator-name = "apc_mem_acc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <2>; + + qcom,corner-acc-map = <0x1 0x0>; + qcom,acc-sel-l1-bit-pos = <0>; + qcom,acc-sel-l1-bit-size = <1>; + qcom,acc-sel-l2-bit-pos = <0>; + qcom,acc-sel-l2-bit-size = <1>; + }; + + apc_cpr: cpr4-ctrl@b018000 { + compatible = "qcom,cpr4-msm8953-apss-regulator"; + reg = <0xb018000 0x4000>, <0xa4000 0x1000>; + reg-names = "cpr_ctrl", "fuse_base"; + interrupts = ; + interrupt-names = "cpr"; + + qcom,cpr-ctrl-name = "apc"; + + qcom,cpr-sensor-time = <1000>; + qcom,cpr-loop-time = <5000000>; + qcom,cpr-idle-cycles = <15>; + qcom,cpr-step-quot-init-min = <12>; + qcom,cpr-step-quot-init-max = <14>; + qcom,cpr-count-mode = <0>; /* All-at-once */ + qcom,cpr-count-repeat = <14>; + qcom,cpr-down-error-step-limit = <1>; + qcom,cpr-up-error-step-limit = <1>; + + qcom,apm-ctrl = <&apc_apm>; + qcom,apm-threshold-voltage = <850000>; + qcom,apm-hysteresis-voltage = <5000>; + + vdd-supply = <&pm8953_s5>; + qcom,voltage-step = <5000>; + vdd-limit-supply = <&pm8953_s5_limit>; + mem-acc-supply = <&apc_mem_acc_vreg>; + + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + + qcom,cpr-panic-reg-addr-list = + <0xb1d2c18 0xb1d2900 0x0b1112b0 0xb018798>; + qcom,cpr-panic-reg-name-list = + "CCI_SAW4_PMIC_STS", "CCI_SAW4_VCTL", + "APCS_ALIAS0_APM_CTLER_STATUS", + "APCS0_CPR_CORE_ADJ_MODE_REG"; + + qcom,cpr-temp-point-map = <250 650 850>; + qcom,cpr-initial-temp-band = <0>; + + /* Turbo (corner 6) ceiling voltage */ + qcom,cpr-aging-ref-voltage = <990000>; + + thread@0 { + qcom,cpr-thread-id = <0>; + qcom,cpr-consecutive-up = <0>; + qcom,cpr-consecutive-down = <2>; + qcom,cpr-up-threshold = <2>; + qcom,cpr-down-threshold = <1>; + + apc_vreg: regulator { + regulator-name = "apc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <9>; + + qcom,cpr-fuse-corners = <4>; + qcom,cpr-fuse-combos = <64>; + qcom,cpr-speed-bins = <8>; + qcom,cpr-speed-bin-corners = + <9 0 7 0 0 0 7 9>; + qcom,cpr-corners = + /* Speed bin 0 */ + <9 9 9 9 9 9 9 9>, + + /* Speed bin 1 */ + <0 0 0 0 0 0 0 0>, + + /* Speed bin 2 */ + <7 7 7 7 7 7 7 7>, + + /* Speed bin 3..5 */ + <0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0>, + + /* Speed bin 6 */ + <7 7 7 7 7 7 7 7>, + + /* Speed bin 7 */ + <9 9 9 9 9 9 9 9>; + + qcom,cpr-corner-fmax-map = + /* Speed bin 0 */ + <1 2 4 9>, + + /* Speed bin 1 */ + <0 0 0 0>, + + /* Speed bin 2 */ + <1 2 4 7>, + + /* Speed bin 3..5 */ + <0 0 0 0>, + <0 0 0 0>, + <0 0 0 0>, + + /* Speed bin 6 */ + <1 2 4 7>, + + /* Speed bin 7 */ + <1 2 4 9>; + + qcom,cpr-voltage-ceiling = + /* Speed bin 0 */ + <715000 790000 860000 865000 920000 + 990000 1065000 1065000 1065000>, + + /* Speed bin 2 */ + <715000 790000 860000 865000 920000 + 990000 1065000>, + + /* Speed bin 6 */ + <715000 790000 860000 865000 920000 + 990000 1065000>, + + /* Speed bin 7 */ + <715000 790000 860000 865000 920000 + 990000 1065000 1065000 1065000>; + + qcom,cpr-voltage-floor = + /* Speed bin 0 */ + <500000 500000 500000 500000 500000 + 500000 500000 500000 500000>, + + /* Speed bin 2 */ + <500000 500000 500000 500000 500000 + 500000 500000>, + + /* Speed bin 6 */ + <500000 500000 500000 500000 500000 + 500000 500000>, + + /* Speed bin 7 */ + <500000 500000 500000 500000 500000 + 500000 500000 500000 500000>; + + qcom,cpr-floor-to-ceiling-max-range = + /* Speed bin 0; CPR rev 0..7 */ + < 0 0 0 0 0 + 0 0 0 0>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + + /* Speed bin 2; CPR rev 0..7 */ + < 0 0 0 0 0 + 0 0>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + + /* Speed bin 6; CPR rev 0..7 */ + < 0 0 0 0 0 + 0 0>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000>, + + /* Speed bin 7; CPR rev 0..7 */ + < 0 0 0 0 0 + 0 0 0 0>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>, + <50000 50000 50000 50000 50000 + 50000 50000 50000 50000>; + + qcom,cpr-misc-fuse-voltage-adjustment = + /* Speed bin 0; misc fuse 0..1 */ + < 0 0 0 0 0 + 0 0 0 0>, + < 0 0 30000 0 0 + 0 0 0 0>, + + /* Speed bin 2; misc fuse 0..1 */ + < 0 0 0 0 0 + 0 0>, + < 0 0 30000 0 0 + 0 0>, + + /* Speed bin 6; misc fuse 0..1 */ + < 0 0 0 0 0 + 0 0>, + < 0 0 30000 0 0 + 0 0>, + + /* Speed bin 7; misc fuse 0..1 */ + < 0 0 0 0 0 + 0 0 0 0>, + < 0 0 30000 0 0 + 0 0 0 0>; + + qcom,mem-acc-voltage = + /* Speed bin 0 */ + <1 1 2 2 2 2 2 2 2>, + + /* Speed bin 2 */ + <1 1 2 2 2 2 2>, + + /* Speed bin 6 */ + <1 1 2 2 2 2 2>, + + /* Speed bin 7 */ + <1 1 2 2 2 2 2 2 2>; + + qcom,corner-frequencies = + /* Speed bin 0 */ + <652800000 1036800000 1401600000 + 1689600000 1804800000 1958400000 + 2016000000 2150400000 2208000000>, + + /* Speed bin 2 */ + <652800000 1036800000 1401600000 + 1689600000 1804800000 1958400000 + 2016000000>, + + /* Speed bin 6 */ + <652800000 1036800000 1401600000 + 1689600000 1804800000 1958400000 + 2016000000>, + + /* Speed bin 7 */ + <652800000 1036800000 1401600000 + 1689600000 1804800000 1958400000 + 2016000000 2150400000 2208000000>; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + /* Speed bin 0; CPR rev 0..7 */ + < 0 0 0 0>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 1; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 2; CPR rev 0..7 */ + < 0 0 0 0>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 3; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 4; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 5; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 6; CPR rev 0..7 */ + < 0 0 0 0>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 7; CPR rev 0..7 */ + < 0 0 0 0>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 25000 0 5000 40000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + /* Speed bin 0; CPR rev 0..7 */ + < 0 0 0 0>, + < 10000 (-15000) 0 25000>, + < 10000 (-15000) 0 25000>, + <(-5000) (-30000) (-15000) 10000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 1; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 2; CPR rev 0..7 */ + < 0 0 0 0>, + < 10000 (-15000) 0 25000>, + < 10000 (-15000) 0 25000>, + <(-5000) (-30000) (-15000) 10000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 3; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 4; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 5; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 6; CPR rev 0..7 */ + < 0 0 0 0>, + < 10000 (-15000) 0 25000>, + < 10000 (-15000) 0 25000>, + <(-5000) (-30000) (-15000) 10000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 7; CPR rev 0..7 */ + < 0 0 0 0>, + < 10000 (-15000) 0 25000>, + < 10000 (-15000) 0 25000>, + <(-5000) (-30000) (-15000) 10000>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>; + + qcom,cpr-ro-scaling-factor = + <3610 3790 0 2200 2450 2310 2170 2210 + 2330 2210 2470 2340 780 2700 2450 2090>, + <3610 3790 0 2200 2450 2310 2170 2210 + 2330 2210 2470 2340 780 2700 2450 2090>, + <3610 3790 0 2200 2450 2310 2170 2210 + 2330 2210 2470 2340 780 2700 2450 2090>, + <3610 3790 0 2200 2450 2310 2170 2210 + 2330 2210 2470 2340 780 2700 2450 2090>; + + qcom,allow-voltage-interpolation; + qcom,allow-quotient-interpolation; + qcom,cpr-scaled-open-loop-voltage-as-ceiling; + + qcom,corner-allow-temp-adjustment = + /* Speed bin 0; CPR rev 0..7 */ + <0 0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + + /* Speed bin 2; CPR rev 0..7 */ + <0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + + /* Speed bin 6; CPR rev 0..7 */ + <0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + <1 1 1 1 0 0 0>, + + /* Speed bin 7; CPR rev 0..7 */ + <0 0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>, + <1 1 1 1 0 0 0 0 0>; + + qcom,cpr-corner1-temp-core-voltage-adjustment = + <(0) (-5000) (-15000) (-20000)>; + + qcom,cpr-corner2-temp-core-voltage-adjustment = + <(0) (-5000) (-15000) (-15000)>; + + qcom,cpr-corner3-temp-core-voltage-adjustment = + <(0) (-5000) (-15000) (0)>; + + qcom,cpr-corner4-temp-core-voltage-adjustment = + <(0) (-5000) (-15000) (0)>; + + qcom,cpr-aging-max-voltage-adjustment = <15000>; + qcom,cpr-aging-ref-corner = <6>; /* Turbo */ + qcom,cpr-aging-ro-scaling-factor = <2800>; + qcom,allow-aging-voltage-adjustment = + /* Speed bin 0 */ + <0 0 0 1 1 1 1 1>, + + /* Speed bin 1 */ + <0 0 0 0 0 0 0 0>, + + /* Speed bin 2 */ + <0 0 0 1 1 1 1 1>, + + /* Speed bin 3..5 */ + <0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0>, + <0 0 0 0 0 0 0 0>, + + /* Speed bin 6 */ + <0 0 0 1 1 1 1 1>, + + /* Speed bin 7 */ + <0 0 0 1 1 1 1 1>; + }; + }; + }; + + gfx_mem_acc: regulator@194415c { + compatible = "qcom,mem-acc-regulator"; + reg = <0x0194415c 0x4>; + reg-names = "acc-sel-l1"; + regulator-name = "gfx_mem_acc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <2>; + + qcom,acc-sel-l1-bit-pos = <0>; + qcom,acc-sel-l1-bit-size = <1>; + qcom,corner-acc-map = <0x1 0x0>; + }; + + gfx_vreg_corner: ldo@185f000 { + compatible = "qcom,msm8953-gfx-ldo"; + reg = <0x0185f000 0x30>, <0xa4000 0x1000>; + reg-names = "ldo_addr", "efuse_addr"; + + regulator-name = "msm_gfx_ldo"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,ldo-voltage-ceiling = <620000 680000 750000>; + qcom,ldo-voltage-floor = <510000 510000 600000>; + + qcom,num-corners = <7>; + qcom,num-ldo-corners = <3>; + qcom,ldo-enable-corner-map = <1 1 1 0 0 0 0>; + qcom,init-corner = <4>; + + vdd-cx-supply = <&pm8953_s2_level>; + qcom,vdd-cx-corner-map = , + , + , + , + , + , + ; + + mem-acc-supply = <&gfx_mem_acc>; + qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>; + qcom,ldo-init-voltage-adjustment = <35000 25000 0>; + }; + + eldo2_8953: eldo2 { + compatible = "regulator-fixed"; + regulator-name = "eldo2_8953"; + startup-delay-us = <0>; + enable-active-high; + gpio = <&tlmm 50 0>; + regulator-always-on; + }; + + adv_vreg: adv_vreg { + compatible = "regulator-fixed"; + regulator-name = "adv_vreg"; + startup-delay-us = <400>; + enable-active-high; + gpio = <&pm8953_gpios 5 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d5a6f52321b6c774651e5138957494efb015659a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi @@ -0,0 +1,1090 @@ +/* Copyright (c) 2018, 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 + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi_cooling_devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + qdsp-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-cpu3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc1-l2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc0-cpu0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc0-cpu1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc0-cpu2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc0-cpu3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + apc0-l2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 15>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu1-step { + polling-delay-passive = <250>; + polling-delay = <0>; + thermal-sensors = <&tsens0 15>; + thermal-governor = "step_wise"; + trips { + gpu_trip0: gpu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + gpu_cdev0 { + trip = <&gpu_trip0>; + cooling-device = + <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + deca-cpu-max-step { + polling-delay-passive = <50>; + polling-delay = <100>; + thermal-governor = "step_wise"; + trips { + cpu_trip:cpu-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu1_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU1 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu2_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU2 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu3_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU3 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu4_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU4 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu5_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU5 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu6_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu7_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; + + pop-mem-step { + polling-delay-passive = <250>; + polling-delay = <0>; + thermal-sensors = <&tsens0 2>; + thermal-governor = "step_wise"; + trips { + pop_trip: pop-trip { + temperature = <70000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + pop_cdev0 { + trip = <&pop_trip>; + cooling-device = + <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev1 { + trip = <&pop_trip>; + cooling-device = + <&CPU1 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev2 { + trip = <&pop_trip>; + cooling-device = + <&CPU2 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev3 { + trip = <&pop_trip>; + cooling-device = + <&CPU3 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev4 { + trip = <&pop_trip>; + cooling-device = + <&CPU4 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev5 { + trip = <&pop_trip>; + cooling-device = + <&CPU5 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev6 { + trip = <&pop_trip>; + cooling-device = + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev7 { + trip = <&pop_trip>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; + + apc1-cpu0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "step_wise"; + trips { + apc1_cpu0_trip: apc1-cpu0-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu4_cdev { + trip = <&apc1_cpu0_trip>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc1-cpu1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "step_wise"; + trips { + apc1_cpu1_trip: apc1-cpu1-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu5_cdev { + trip = <&apc1_cpu1_trip>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc1-cpu2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + trips { + apc1_cpu2_trip: apc1-cpu2-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu6_cdev { + trip = <&apc1_cpu2_trip>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc1-cpu3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "step_wise"; + trips { + apc1_cpu3_trip: apc1-cpu3-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu7_cdev { + trip = <&apc1_cpu3_trip>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc0-cpu0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "step_wise"; + trips { + apc0_cpu0_trip: apc0-cpu0-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&apc0_cpu0_trip>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc0-cpu1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; + trips { + apc0_cpu1_trip: apc0-cpu1-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu1_cdev { + trip = <&apc0_cpu1_trip>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc0-cpu2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "step_wise"; + trips { + apc0_cpu2_trip: apc0-cpu2-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu2_cdev { + trip = <&apc0_cpu2_trip>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + apc0-cpu3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "step_wise"; + trips { + apc0_cpu3_trip: apc0-cpu3-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu3_cdev { + trip = <&apc0_cpu3_trip>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + mdm-core-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 1>; + tracks-low; + trips { + mdm_core_trip: mdm-core-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&mdm_core_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + qdsp-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 2>; + tracks-low; + trips { + qdsp_trip: qdsp-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&qdsp_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + camera-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 3>; + tracks-low; + trips { + camera_trip: camera-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 4>; + tracks-low; + trips { + cpu4_trip: apc1-cpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu4_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu4_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu4_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu4_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 5>; + tracks-low; + trips { + cpu5_trip: apc1-cpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu5_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu5_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu5_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu5_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu2-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 6>; + tracks-low; + trips { + cpu6_trip: apc1-cpu2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu6_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu6_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu6_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu6_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-cpu3-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 7>; + tracks-low; + trips { + cpu7_trip: apc1-cpu3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu7_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu7_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu7_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu7_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc1-l2-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 8>; + tracks-low; + trips { + apc1_l2_trip: apc1-l2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&apc1_l2_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&apc1_l2_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&apc1_l2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&apc1_l2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc0-cpu0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 9>; + tracks-low; + trips { + cpu0_trip: apc0-cpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc0-cpu1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 10>; + tracks-low; + trips { + cpu1_trip: apc0-cpu1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc0-cpu2-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 11>; + tracks-low; + trips { + cpu2_trip: apc0-cpu2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc0-cpu3-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 12>; + tracks-low; + trips { + cpu3_trip: apc0-cpu3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + apc0-l2-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 13>; + tracks-low; + trips { + apc0_l2_trip: apc0-l2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&apc0_l2_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&apc0_l2_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&apc0_l2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&apc0_l2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + gpu0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 14>; + tracks-low; + trips { + gpu0_trip: gpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu0_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&gpu0_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&gpu0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + gpu1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 15>; + tracks-low; + trips { + gpu1_trip: gpu1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu1_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4) + (THERMAL_MAX_LIMIT - 4)>; + }; + gpu_vdd_cdev { + trip = <&gpu1_trip>; + cooling-device = <&msm_gpu 2 2>; + }; + cx_vdd_cdev { + trip = <&gpu1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts new file mode 100644 index 0000000000000000000000000000000000000000..ddf221857ac9367b02bdb5718268ddfd6a40800f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, 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 "msm8953.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC"; + compatible = "qcom,msm8953"; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; + qcom,pmic-name = "PMI8950"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..69cd4fc33e550c95496419b3e2b12651d328f00a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -0,0 +1,1927 @@ +/* + * Copyright (c) 2015-2018, 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 "skeleton64.dtsi" +#include +#include +#include +#include +#include + +/ { + model = "Qualcomm Technologies, Inc. MSM8953"; + compatible = "qcom,msm8953"; + qcom,msm-id = <293 0x0>; + qcom,msm-name = "MSM8953"; + interrupt-parent = <&intc>; + + chosen { + bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait"; + status = "ok"; + }; + + }; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + other_ext_mem: other_ext_region@0 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x85b00000 0x0 0xd00000>; + }; + + modem_mem: modem_region@0 { + compatible = "removed-dma-pool"; + no-map-fixup; + reg = <0x0 0x86c00000 0x0 0x6a00000>; + }; + + adsp_fw_mem: adsp_fw_region@0 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8d600000 0x0 0x1100000>; + }; + + wcnss_fw_mem: wcnss_fw_region@0 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8e700000 0x0 0x700000>; + }; + + venus_mem: venus_region@0 { + compatible = "shared-dma-pool"; + reusable; + alloc-ranges = <0x0 0x80000000 0x0 0x10000000>; + alignment = <0 0x400000>; + size = <0 0x0800000>; + }; + + secure_mem: secure_region@0 { + compatible = "shared-dma-pool"; + reusable; + alignment = <0 0x400000>; + size = <0 0x09800000>; + }; + + qseecom_mem: qseecom_region@0 { + compatible = "shared-dma-pool"; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + }; + + adsp_mem: adsp_region@0 { + compatible = "shared-dma-pool"; + reusable; + size = <0 0x400000>; + }; + + dfps_data_mem: dfps_data_mem@90000000 { + reg = <0 0x90000000 0 0x1000>; + label = "dfps_data_mem"; + }; + + cont_splash_mem: splash_region@0x90001000 { + reg = <0x0 0x90001000 0x0 0x13ff000>; + label = "cont_splash_mem"; + }; + + gpu_mem: gpu_region@0 { + compatible = "shared-dma-pool"; + reusable; + alloc-ranges = <0x0 0x80000000 0x0 0x10000000>; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + }; + + aliases { + /* smdtty devices */ + smd1 = &smdtty_apps_fm; + smd2 = &smdtty_apps_riva_bt_acl; + smd3 = &smdtty_apps_riva_bt_cmd; + smd4 = &smdtty_mbalbridge; + smd5 = &smdtty_apps_riva_ant_cmd; + smd6 = &smdtty_apps_riva_ant_data; + smd7 = &smdtty_data1; + smd8 = &smdtty_data4; + smd11 = &smdtty_data11; + smd21 = &smdtty_data21; + smd36 = &smdtty_loopback; + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 for SD card */ + i2c2 = &i2c_2; + i2c3 = &i2c_3; + i2c5 = &i2c_5; + spi3 = &spi_3; + }; + + soc: soc { }; + +}; + +#include "msm8953-pinctrl.dtsi" +#include "msm8953-cpu.dtsi" +#include "msm8953-pm.dtsi" +#include "msm8953-bus.dtsi" +#include "msm8953-coresight.dtsi" +#include "msm8953-ion.dtsi" +#include "msm-arm-smmu-8953.dtsi" +#include "msm8953-gpu.dtsi" + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + dcc: dcc@b3000 { + compatible = "qcom,dcc"; + reg = <0xb3000 0x1000>, + <0xb4000 0x800>; + reg-names = "dcc-base", "dcc-ram-base"; + + clocks = <&clock_gcc clk_gcc_dcc_clk>; + clock-names = "apb_pclk"; + qcom,save-reg; + }; + + apc_apm: apm@b111000 { + compatible = "qcom,msm8953-apm"; + reg = <0xb111000 0x1000>; + reg-names = "pm-apcc-glb"; + qcom,apm-post-halt-delay = <0x2>; + qcom,apm-halt-clk-delay = <0x11>; + qcom,apm-resume-clk-delay = <0x10>; + qcom,apm-sel-switch-delay = <0x01>; + }; + + intc: interrupt-controller@b000000 { + compatible = "qcom,msm-qgic2"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x0b000000 0x1000>, + <0x0b002000 0x1000>; + }; + + qcom,msm-gladiator@b1c0000 { + compatible = "qcom,msm-gladiator"; + reg = <0x0b1c0000 0x4000>; + reg-names = "gladiator_base"; + interrupts = <0 22 0>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 2 0xff08>, + <1 3 0xff08>, + <1 4 0xff08>, + <1 1 0xff08>; + clock-frequency = <19200000>; + }; + + timer@b120000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0xb120000 0x1000>; + clock-frequency = <19200000>; + + frame@b121000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0xb121000 0x1000>, + <0xb122000 0x1000>; + }; + + frame@b123000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0xb123000 0x1000>; + status = "disabled"; + }; + + frame@b124000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0xb124000 0x1000>; + status = "disabled"; + }; + + frame@b125000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0xb125000 0x1000>; + status = "disabled"; + }; + + frame@b126000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0xb126000 0x1000>; + status = "disabled"; + }; + + frame@b127000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0xb127000 0x1000>; + status = "disabled"; + }; + + frame@b128000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0xb128000 0x1000>; + status = "disabled"; + }; + }; + qcom,rmtfs_sharedmem@00000000 { + compatible = "qcom,sharedmem-uio"; + reg = <0x00000000 0x00180000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + }; + + restart@4ab000 { + compatible = "qcom,pshold"; + reg = <0x4ab000 0x4>, + <0x193d100 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom,mpm2-sleep-counter@4a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x4a3000 0x1000>; + clock-frequency = <32768>; + }; + + cpu-pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <1 7 0xff00>; + }; + + qcom,sps { + compatible = "qcom,msm_sps_4k"; + qcom,pipe-attr-ee; + }; + + thermal_zones: thermal-zones {}; + + tsens0: tsens@4a8000 { + compatible = "qcom,msm8953-tsens"; + reg = <0x4a8000 0x1000>, + <0x4a9000 0x1000>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 184 0>, <0 314 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + qcom_seecom: qseecom@85b00000 { + compatible = "qcom,qseecom"; + reg = <0x85b00000 0x800000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,support-bus-scaling; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 0 0>, + <55 512 120000 1200000>, + <55 512 393600 3936000>; + clocks = <&clock_gcc clk_crypto_clk_src>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,ce-opp-freq = <100000000>; + status = "okay"; + }; + + qcom_tzlog: tz-log@08600720 { + compatible = "qcom,tz-log"; + reg = <0x08600720 0x2000>; + status = "okay"; + }; + + qcom_rng: qrng@e3000 { + compatible = "qcom,msm-rng"; + reg = <0xe3000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 800>; /* 100 MB/s */ + clocks = <&clock_gcc clk_gcc_prng_ahb_clk>; + clock-names = "iface_clk"; + status = "okay"; + }; + + qcom_crypto: qcrypto@720000 { + compatible = "qcom,qcrypto"; + reg = <0x720000 0x20000>, + <0x704000 0x20000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 207 0>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 393600 393600>; + clocks = <&clock_gcc clk_crypto_clk_src>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-hmac-algo; + qcom,use-sw-aead-algo; + qcom,ce-opp-freq = <100000000>; + status = "okay"; + }; + + qcom_cedev: qcedev@720000 { + compatible = "qcom,qcedev"; + reg = <0x720000 0x20000>, + <0x704000 0x20000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 207 0>; + qcom,bam-pipe-pair = <1>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 393600 393600>; + clocks = <&clock_gcc clk_crypto_clk_src>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,ce-opp-freq = <100000000>; + status = "okay"; + }; + + blsp1_uart0: serial@78af000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x78af000 0x200>; + interrupts = <0 107 0>; + clocks = <&clock_gcc clk_gcc_blsp1_uart1_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + clock-names = "core", "iface"; + status = "disabled"; + }; + + blsp1_uart1: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &tlmm 13 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xFD>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp2_uart0: uart@7aef000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x7aef000 0x200>, + <0x7ac4000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp2_uart0>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 306 0 + 1 &intc 0 239 0 + 2 &tlmm 17 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xFD>; + qcom,master-id = <84>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp2_uart1_apps_clk>, + <&clock_gcc clk_gcc_blsp2_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp2_uart0_sleep>; + pinctrl-1 = <&blsp2_uart0_active>; + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,msm-bus,name = "blsp2_uart0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + status = "disabled"; + }; + + blsp1_serial1: serial@78b0000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x78b0000 0x200>; + interrupts = <0 108 0>; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + clock-names = "core", "iface"; + status = "disabled"; + }; + + dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0x7884000 0x1f000>; + interrupts = <0 238 0>; + qcom,summing-threshold = <10>; + }; + + dma_blsp2: qcom,sps-dma@7ac4000 { /* BLSP2 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0x7ac4000 0x1f000>; + interrupts = <0 239 0>; + qcom,summing-threshold = <10>; + }; + + spi_3: spi@78b7000 { /* BLSP1 QUP3 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x78b7000 0x600>, + <0x7884000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 97 0>, <0 238 0>; + spi-max-frequency = <19200000>; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi3_default &spi3_cs0_active>; + pinctrl-1 = <&spi3_sleep &spi3_cs0_sleep>; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_spi_apps_clk>; + clock-names = "iface_clk", "core_clk"; + qcom,infinite-mode = <0>; + qcom,use-bam; + qcom,use-pinctrl; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <8>; + qcom,bam-producer-pipe-index = <9>; + qcom,master-id = <86>; + status = "disabled"; + }; + + i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0x78b6000 0x600>; + interrupt-names = "qup_irq"; + interrupts = <0 96 0>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup2_i2c_apps_clk>; + + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_2_active>; + pinctrl-1 = <&i2c_2_sleep>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + qcom,master-id = <86>; + dmas = <&dma_blsp1 6 64 0x20000020 0x20>, + <&dma_blsp1 7 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0x78b7000 0x600>; + interrupt-names = "qup_irq"; + interrupts = <0 97 0>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; + + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_3_active>; + pinctrl-1 = <&i2c_3_sleep>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + qcom,master-id = <86>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + i2c_5: i2c@7af5000 { /* BLSP2 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0x7af5000 0x600>; + interrupt-names = "qup_irq"; + interrupts = <0 299 0>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, + <&clock_gcc clk_gcc_blsp2_qup1_i2c_apps_clk>; + + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_5_active>; + pinctrl-1 = <&i2c_5_sleep>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + qcom,master-id = <84>; + dmas = <&dma_blsp2 4 64 0x20000020 0x20>, + <&dma_blsp2 5 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + slim_msm: slim@c140000{ + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0xc140000 0x2c000>, + <0xc104000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0>, <0 180 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x600000>; + qcom,ea-pc = <0x200>; + status = "disabled"; + }; + + clock_gcc: qcom,gcc@1800000 { + compatible = "qcom,gcc-8953"; + reg = <0x1800000 0x80000>, + <0x00a4124 0x08>; + reg-names = "cc_base", "efuse"; + vdd_dig-supply = <&pm8953_s2_level>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_debug: qcom,cc-debug@1874000 { + compatible = "qcom,cc-debug-8953"; + reg = <0x1874000 0x4>; + reg-names = "cc_base"; + clocks = <&clock_cpu clk_cpu_debug_pri_mux>; + clock-names = "debug_cpu_clk"; + #clock-cells = <1>; + }; + + clock_gcc_gfx: qcom,gcc-gfx@1800000 { + compatible = "qcom,gcc-gfx-8953"; + reg = <0x1800000 0x80000>; + reg-names = "cc_base"; + vdd_gfx-supply = <&gfx_vreg_corner>; + clocks = <&clock_gcc clk_xo_clk_src>; + clock-names = "xo"; + qcom,gfxfreq-corner = + < 0 0 >, + < 133330000 1 >, /* Min SVS */ + < 216000000 2 >, /* Low SVS */ + < 320000000 3 >, /* SVS */ + < 400000000 4 >, /* SVS Plus */ + < 510000000 5 >, /* NOM */ + < 560000000 6 >, /* Nom Plus */ + < 650000000 7 >; /* Turbo */ + #clock-cells = <1>; + }; + + clock_cpu: qcom,cpu-clock-8953@b116000 { + compatible = "qcom,cpu-clock-8953"; + reg = <0xb114000 0x68>, + <0xb014000 0x68>, + <0xb116000 0x400>, + <0xb111050 0x08>, + <0xb011050 0x08>, + <0xb1d1050 0x08>, + <0x00a4124 0x08>; + reg-names = "rcgwr-c0-base", "rcgwr-c1-base", + "c0-pll", "c0-mux", "c1-mux", + "cci-mux", "efuse"; + vdd-mx-supply = <&pm8953_s7_level_ao>; + vdd-cl-supply = <&apc_vreg>; + clocks = <&clock_gcc clk_xo_a_clk_src>; + clock-names = "xo_a"; + qcom,num-clusters = <2>; + qcom,speed0-bin-v0-cl = + < 0 0>, + < 652800000 1>, + < 1036800000 2>, + < 1401600000 3>, + < 1689600000 4>, + < 1804800000 5>, + < 1958400000 6>, + < 2016000000 7>; + qcom,speed0-bin-v0-cci = + < 0 0>, + < 261120000 1>, + < 414720000 2>, + < 560640000 3>, + < 675840000 4>, + < 721920000 5>, + < 783360000 6>, + < 806400000 7>; + qcom,speed2-bin-v0-cl = + < 0 0>, + < 652800000 1>, + < 1036800000 2>, + < 1401600000 3>, + < 1689600000 4>, + < 1804800000 5>, + < 1958400000 6>, + < 2016000000 7>; + qcom,speed2-bin-v0-cci = + < 0 0>, + < 261120000 1>, + < 414720000 2>, + < 560640000 3>, + < 675840000 4>, + < 721920000 5>, + < 783360000 6>, + < 806400000 7>; + qcom,speed7-bin-v0-cl = + < 0 0>, + < 652800000 1>, + < 1036800000 2>, + < 1401600000 3>, + < 1689600000 4>, + < 1804800000 5>, + < 1958400000 6>, + < 2016000000 7>, + < 2150400000 8>, + < 2208000000 9>; + qcom,speed7-bin-v0-cci = + < 0 0>, + < 261120000 1>, + < 414720000 2>, + < 560640000 3>, + < 675840000 4>, + < 721920000 5>, + < 783360000 6>, + < 806400000 7>, + < 860160000 8>, + < 883200000 9>; + qcom,speed6-bin-v0-cl = + < 0 0>, + < 652800000 1>, + < 1036800000 2>, + < 1401600000 3>, + < 1689600000 4>, + < 1804800000 5>; + qcom,speed6-bin-v0-cci = + < 0 0>, + < 261120000 1>, + < 414720000 2>, + < 560640000 3>, + < 675840000 4>, + < 721920000 5>; + #clock-cells = <1>; + }; + + msm_cpufreq: qcom,msm-cpufreq { + compatible = "qcom,msm-cpufreq"; + clock-names = "l2_clk", "cpu0_clk", "cpu1_clk", "cpu2_clk", + "cpu3_clk", "cpu4_clk", "cpu5_clk", + "cpu6_clk", "cpu7_clk"; + clocks = <&clock_cpu clk_cci_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>, + <&clock_cpu clk_a53_pwr_clk>; + + qcom,cpufreq-table = + < 652800 >, + < 1036800 >, + < 1401600 >, + < 1689600 >, + < 1804800 >, + < 1958400 >, + < 2016000 >, + < 2150400 >, + < 2208000 >; + }; + + cpubw: qcom,cpubw { + compatible = "qcom,devbw"; + governor = "cpufreq"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < 769 /* 100.8 MHz */ >, + < 1611 /* 211.2 MHz */ >, /*Low SVS*/ + < 2124 /* 278.4 MHz */ >, + < 2929 /* 384 MHz */ >, + < 3221 /* 422.4 MHz */ >, /* SVS */ + < 4248 /* 556.8 MHz */ >, + < 5126 /* 672 MHz */ >, + < 5859 /* 768 MHz */ >, /* SVS+ */ + < 6152 /* 806.4 MHz */ >, + < 6445 /* 844.8 MHz */ >, /* NOM */ + < 7104 /* 931.2 MHz */ >; /* TURBO */ + }; + + mincpubw: qcom,mincpubw { + compatible = "qcom,devbw"; + governor = "cpufreq"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < 769 /* 100.8 MHz */ >, + < 1611 /* 211.2 MHz */ >, /*Low SVS*/ + < 2124 /* 278.4 MHz */ >, + < 2929 /* 384 MHz */ >, + < 3221 /* 422.4 MHz */ >, /* SVS */ + < 4248 /* 556.8 MHz */ >, + < 5126 /* 672 MHz */ >, + < 5859 /* 768 MHz */ >, /* SVS+ */ + < 6152 /* 806.4 MHz */ >, + < 6445 /* 844.8 MHz */ >, /* NOM */ + < 7104 /* 931.2 MHz */ >; /* TURBO */ + }; + + qcom,cpu-bwmon { + compatible = "qcom,bimc-bwmon2"; + reg = <0x408000 0x300>, <0x401000 0x200>; + reg-names = "base", "global_base"; + interrupts = <0 183 4>; + qcom,mport = <0>; + qcom,target-dev = <&cpubw>; + }; + + devfreq-cpufreq { + cpubw-cpufreq { + target-dev = <&cpubw>; + cpu-to-dev-map = + < 652800 1611>, + < 1036800 3221>, + < 1401600 5859>, + < 1689600 6445>, + < 1804800 7104>, + < 1958400 7104>, + < 2208000 7104>; + }; + + mincpubw-cpufreq { + target-dev = <&mincpubw>; + cpu-to-dev-map = + < 652800 1611 >, + < 1401600 3221 >, + < 2208000 5859 >; + }; + }; + + cpubw_compute: qcom,cpubw-compute { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = < &CPU0 &CPU1 &CPU2 &CPU3 + &CPU4 &CPU5 &CPU6 &CPU7 >; + qcom,target-dev = <&cpubw>; + qcom,core-dev-table = + < 652800 1611>, + < 1036800 3221>, + < 1401600 5859>, + < 1689600 6445>, + < 1804800 7104>, + < 1958400 7104>, + < 2208000 7104>; + }; + + mincpubw_compute: qcom,mincpubw-compute { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = < &CPU0 &CPU1 &CPU2 &CPU3 + &CPU4 &CPU5 &CPU6 &CPU7 >; + qcom,target-dev = <&mincpubw>; + qcom,core-dev-table = + < 652800 1611 >, + < 1401600 3221 >, + < 2208000 5859 >; + }; + + qcom,ipc-spinlock@1905000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1905000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,smem@86300000 { + compatible = "qcom,smem"; + reg = <0x86300000 0x100000>, + <0x0b011008 0x4>, + <0x60000 0x8000>, + <0x193d000 0x8>; + reg-names = "smem", "irq-reg-base", + "aux-mem1", "smem_targ_info_reg"; + qcom,mpu-enabled; + + qcom,smd-modem { + compatible = "qcom,smd"; + qcom,smd-edge = <0>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x1000>; + interrupts = <0 25 1>; + label = "modem"; + qcom,not-loadable; + }; + + qcom,smsm-modem { + compatible = "qcom,smsm"; + qcom,smsm-edge = <0>; + qcom,smsm-irq-offset = <0x0>; + qcom,smsm-irq-bitmask = <0x2000>; + interrupts = <0 26 1>; + }; + + qcom,smd-wcnss { + compatible = "qcom,smd"; + qcom,smd-edge = <6>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x20000>; + interrupts = <0 142 1>; + label = "wcnss"; + }; + + qcom,smsm-wcnss { + compatible = "qcom,smsm"; + qcom,smsm-edge = <6>; + qcom,smsm-irq-offset = <0x0>; + qcom,smsm-irq-bitmask = <0x80000>; + interrupts = <0 144 1>; + }; + + qcom,smd-adsp { + compatible = "qcom,smd"; + qcom,smd-edge = <1>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x100>; + interrupts = <0 289 1>; + label = "adsp"; + }; + + qcom,smsm-adsp { + compatible = "qcom,smsm"; + qcom,smsm-edge = <1>; + qcom,smsm-irq-offset = <0x0>; + qcom,smsm-irq-bitmask = <0x200>; + interrupts = <0 290 1>; + }; + + qcom,smd-rpm { + compatible = "qcom,smd"; + qcom,smd-edge = <15>; + qcom,smd-irq-offset = <0x0>; + qcom,smd-irq-bitmask = <0x1>; + interrupts = <0 168 1>; + label = "rpm"; + qcom,irq-no-suspend; + qcom,not-loadable; + }; + }; + + qcom,smdtty { + compatible = "qcom,smdtty"; + + smdtty_apps_fm: qcom,smdtty-apps-fm { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_FM"; + }; + + smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_BT_ACL"; + }; + + smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_BT_CMD"; + }; + + smdtty_mbalbridge: qcom,smdtty-mbalbridge { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "MBALBRIDGE"; + }; + + smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD"; + }; + + smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data { + qcom,smdtty-remote = "wcnss"; + qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA"; + }; + + smdtty_data1: qcom,smdtty-data1 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA1"; + }; + + smdtty_data4: qcom,smdtty-data4 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA4"; + }; + + smdtty_data11: qcom,smdtty-data11 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA11"; + }; + + smdtty_data21: qcom,smdtty-data21 { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "DATA21"; + }; + + smdtty_loopback: smdtty-loopback { + qcom,smdtty-remote = "modem"; + qcom,smdtty-port-name = "LOOPBACK"; + qcom,smdtty-dev-name = "LOOPBACK_TTY"; + }; + }; + + qcom,smdpkt { + compatible = "qcom,smdpkt"; + + qcom,smdpkt-data5-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA5_CNTL"; + qcom,smdpkt-dev-name = "smdcntl0"; + }; + + qcom,smdpkt-data22 { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA22"; + qcom,smdpkt-dev-name = "smd22"; + }; + + qcom,smdpkt-data40-cntl { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "DATA40_CNTL"; + qcom,smdpkt-dev-name = "smdcntl8"; + }; + + qcom,smdpkt-apr-apps2 { + qcom,smdpkt-remote = "adsp"; + qcom,smdpkt-port-name = "apr_apps2"; + qcom,smdpkt-dev-name = "apr_apps2"; + }; + + qcom,smdpkt-loopback { + qcom,smdpkt-remote = "modem"; + qcom,smdpkt-port-name = "LOOPBACK"; + qcom,smdpkt-dev-name = "smd_pkt_loopback"; + }; + }; + + rpm_bus: qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + rpm-channel-name = "rpm_requests"; + rpm-channel-type = <15>; /* SMD_APPS_RPM */ + }; + + wdog: qcom,wdt@b017000 { + compatible = "qcom,msm-watchdog"; + reg = <0xb017000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 3 0>, <0 4 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <10000>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; + + qcom,chd { + compatible = "qcom,core-hang-detect"; + qcom,threshold-arr = <0xb1880b0 0xb1980b0 0xb1a80b0 + 0xb1b80b0 0xb0880b0 0xb0980b0 0xb0a80b0 0xb0b80b0>; + qcom,config-arr = <0xb1880b8 0xb1980b8 0xb1a80b8 + 0xb1b80b8 0xb0880b8 0xb0980b8 0xb0a80b8 0xb0b80b8>; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,msm-imem@8600000 { + compatible = "qcom,msm-imem"; + reg = <0x08600000 0x1000>; + ranges = <0x0 0x08600000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + dload_type@18 { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x18 4>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + + }; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x200000>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x300000>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <1>; + label = "modem"; + }; + }; + sdcc1_ice: sdcc1ice@7803000 { + compatible = "qcom,ice"; + reg = <0x7803000 0x8000>; + interrupt-names = "sdcc_ice_nonsec_level_irq", + "sdcc_ice_sec_level_irq"; + interrupts = <0 312 0>, <0 313 0>; + qcom,enable-ice-clk; + clock-names = "ice_core_clk_src", "ice_core_clk", + "bus_clk", "iface_clk"; + clocks = <&clock_gcc clk_sdcc1_ice_core_clk_src>, + <&clock_gcc clk_gcc_sdcc1_ice_core_clk>, + <&clock_gcc clk_gcc_sdcc1_apps_clk>, + <&clock_gcc clk_gcc_sdcc1_ahb_clk>; + qcom,op-freq-hz = <270000000>, <0>, <0>, <0>; + qcom,msm-bus,name = "sdcc_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <78 512 0 0>, /* No vote */ + <78 512 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", "MAX"; + qcom,instance-type = "sdcc"; + }; + + sdhc_1: sdhci@7824900 { + compatible = "qcom,sdhci-msm"; + reg = <0x7824900 0x500>, <0x7824000 0x800>, <0x7824e00 0x200>; + reg-names = "hc_mem", "core_mem", "cmdq_mem"; + + interrupts = <0 123 0>, <0 138 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + sdhc-msm-crypto = <&sdcc1_ice>; + qcom,bus-width = <8>; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <2 213>; + + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cmdq-latency-us = <2 213>, <2 213>; + + qcom,pm-qos-legacy-latency-us = <2 213>, <2 213>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */ + <78 512 1046 3200>, /* 400 KB/s*/ + <78 512 52286 160000>, /* 20 MB/s */ + <78 512 65360 200000>, /* 25 MB/s */ + <78 512 130718 400000>, /* 50 MB/s */ + <78 512 130718 400000>, /* 100 MB/s */ + <78 512 261438 800000>, /* 200 MB/s */ + <78 512 261438 800000>, /* 400 MB/s */ + <78 512 1338562 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + clocks = <&clock_gcc clk_gcc_sdcc1_ahb_clk>, + <&clock_gcc clk_gcc_sdcc1_apps_clk>, + <&clock_gcc clk_gcc_sdcc1_ice_core_clk>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + qcom,ice-clk-rates = <270000000 160000000>; + qcom,large-address-bus; + + status = "disabled"; + }; + + sdhc_2: sdhci@7864900 { + compatible = "qcom,sdhci-msm"; + reg = <0x7864900 0x500>, <0x7864000 0x800>; + reg-names = "hc_mem", "core_mem"; + + interrupts = <0 125 0>, <0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <2 213>; + + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-legacy-latency-us = <2 213>, <2 213>; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */ + <81 512 1046 3200>, /* 400 KB/s*/ + <81 512 52286 160000>, /* 20 MB/s */ + <81 512 65360 200000>, /* 25 MB/s */ + <81 512 130718 400000>, /* 50 MB/s */ + <81 512 261438 800000>, /* 100 MB/s */ + <81 512 261438 800000>, /* 200 MB/s */ + <81 512 1338562 4096000>; /* Max. bandwidth */ + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>, + <&clock_gcc clk_gcc_sdcc2_apps_clk>; + clock-names = "iface_clk", "core_clk"; + + qcom,large-address-bus; + status = "disabled"; + }; + + ipa_hw: qcom,ipa@07900000 { + compatible = "qcom,ipa"; + reg = <0x07900000 0x4effc>, <0x07904000 0x26934>; + reg-names = "ipa-base", "bam-base"; + interrupts = <0 228 0>, + <0 230 0>; + interrupt-names = "ipa-irq", "bam-irq"; + qcom,ipa-hw-ver = <6>; /* IPA core version = IPAv2.6L */ + qcom,ipa-hw-mode = <0>; /* IPA hw type = Normal */ + qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/ + qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/ + clock-names = "core_clk"; + clocks = <&clock_gcc clk_ipa_clk>; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <90 512 0 0>, /* No BIMC vote (ab=0 Mbps, ib=0 Mbps ~ 0MHZ) */ + <90 512 100000 800000>, /* SVS (ab=100, ib=800 ~ 50MHz) */ + <90 512 100000 1200000>; /* PERF (ab=100, ib=1200 ~ 75MHz) */ + qcom,bus-vector-names = "MIN", "SVS", "PERF"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa"; + qcom,rmnet-ipa-ssr; + qcom,ipa-loaduC; + qcom,ipa-advertise-sg-support; + }; + + spmi_bus: qcom,spmi@200f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x200f000 0x1000>, + <0x2400000 0x800000>, + <0x2c00000 0x800000>, + <0x3800000 0x200000>, + <0x200a000 0x2100>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + usb3: ssusb@7000000{ + compatible = "qcom,dwc-usb3-msm"; + reg = <0x07000000 0xfc000>, + <0x0007e000 0x400>; + reg-names = "core_base", + "ahb2phy_base"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 136 0>, <0 220 0>, <0 134 0>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", "pwr_event_irq"; + + USB3_GDSC-supply = <&gdsc_usb30>; + qcom,usb-dbm = <&dbm_1p5>; + qcom,msm-bus,name = "usb3"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <61 512 0 0>, + <61 512 240000 800000>, + <61 512 240000 800000>; + + /* CPU-CLUSTER-WFI-LVL latency +1 */ + qcom,pm-qos-latency = <2>; + + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + + clocks = <&clock_gcc clk_gcc_usb30_master_clk>, + <&clock_gcc clk_gcc_pcnoc_usb3_axi_clk>, + <&clock_gcc clk_gcc_usb30_mock_utmi_clk>, + <&clock_gcc clk_gcc_usb30_sleep_clk>, + <&clock_gcc clk_xo_dwc3_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb_clk>; + + clock-names = "core_clk", "iface_clk", "utmi_clk", + "sleep_clk", "xo", "cfg_ahb_clk"; + + qcom,core-clk-rate = <133333333>; /* NOM */ + qcom,core-clk-rate-hs = <60000000>; /* LOW SVS */ + + resets = <&clock_gcc GCC_USB_30_BCR>; + reset-names = "core_reset"; + + dwc3@7000000 { + compatible = "snps,dwc3"; + reg = <0x07000000 0xc8d0>; + interrupt-parent = <&intc>; + interrupts = <0 140 0>; + usb-phy = <&qusb_phy>, <&ssphy>; + tx-fifo-resize; + snps,usb3-u1u2-disable; + snps,nominal-elastic-buffer; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + }; + + qcom,usbbam@7104000 { + compatible = "qcom,usb-bam-msm"; + reg = <0x07104000 0x1a934>; + interrupt-parent = <&intc>; + interrupts = <0 135 0>; + + qcom,bam-type = <0>; + qcom,usb-bam-fifo-baseaddr = <0x08605000>; + qcom,usb-bam-num-pipes = <8>; + qcom,ignore-core-reset-ack; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-ipa-out-0"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <0>; + qcom,pipe-num = <0>; + qcom,peer-bam = <1>; + qcom,src-bam-pipe-index = <1>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + + qcom,pipe1 { + label = "ssusb-ipa-in-0"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <1>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + + qcom,pipe2 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x06044000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <2>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0xe00>; + qcom,descriptor-fifo-offset = <0xe00>; + qcom,descriptor-fifo-size = <0x200>; + }; + + qcom,pipe3 { + label = "ssusb-dpl-ipa-in-1"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <1>; + qcom,pipe-num = <1>; + qcom,peer-bam = <1>; + qcom,dst-bam-pipe-index = <2>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + }; + }; + + qusb_phy: qusb@79000 { + compatible = "qcom,qusb2phy"; + reg = <0x079000 0x180>, + <0x01841030 0x4>, + <0x0193f020 0x4>; + reg-names = "qusb_phy_base", + "ref_clk_addr", + "tcsr_clamp_dig_n_1p8"; + + USB3_GDSC-supply = <&gdsc_usb30>; + vdd-supply = <&pm8953_l3>; + vdda18-supply = <&pm8953_l7>; + vdda33-supply = <&pm8953_l13>; + qcom,vdd-voltage-level = <0 925000 925000>; + + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc0 0x8c + 0x14 0x9c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x00 0x90 + 0x9f 0x1c + 0x00 0x18>; + phy_type= "utmi"; + qcom,phy-clk-scheme = "cml"; + qcom,major-rev = <1>; + + clocks = <&clock_gcc clk_bb_clk1>, + <&clock_gcc clk_gcc_qusb_ref_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb_clk>, + <&clock_gcc clk_gcc_pcnoc_usb3_axi_clk>, + <&clock_gcc clk_gcc_usb30_master_clk>; + + clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk", + "iface_clk", "core_clk"; + + resets = <&clock_gcc GCC_QUSB2_PHY_BCR>; + reset-names = "phy_reset"; + }; + + ssphy: ssphy@78000 { + compatible = "qcom,usb-ssphy-qmp"; + reg = <0x78000 0x9f8>, + <0x0193f244 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; + + qcom,qmp-phy-init-seq = /**/ + <0xac 0x14 0x00 + 0x34 0x08 0x00 + 0x174 0x30 0x00 + 0x3c 0x06 0x00 + 0xb4 0x00 0x00 + 0xb8 0x08 0x00 + 0x194 0x06 0x3e8 + 0x19c 0x01 0x00 + 0x178 0x00 0x00 + 0xd0 0x82 0x00 + 0xdc 0x55 0x00 + 0xe0 0x55 0x00 + 0xe4 0x03 0x00 + 0x78 0x0b 0x00 + 0x84 0x16 0x00 + 0x90 0x28 0x00 + 0x108 0x80 0x00 + 0x10c 0x00 0x00 + 0x184 0x0a 0x00 + 0x4c 0x15 0x00 + 0x50 0x34 0x00 + 0x54 0x00 0x00 + 0xc8 0x00 0x00 + 0x18c 0x00 0x00 + 0xcc 0x00 0x00 + 0x128 0x00 0x00 + 0x0c 0x0a 0x00 + 0x10 0x01 0x00 + 0x1c 0x31 0x00 + 0x20 0x01 0x00 + 0x14 0x00 0x00 + 0x18 0x00 0x00 + 0x24 0xde 0x00 + 0x28 0x07 0x00 + 0x48 0x0f 0x00 + 0x70 0x0f 0x00 + 0x100 0x80 0x00 + 0x440 0x0b 0x00 + 0x4d8 0x02 0x00 + 0x4dc 0x6c 0x00 + 0x4e0 0xbb 0x00 + 0x508 0x77 0x00 + 0x50c 0x80 0x00 + 0x514 0x03 0x00 + 0x51c 0x16 0x00 + 0x448 0x75 0x00 + 0x454 0x00 0x00 + 0x40c 0x0a 0x00 + 0x41c 0x06 0x00 + 0x510 0x00 0x00 + 0x268 0x45 0x00 + 0x2ac 0x12 0x00 + 0x294 0x06 0x00 + 0x254 0x00 0x00 + 0x8c8 0x83 0x00 + 0x8c4 0x02 0x00 + 0x8cc 0x09 0x00 + 0x8d0 0xa2 0x00 + 0x8d4 0x85 0x00 + 0x880 0xd1 0x00 + 0x884 0x1f 0x00 + 0x888 0x47 0x00 + 0x80c 0x9f 0x00 + 0x824 0x17 0x00 + 0x828 0x0f 0x00 + 0x8b8 0x75 0x00 + 0x8bc 0x13 0x00 + 0x8b0 0x86 0x00 + 0x8a0 0x04 0x00 + 0x88c 0x44 0x00 + 0x870 0xe7 0x00 + 0x874 0x03 0x00 + 0x878 0x40 0x00 + 0x87c 0x00 0x00 + 0x9d8 0x88 0x00 + 0xffffffff 0x00 0x00>; + qcom,qmp-phy-reg-offset = + <0x974 /* USB3_PHY_PCS_STATUS */ + 0x8d8 /* USB3_PHY_AUTONOMOUS_MODE_CTRL */ + 0x8dc /* USB3_PHY_LFPS_RXTERM_IRQ_CLEAR */ + 0x804 /* USB3_PHY_POWER_DOWN_CONTROL */ + 0x800 /* USB3_PHY_SW_RESET */ + 0x808>; /* USB3_PHY_START */ + + vdd-supply = <&pm8953_l3>; + core-supply = <&pm8953_l7>; + qcom,vdd-voltage-level = <0 925000 925000>; + qcom,core-voltage-level = <0 1800000 1800000>; + qcom,vbus-valid-override; + + clocks = <&clock_gcc clk_gcc_usb3_aux_clk>, + <&clock_gcc clk_gcc_usb3_pipe_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb_clk>, + <&clock_gcc clk_bb_clk1>, + <&clock_gcc clk_gcc_usb_ss_ref_clk>; + + clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", + "ref_clk_src", "ref_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_BCR>; + + reset-names = "phy_reset", "phy_phy_reset"; + }; + + dbm_1p5: dbm@70f8000 { + compatible = "qcom,usb-dbm-1p5"; + reg = <0x070f8000 0x300>; + qcom,reset-ep-after-lpm-resume; + }; + + qcom,mss@4080000 { + compatible = "qcom,pil-q6v55-mss"; + reg = <0x04080000 0x100>, + <0x0194f000 0x010>, + <0x01950000 0x008>, + <0x01951000 0x008>, + <0x04020000 0x040>, + <0x01871000 0x004>; + reg-names = "qdsp6_base", "halt_q6", "halt_modem", "halt_nc", + "rmb_base", "restart_reg"; + + interrupts = ; + vdd_mss-supply = <&pm8953_s1>; + vdd_cx-supply = <&pm8953_s2_level>; + vdd_cx-voltage = ; + vdd_mx-supply = <&pm8953_s7_level_ao>; + vdd_mx-uV = ; + vdd_pll-supply = <&pm8953_l7>; + qcom,vdd_pll = <1800000>; + vdd_mss-uV = ; + + clocks = <&clock_gcc clk_xo_pil_mss_clk>, + <&clock_gcc clk_gcc_mss_cfg_ahb_clk>, + <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>, + <&clock_gcc clk_gcc_boot_rom_ahb_clk>; + clock-names = "xo", "iface_clk", "bus_clk", "mem_clk"; + qcom,proxy-clock-names = "xo"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk"; + + qcom,pas-id = <5>; + qcom,pil-mss-memsetup; + qcom,firmware-name = "modem"; + qcom,pil-self-auth; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,qdsp6v56-1-10; + qcom,reset-clk; + + memory-region = <&modem_mem>; + }; + + qcom,lpass@c200000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xc200000 0x00100>; + interrupts = <0 293 1>; + + vdd_cx-supply = <&pm8953_s2_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + qcom,mas-crypto = <&mas_crypto>; + + clocks = <&clock_gcc clk_xo_pil_lpass_clk>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>, + <&clock_gcc clk_crypto_clk_src>; + clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,scm_core_clk_src-freq = <80000000>; + + qcom,pas-id = <1>; + qcom,complete-ramdump; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + + memory-region = <&adsp_fw_mem>; + }; + + qcom,pronto@a21b000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x0a21b000 0x3000>; + interrupts = <0 149 1>; + + vdd_pronto_pll-supply = <&pm8953_l7>; + proxy-reg-names = "vdd_pronto_pll"; + vdd_pronto_pll-uV-uA = <1800000 18000>; + qcom,mas-crypto = <&mas_crypto>; + + clocks = <&clock_gcc clk_xo_pil_pronto_clk>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>, + <&clock_gcc clk_crypto_clk_src>; + + clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,scm_core_clk_src = <80000000>; + + qcom,pas-id = <6>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <422>; + qcom,sysmon-id = <6>; + qcom,ssctl-instance-id = <0x13>; + qcom,firmware-name = "wcnss"; + + memory-region = <&wcnss_fw_mem>; + }; + + qcom,venus@1de0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x1de0000 0x4000>; + + vdd-supply = <&gdsc_venus>; + qcom,proxy-reg-names = "vdd"; + qcom,mas-crypto = <&mas_crypto>; + + clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>, + <&clock_gcc clk_gcc_venus0_ahb_clk>, + <&clock_gcc clk_gcc_venus0_axi_clk>, + <&clock_gcc clk_gcc_crypto_clk>, + <&clock_gcc clk_gcc_crypto_ahb_clk>, + <&clock_gcc clk_gcc_crypto_axi_clk>, + <&clock_gcc clk_crypto_clk_src>; + + clock-names = "core_clk", "iface_clk", "bus_clk", + "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + + qcom,proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "scm_core_clk", + "scm_iface_clk", "scm_bus_clk", + "scm_core_clk_src"; + qcom,scm_core_clk_src-freq = <80000000>; + + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&venus_mem>; + }; + + qcom,wcnss-wlan@0a000000 { + compatible = "qcom,wcnss_wlan"; + reg = <0x0a000000 0x280000>, + <0x0b011008 0x04>, + <0x0a21b000 0x3000>, + <0x03204000 0x00000100>, + <0x03200800 0x00000200>, + <0x0a100400 0x00000200>, + <0x0a205050 0x00000200>, + <0x0a219000 0x00000020>, + <0x0a080488 0x00000008>, + <0x0a080fb0 0x00000008>, + <0x0a08040c 0x00000008>, + <0x0a0120a8 0x00000008>, + <0x0a012448 0x00000008>, + <0x0a080c00 0x00000001>; + + reg-names = "wcnss_mmio", "wcnss_fiq", + "pronto_phy_base", "riva_phy_base", + "riva_ccu_base", "pronto_a2xb_base", + "pronto_ccpu_base", "pronto_saw2_base", + "wlan_tx_phy_aborts","wlan_brdg_err_source", + "wlan_tx_status", "alarms_txctl", + "alarms_tactl", "pronto_mcu_base"; + + interrupts = <0 145 0 0 146 0>; + interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq"; + + qcom,pronto-vddmx-supply = <&pm8953_s7_level_ao>; + qcom,pronto-vddcx-supply = <&pm8953_s2_level>; + qcom,pronto-vddpx-supply = <&pm8953_l5>; + qcom,iris-vddxo-supply = <&pm8953_l7>; + qcom,iris-vddrfa-supply = <&pm8953_l19>; + qcom,iris-vddpa-supply = <&pm8953_l9>; + qcom,iris-vdddig-supply = <&pm8953_l5>; + + qcom,iris-vddxo-voltage-level = <1800000 0 1800000>; + qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>; + qcom,iris-vddpa-voltage-level = <3300000 0 3300000>; + qcom,iris-vdddig-voltage-level = <1800000 0 1800000>; + + qcom,vddmx-voltage-level = ; + qcom,vddcx-voltage-level = ; + qcom,vddpx-voltage-level = <1800000 0 1800000>; + + qcom,iris-vddxo-current = <10000>; + qcom,iris-vddrfa-current = <100000>; + qcom,iris-vddpa-current = <515000>; + qcom,iris-vdddig-current = <10000>; + + qcom,pronto-vddmx-current = <0>; + qcom,pronto-vddcx-current = <0>; + qcom,pronto-vddpx-current = <0>; + + pinctrl-names = "wcnss_default", "wcnss_sleep", + "wcnss_gpio_default"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; + pinctrl-2 = <&wcnss_gpio_default>; + + gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>, + <&tlmm 79 0>, <&tlmm 80 0>; + + clocks = <&clock_gcc clk_xo_wlan_clk>, + <&clock_gcc clk_rf_clk2>, + <&clock_debug clk_gcc_debug_mux>, + <&clock_gcc clk_wcnss_m_clk>; + + clock-names = "xo", "rf_clk", "measure", "wcnss_debug"; + + qcom,has-autodetect-xo; + qcom,is-pronto-v3; + qcom,has-pronto-hw; + qcom,has-vsys-adc-channel; + qcom,has-a2xb-split-reg; + qcom,wcnss-adc_tm = <&pm8953_adc_tm>; + }; + +}; + +#include "pm8953-rpm-regulator.dtsi" +#include "pm8953.dtsi" +#include "msm8953-regulator.dtsi" +#include "msm-gdsc-8916.dtsi" +#include "msm8953-thermal.dtsi" + +&gdsc_venus { + clock-names = "bus_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_venus0_axi_clk>, + <&clock_gcc clk_gcc_venus0_vcodec0_clk>; + status = "okay"; +}; + +&gdsc_venus_core0 { + qcom,support-hw-trigger; + clock-names ="core0_clk"; + clocks = <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>; + status = "okay"; +}; + +&gdsc_mdss { + clock-names = "core_clk", "bus_clk"; + clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>, + <&clock_gcc clk_gcc_mdss_axi_clk>; + proxy-supply = <&gdsc_mdss>; + qcom,proxy-consumer-enable; + status = "okay"; +}; + +&gdsc_oxili_gx { + clock-names = "core_root_clk"; + clocks =<&clock_gcc_gfx clk_gfx3d_clk_src>; + qcom,force-enable-root-clk; + parent-supply = <&gfx_vreg_corner>; + status = "okay"; +}; + +&gdsc_jpeg { + clock-names = "core_clk", "bus_clk"; + clocks = <&clock_gcc clk_gcc_camss_jpeg0_clk>, + <&clock_gcc clk_gcc_camss_jpeg_axi_clk>; + status = "okay"; +}; + +&gdsc_vfe { + clock-names = "core_clk", "bus_clk", "micro_clk", + "csi_clk"; + clocks = <&clock_gcc clk_gcc_camss_vfe0_clk>, + <&clock_gcc clk_gcc_camss_vfe_axi_clk>, + <&clock_gcc clk_gcc_camss_micro_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe0_clk>; + status = "okay"; +}; + +&gdsc_vfe1 { + clock-names = "core_clk", "bus_clk", "micro_clk", + "csi_clk"; + clocks = <&clock_gcc clk_gcc_camss_vfe1_clk>, + <&clock_gcc clk_gcc_camss_vfe1_axi_clk>, + <&clock_gcc clk_gcc_camss_micro_ahb_clk>, + <&clock_gcc clk_gcc_camss_csi_vfe1_clk>; + status = "okay"; +}; + +&gdsc_cpp { + clock-names = "core_clk", "bus_clk"; + clocks = <&clock_gcc clk_gcc_camss_cpp_clk>, + <&clock_gcc clk_gcc_camss_cpp_axi_clk>; + status = "okay"; +}; + +&gdsc_oxili_cx { + clock-names = "core_clk"; + clocks = <&clock_gcc_gfx clk_gcc_oxili_gfx3d_clk>; + status = "okay"; +}; + +&gdsc_usb30 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/mtp8953-ipc.dts b/arch/arm64/boot/dts/qcom/mtp8953-ipc.dts new file mode 100644 index 0000000000000000000000000000000000000000..481e576142564e2fb0cecfe055e8af4ad2894f52 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/mtp8953-ipc.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016-2017, 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 "msm8953.dtsi" +#include "msm8953-ipc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 IPC"; + compatible = "qcom,msm8953-ipc", "qcom,msm8953", "qcom,ipc"; + qcom,board-id= <12 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4830af4a561709efff39c0856332dcb4fdcbf4ce --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm660.dtsi @@ -0,0 +1,706 @@ +/* Copyright (c) 2016-2018, 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 +#include +#include + +&spmi_bus { + pm660_0: qcom,pm660@0 { + compatible ="qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + qcom,fab-id-valid; + }; + + pm660_misc: qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm660_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pm660_tz"; + qcom,channel-num = <6>; + qcom,temp_alarm-vadc = <&pm660_vadc>; + #thermal-sensor-cells = <0>; + }; + + pm660_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xd00>; + interrupts = <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xca 0 IRQ_TYPE_NONE>, + <0x0 0xcb 0 IRQ_TYPE_NONE>, + <0x0 0xcc 0 IRQ_TYPE_NONE>; + interrupt-names = "pm660_gpio2", "pm660_gpio3", + "pm660_gpio4", "pm660_gpio9", + "pm660_gpio11", "pm660_gpio12", + "pm660_gpio13"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <1 5 6 7 8 10>; + }; + + pm660_coincell: qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + }; + + pm660_rtc: qcom,pm660_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm660_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + qcom,pm660_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + + pm660_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc-hc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + + chan@6 { + label = "die_temp"; + reg = <6>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@0 { + label = "ref_gnd"; + reg = <0>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@1 { + label = "ref_1250v"; + reg = <1>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@85 { + label = "vcoin"; + reg = <0x85>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4e { + label = "emmc_therm"; + reg = <0x4e>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@4f { + label = "pa_therm0"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@1d { + label = "drax_temp"; + reg = <0x1d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + }; + + pm660_pdphy: qcom,usb-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + vdd-pdphy-supply = <&pm660l_l7>; + vbus-supply = <0>; + vconn-supply = <0>; + interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>; /* 9V @ 3A */ + }; + + pm660_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm-hc"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + qcom,adc_tm-vadc = <&pm660_vadc>; + qcom,decimation = <0>; + qcom,fast-avg-setup = <0>; + #thermal-sensor-cells = <1>; + + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,btm-channel-number = <0x60>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; + + chan@4e { + label = "emmc_therm"; + reg = <0x4e>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x80>; + qcom,thermal-node; + }; + + chan@4f { + label = "pa_therm0"; + reg = <0x4f>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x88>; + qcom,thermal-node; + }; + }; + + bcl_sensor: bcl@4200 { + compatible = "qcom,msm-bcl-lmh"; + reg = <0x4200 0xff>, + <0x4300 0xff>; + reg-names = "fg_user_adc", + "fg_lmh"; + interrupts = <0x0 0x42 0x0 IRQ_TYPE_NONE>, + <0x0 0x42 0x1 IRQ_TYPE_NONE>, + <0x0 0x42 0x2 IRQ_TYPE_NONE>, + <0x0 0x42 0x3 IRQ_TYPE_NONE>, + <0x0 0x42 0x4 IRQ_TYPE_NONE>; + interrupt-names = "bcl-high-ibat", + "bcl-very-high-ibat", + "bcl-low-vbat", + "bcl-very-low-vbat", + "bcl-crit-low-vbat"; + #thermal-sensor-cells = <1>; + }; + + pm660_div_clk: qcom,clkdiv@5b00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <1>; + qcom,clkdiv-init-freq = <9600000>; + status = "disabled"; + }; + }; + + pm660_1: qcom,pm660@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + }; +}; + +&thermal_zones { + xo-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4c>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + msm-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4d>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + emmc-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4e>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm0-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4f>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x51>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + ibat-high { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 0>; + + trips { + ibat-high { + temperature = <4200>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + ibat-vhigh { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 1>; + + trips { + ibat-vhigh { + temperature = <4300>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + vbat_adc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 2>; + tracks-low; + + trips { + pm660_vbat_adc: vbat-adc { + temperature = <3300>; + hysteresis = <100>; + type = "passive"; + }; + }; + cooling-maps { + vbat_map6 { + trip = <&pm660_vbat_adc>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_map7 { + trip = <&pm660_vbat_adc>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + vbat_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 3>; + tracks-low; + + trips { + vbat-low { + temperature = <3100>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + vbat_too_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 4>; + tracks-low; + + trips { + vbat-too-low { + temperature = <2900>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + soc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 5>; + tracks-low; + + trips { + pm660_low_soc: low-soc { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + soc_map6 { + trip = <&pm660_low_soc>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_map7 { + trip = <&pm660_low_soc>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm660_temp_alarm: pm660_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm660_tz>; + + trips { + pm660_trip0: pm660-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm660_trip1: pm660-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm660_trip2: pm660-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "critical"; + }; + }; + cooling-maps { + trip0_cpu0 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu1 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU1 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu2 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU2 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu3 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU3 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu4 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu5 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU5 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu6 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu7 { + trip = <&pm660_trip0>; + cooling-device = + <&CPU7 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip1_cpu1 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu2 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu3 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu4 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu5 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu6 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu7 { + trip = <&pm660_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm660a.dtsi b/arch/arm64/boot/dts/qcom/pm660a.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bfe1b5aa831bc1ab67f6967d8014c13200cbf427 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm660a.dtsi @@ -0,0 +1,29 @@ +/* Copyright (c) 2016-2017, 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. + */ + +/* Disable WLED */ +&pm660l_wled { + status = "disabled"; +}; + +/* disable LCDB */ +&pm660l_lcdb { + status = "disabled"; +}; + +&pm660a_oledb { + status = "okay"; +}; + +&pm660a_labibb { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bcb513871ed6b604efed327cec9eacda53c6e8b1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi @@ -0,0 +1,320 @@ +/* Copyright (c) 2016-2017, 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 +#include +#include + +&spmi_bus { + qcom,pm660l@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660l_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pm660l_pbs: qcom,pbs@7300 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7300 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = + ; + }; + + pm660l_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pm660l_tz"; + #thermal-sensor-cells = <0>; + }; + + pm660l_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x2 0xc2 0 IRQ_TYPE_NONE>, + <0x2 0xc3 0 IRQ_TYPE_NONE>, + <0x2 0xc4 0 IRQ_TYPE_NONE>, + <0x2 0xc5 0 IRQ_TYPE_NONE>, + <0x2 0xc6 0 IRQ_TYPE_NONE>, + <0x2 0xc7 0 IRQ_TYPE_NONE>, + <0x2 0xc8 0 IRQ_TYPE_NONE>; + interrupt-names = "pm660l_gpio3", "pm660l_gpio4", + "pm660l_gpio5", "pm660l_gpio6", + "pm660l_gpio7", "pm660l_gpio8", + "pm660l_gpio9"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <1 2 10 11 12>; + }; + }; + + pm660l_3: qcom,pm660l@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660l_pwm_1: pwm@b100 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb100 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,channel-id = <1>; + qcom,lpg-lut-size = <0x7e>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <0>; + #pwm-cells = <2>; + }; + + pm660l_pwm_2: pwm@b200 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb200 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,channel-id = <2>; + qcom,lpg-lut-size = <0x7e>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <1>; + #pwm-cells = <2>; + }; + + pm660l_pwm_3: pwm@b300 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb300 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,channel-id = <3>; + qcom,lpg-lut-size = <0x7e>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <2>; + #pwm-cells = <2>; + qcom,period = <6000000>; + + qcom,lpg { + label = "lpg"; + cell-index = <0>; + qcom,duty-percents = + <0x01 0x0a 0x14 0x1e 0x28 0x32 0x3c + 0x46 0x50 0x5a 0x64 + 0x64 0x5a 0x50 0x46 0x3c 0x32 0x28 0x1e + 0x14 0x0a 0x01>; + }; + }; + + pm660l_pwm_4: pwm@b400 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb400 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,channel-id = <4>; + qcom,lpg-lut-size = <0x7e>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <3>; + #pwm-cells = <2>; + status = "disabled"; + }; + + qcom,leds@d000 { + compatible = "qcom,leds-qpnp"; + reg = <0xd000 0x100>; + label = "rgb"; + + red_led: qcom,rgb_0 { + label = "rgb"; + qcom,id = <3>; + qcom,mode = "pwm"; + pwms = <&pm660l_pwm_3 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "red"; + qcom,start-idx = <0>; + qcom,idx-len = <22>; + qcom,duty-pcts = + [01 0a 14 1e 28 32 3c 46 50 5a 64 + 64 5a 50 46 3c 32 28 1e 14 0a 01]; + qcom,use-blink; + }; + + green_led: qcom,rgb_1 { + label = "rgb"; + qcom,id = <4>; + qcom,mode = "pwm"; + pwms = <&pm660l_pwm_2 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "green"; + }; + + blue_led: qcom,rgb_2 { + label = "rgb"; + qcom,id = <5>; + qcom,mode = "pwm"; + pwms = <&pm660l_pwm_1 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "blue"; + }; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,hdrm-auto-mode; + qcom,short-circuit-det; + qcom,open-circuit-det; + qcom,vph-droop-det; + qcom,thermal-derate-en; + qcom,thermal-derate-current = <200 500 1000>; + qcom,isc-delay = <192>; + qcom,pmic-revid = <&pm660l_revid>; + + pm660l_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch0_trigger"; + }; + + pm660l_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <4>; + qcom,default-led-trigger = "switch1_trigger"; + }; + }; + }; +}; + +&thermal_zones { + pm660l_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660l_tz>; + + trips { + pm660l_trip0: pm660l-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm660l_trip1: pm660l-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm660l_trip2: pm660l-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi index 1f8d20e9dd578d02145accb25182cad5412d288b..aff92a8100a2a3125b3214f73770c0511b02d203 100644 --- a/arch/arm64/boot/dts/qcom/pm8005.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,11 +25,12 @@ reg = <0x100 0x100>; }; - qcom,temp-alarm@2400 { + pm8005_tz: qcom,temp-alarm@2400 { compatible = "qcom,qpnp-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>; label = "pm8005_tz"; + #thermal-sensor-cells = <0>; }; pm8005_gpios: pinctrl@c000 { @@ -79,3 +80,28 @@ }; }; }; + +&thermal_zones { + pm8005_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8005_tz>; + trips { + pm8005-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm8005-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm8005-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8937-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8937-rpm-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..33a5e162845becd49388a3d9392bc77ddcbd59b2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8937-rpm-regulator.dtsi @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&rpm_bus { + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <4>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_s4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <9>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa14 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <14>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l14 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l14"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa15 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <15>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l15 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l15"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa16 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <16>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l16 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l16"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa17 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <17>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l17 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l17"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa19 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <19>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l19 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l19"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa22 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <22>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l22 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l22"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa23 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <23>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l23 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8937_l23"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8937.dtsi b/arch/arm64/boot/dts/qcom/pm8937.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6a61445846d498a5b7d3db29331a5be4cedf86e5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8937.dtsi @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2015-2018, 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. + */ + +&spmi_bus { + + qcom,pm8937@0 { + compatible ="qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm8937_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,system-reset; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm8937_temp_alarm: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pm8937_tz"; + qcom,channel-num = <8>; + qcom,threshold-set = <0>; + qcom,temp_alarm-vadc = <&pm8937_vadc>; + }; + + pm8937_coincell: qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + }; + + pm8937_rtc: qcom,pm8937_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8937_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + + qcom,pm8937_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + + pm8937_mpps: mpps { + compatible = "qcom,spmi-mpp"; + reg = <0xa000 0x400>; + interrupts = <0x0 0xa0 0 IRQ_TYPE_NONE>, + <0x0 0xa1 0 IRQ_TYPE_NONE>, + <0x0 0xa2 0 IRQ_TYPE_NONE>, + <0x0 0xa3 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8937_mpp1", "pm8937_mpp2", + "pm8937_mpp3", "pm8937_mpp4"; + gpio-controller; + #gpio-cells = <2>; + }; + + pm8937_gpios: gpios { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x800>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8937_gpio1", "pm8937_gpio2", + "pm8937_gpio5", "pmi8937_gpio7", + "pm8937_gpio8"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <3 4 6>; + }; + + pm8937_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + + chan@5 { + label = "vcoin"; + reg = <5>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@7 { + label = "vph_pwr"; + reg = <7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@8 { + label = "die_temp"; + reg = <8>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@c { + label = "ref_buf_625mv"; + reg = <0xc>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@11 { + label = "pa_therm1"; + reg = <0x11>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@32 { + label = "xo_therm"; + reg = <0x32>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@3c { + label = "xo_therm_buf"; + reg = <0x3c>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@13 { + label = "case_therm"; + reg = <0x13>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + }; + + pm8937_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set", + "high-thr-en-set", + "low-thr-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,adc_tm-vadc = <&pm8937_vadc>; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,btm-channel-number = <0x48>; + qcom,thermal-node; + }; + + chan@7 { + label = "vph_pwr"; + reg = <0x7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,btm-channel-number = <0x68>; + }; + }; + + }; + + pm8937_1: qcom,pm8937@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm8937_pwm: pwm@bc00 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xbc00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8950.dtsi b/arch/arm64/boot/dts/qcom/pm8950.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f47872a5ab74274e995eddcca364b84b3d0bac0e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8950.dtsi @@ -0,0 +1,388 @@ +/* Copyright (c) 2015-2017, 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. + */ + +&spmi_bus { + qcom,pm8950@0 { + compatible ="qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8950_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pm8950_temp_alarm: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0>; + label = "pm8950_tz"; + qcom,channel-num = <8>; + qcom,threshold-set = <0>; + qcom,temp_alarm-vadc = <&pm8950_vadc>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0>, + <0x0 0x8 0x1>, + <0x0 0x8 0x4>, + <0x0 0x8 0x5>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,system-reset; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm8950_coincell: qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + }; + + pm8950_mpps: mpps { + compatible = "qcom,qpnp-pin"; + spmi-dev-container; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pm8950-mpp"; + + mpp@a000 { + reg = <0xa000 0x100>; + qcom,pin-num = <1>; + status = "disabled"; + }; + + mpp@a100 { + /* MPP2 - PA_THERM config */ + reg = <0xa100 0x100>; + qcom,pin-num = <2>; + qcom,mode = <4>; /* AIN input */ + qcom,invert = <1>; /* Enable MPP */ + qcom,ain-route = <1>; /* AMUX 6 */ + qcom,master-en = <1>; + qcom,src-sel = <0>; /* Function constant */ + }; + + mpp@a200 { + reg = <0xa200 0x100>; + qcom,pin-num = <3>; + status = "disabled"; + }; + + mpp@a300 { + /* MPP4 - CASE_THERM config */ + reg = <0xa300 0x100>; + qcom,pin-num = <4>; + qcom,mode = <4>; /* AIN input */ + qcom,invert = <1>; /* Enable MPP */ + qcom,ain-route = <3>; /* AMUX 8 */ + qcom,master-en = <1>; + qcom,src-sel = <0>; /* Function constant */ + }; + }; + + pm8950_gpios: gpios { + spmi-dev-container; + compatible = "qcom,qpnp-pin"; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + label = "pm8950-gpio"; + + gpio@c000 { + reg = <0xc000 0x100>; + qcom,pin-num = <1>; + status = "disabled"; + }; + + gpio@c100 { + reg = <0xc100 0x100>; + qcom,pin-num = <2>; + status = "disabled"; + }; + + gpio@c200 { + reg = <0xc200 0x100>; + qcom,pin-num = <3>; + status = "disabled"; + }; + + gpio@c300 { + reg = <0xc300 0x100>; + qcom,pin-num = <4>; + status = "disabled"; + }; + + gpio@c400 { + reg = <0xc400 0x100>; + qcom,pin-num = <5>; + status = "disabled"; + }; + + gpio@c500 { + reg = <0xc500 0x100>; + qcom,pin-num = <6>; + status = "disabled"; + }; + + gpio@c600 { + reg = <0xc600 0x100>; + qcom,pin-num = <7>; + status = "disabled"; + }; + + gpio@c700 { + reg = <0xc700 0x100>; + qcom,pin-num = <8>; + status = "disabled"; + }; + }; + + pm8950_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + qcom,pmic-revid = <&pm8950_revid>; + + chan@5 { + label = "vcoin"; + reg = <5>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@7 { + label = "vph_pwr"; + reg = <7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@8 { + label = "die_temp"; + reg = <8>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@c { + label = "ref_buf_625mv"; + reg = <0xc>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@11 { + label = "pa_therm1"; + reg = <0x11>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@32 { + label = "xo_therm"; + reg = <0x32>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@3c { + label = "xo_therm_buf"; + reg = <0x3c>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@13 { + label = "case_therm"; + reg = <0x13>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + }; + + pm8950_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0>, + <0x0 0x34 0x3>, + <0x0 0x34 0x4>; + interrupt-names = "eoc-int-en-set", + "high-thr-en-set", + "low-thr-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,adc_tm-vadc = <&pm8950_vadc>; + qcom,pmic-revid = <&pm8950_revid>; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,btm-channel-number = <0x48>; + qcom,thermal-node; + }; + + chan@7 { + label = "vph_pwr"; + reg = <0x7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,btm-channel-number = <0x68>; + }; + }; + + pm8950_rtc: qcom,pm8950_rtc { + spmi-dev-container; + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8950_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + + qcom,pm8950_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1>; + }; + }; + + qcom,leds@a300 { + compatible = "qcom,leds-qpnp"; + reg = <0xa300 0x100>; + label = "mpp"; + }; + }; + + pm8950_1: qcom,pm8950@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8950_pwm: pwm@bc00 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xbc00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1e594c64320c83c25daa35b1862be186bfeb376e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2015-2017, 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. + */ + +&rpm_bus { + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <4>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <7>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_s7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <9>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa16 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <16>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <5000>; + status = "disabled"; + + regulator-l16 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l16"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa17 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <17>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l17 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l17"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa19 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <19>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l19 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l19"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa22 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <22>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l22 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l22"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa23 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <23>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l23 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm8953_l23"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + /* Regulator to notify APC corner to RPM */ + rpm-regulator-clk0 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "clk0"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + status = "disabled"; + + regulator-clk0 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "rpm_apc"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8953.dtsi b/arch/arm64/boot/dts/qcom/pm8953.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d77de729a541a1092af4eb821911e0407eb163ca --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm8953.dtsi @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2015-2018, 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. + */ + +&spmi_bus { + + qcom,pm8953@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm8953_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,system-reset; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm8953_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pm8953_tz"; + qcom,channel-num = <8>; + qcom,threshold-set = <0>; + qcom,temp_alarm-vadc = <&pm8953_vadc>; + #thermal-sensor-cells = <0>; + }; + + pm8953_coincell: qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + }; + + pm8953_mpps: mpps { + compatible = "qcom,spmi-mpp"; + reg = <0xa000 0x400>; + + interrupts = <0x0 0xa0 0 IRQ_TYPE_NONE>, + <0x0 0xa1 0 IRQ_TYPE_NONE>, + <0x0 0xa2 0 IRQ_TYPE_NONE>, + <0x0 0xa3 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8953_mpp1", "pm8953_mpp2", + "pm8953_mpp3", "pm8953_mpp4"; + + gpio-controller; + #gpio-cells = <2>; + }; + + pm8953_gpios: gpios { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x800>; + + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8953_gpio1", "pm8953_gpio4", + "pm8953_gpio7", "pm8953_gpio8"; + + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <2 3 5 6>; + }; + + pm8953_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + + chan@5 { + label = "vcoin"; + reg = <5>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@7 { + label = "vph_pwr"; + reg = <7>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@8 { + label = "die_temp"; + reg = <8>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@c { + label = "ref_buf_625mv"; + reg = <0xc>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@36 { + label = "pa_therm0"; + reg = <0x36>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@11 { + label = "pa_therm1"; + reg = <0x11>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + + chan@32 { + label = "xo_therm"; + reg = <0x32>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@3c { + label = "xo_therm_buf"; + reg = <0x3c>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + chan@13 { + label = "case_therm"; + reg = <0x13>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + }; + + pm8953_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set", + "high-thr-en-set", + "low-thr-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,adc_tm-vadc = <&pm8953_vadc>; + }; + + pm8953_rtc: qcom,pm8953_rtc { + spmi-dev-container; + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8953_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + + qcom,pm8953_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + + pm8953_typec: qcom,pm8953_typec@bf00 { + compatible = "qcom,qpnp-typec"; + reg = <0xbf00 0x100>; + interrupts = <0x0 0xbf 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0xbf 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0xbf 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0xbf 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0xbf 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0xbf 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0xbf 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "vrd-change", + "ufp-detect", + "ufp-detach", + "dfp-detect", + "dfp-detach", + "vbus-err", + "vconn-oc"; + }; + }; + + pm8953_1: qcom,pm8953@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm8953_pwm: pwm@bc00 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xbc00 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + }; +}; + +&thermal_zones { + pm8953_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8953_tz>; + + trips { + pm8953_trip0: pm8953-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm8953_trip1: pm8953-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm8953_trip2: pm8953-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi index 15db8da3eaf2fb44d8f1106002b1ddcbd0a165fc..89499f864a55d4f80b7cccc9cca33cbe35342e2d 100644 --- a/arch/arm64/boot/dts/qcom/pm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi @@ -36,6 +36,7 @@ interrupt-names = "kpdpwr", "resin", "resin-bark", "kpdpwr-resin-bark"; qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; qcom,system-reset; qcom,store-hard-reset-reason; @@ -62,11 +63,14 @@ }; }; - qcom,temp-alarm@2400 { + pm8998_tz: qcom,temp-alarm@2400 { compatible = "qcom,qpnp-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; label = "pm8998_tz"; + qcom,channel-num = <6>; + qcom,temp_alarm-vadc = <&pm8998_vadc>; + #thermal-sensor-cells = <0>; }; pm8998_gpios: pinctrl@c000 { @@ -134,9 +138,7 @@ #size-cells = <0>; interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; interrupt-names = "eoc-int-en-set"; - qcom,adc-bit-resolution = <15>; qcom,adc-vdd-reference = <1875>; - #thermal-sensor-cells = <1>; chan@6 { label = "die_temp"; @@ -182,11 +184,38 @@ #size-cells = <0>; interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; interrupt-names = "eoc-int-en-set"; - qcom,adc-bit-resolution = <15>; qcom,adc-vdd-reference = <1875>; qcom,adc_tm-vadc = <&pm8998_vadc>; qcom,decimation = <0>; qcom,fast-avg-setup = <0>; + #thermal-sensor-cells = <1>; + }; + + pm8998_div_clk1: qcom,clkdiv@5b00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <1>; + qcom,clkdiv-init-freq = <19200000>; + }; + + pm8998_div_clk2: qcom,clkdiv@5c00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5c00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <2>; + qcom,clkdiv-init-freq = <19200000>; + }; + + pm8998_div_clk3: qcom,clkdiv@5d00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5d00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <3>; + qcom,clkdiv-init-freq = <19200000>; }; }; @@ -197,3 +226,30 @@ #size-cells = <0>; }; }; + +&thermal_zones { + pm8998_temp_alarm: pm8998_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8998_tz>; + + trips { + pm8998_trip0: pm8998-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm8998_trip1: pm8998-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm8998_trip2: pm8998-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..074b7da61cc34d51d762786b72bab438e1c3a3f1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -0,0 +1,308 @@ +/* Copyright (c) 2017-2018, 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 +#include +#include + +&spmi_bus { + qcom,pmi632@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmi632_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pmi632_pon: qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + }; + + pmi632_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc-hc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + qcom,adc-full-scale-code = <0x70e4>; + + chan@0 { + label = "ref_gnd"; + reg = <0>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@1 { + label = "ref_1250v"; + reg = <1>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@84 { + label = "vbat_sns"; + reg = <0x84>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@6 { + label = "die_temp"; + reg = <6>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <19>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@7 { + label = "usb_in_i"; + reg = <7>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <21>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@8 { + label = "usb_in_v"; + reg = <8>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <8>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@9 { + label = "chg_temp"; + reg = <9>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <18>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@4a { + label = "bat_therm"; + reg = <0x4a>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <17>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@4b { + label = "bat_id"; + reg = <0x4b>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <8>; + qcom,fast-avg-setup = <0>; + }; + + + chan@1e { + label = "mid_chg"; + reg = <0x1e>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <3>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + }; + + pmi632_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pmi632_tz"; + #thermal-sensor-cells = <0>; + }; + + pmi632_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x800>; + interrupts = <0x2 0xc1 0 IRQ_TYPE_NONE>, + <0x2 0xc2 0 IRQ_TYPE_NONE>, + <0x2 0xc3 0 IRQ_TYPE_NONE>, + <0x2 0xc4 0 IRQ_TYPE_NONE>, + <0x2 0xc5 0 IRQ_TYPE_NONE>, + <0x2 0xc6 0 IRQ_TYPE_NONE>, + <0x2 0xc7 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi632_gpio2", "pmi632_gpio3", + "pmi632_gpio4", "pmi632_gpio5", + "pmi632_gpio6", "pmi632_gpio7", + "pmi632_gpio8"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <1>; + }; + }; + + pmi632_3: qcom,pmi632@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmi632_vib: qcom,vibrator@5700 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5700 0x100>; + qcom,vib-ldo-volt-uv = <1504000>; + qcom,vib-overdrive-volt-uv = <3544000>; + status = "disabled"; + }; + + pmi632_pwm_1: pwm@b300 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb300 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <1>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi632_pwm_2: pwm@b400 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb400 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <2>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi632_pwm_3: pwm@b500 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb500 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <3>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi632_pwm_4: pwm@b600 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb600 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <4>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi632_pwm_5: pwm@b700 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb700 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <5>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi632_lcdb: qpnp-lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + + qcom,pmic-revid = <&pmi632_revid>; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a7aa08ac4cf4247c98510dfc0a9e2d5a86f67805 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2015-2018, 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 + +&spmi_bus { + + qcom,pmi8937@2 { + compatible ="qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmi8937_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = + ; + + pon_perph_reg: qcom,pon_perph_reg { + regulator-name = "pon_spare_reg"; + qcom,pon-spare-reg-addr = <0x8c>; + qcom,pon-spare-reg-bit = <1>; + }; + }; + + pmi8937_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + + chan@0 { + label = "usbin"; + reg = <0>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@1 { + label = "dcin"; + reg = <1>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@3 { + label = "vchg_sns"; + reg = <3>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@d { + label = "chg_temp"; + reg = <0xd>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <16>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@43 { + label = "usb_dp"; + reg = <0x43>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@44 { + label = "usb_dm"; + reg = <0x44>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + }; + + pmi8937_mpps: mpps { + compatible = "qcom,spmi-mpp"; + reg = <0xa000 0x400>; + interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>, + <0x2 0xa1 0 IRQ_TYPE_NONE>, + <0x2 0xa2 0 IRQ_TYPE_NONE>, + <0x2 0xa3 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi8937_mpp1", "pmi8937_mpp2", + "pmi8937_mpp3", "pmi8937_mpp4"; + gpio-controller; + #gpio-cells = <2>; + }; + + pmi8937_charger: qcom,qpnp-smbcharger { + compatible = "qcom,qpnp-smbcharger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,iterm-ma = <100>; + qcom,float-voltage-mv = <4200>; + qcom,resume-delta-mv = <200>; + qcom,chg-inhibit-fg; + qcom,rparasitic-uohm = <100000>; + qcom,bms-psy-name = "bms"; + qcom,thermal-mitigation = <1500 700 600 0>; + qcom,parallel-usb-min-current-ma = <1400>; + qcom,parallel-usb-9v-min-current-ma = <900>; + qcom,parallel-allowed-lowering-ma = <500>; + qcom,pmic-revid = <&pmi8937_revid>; + qcom,force-aicl-rerun; + qcom,aicl-rerun-period-s = <180>; + qcom,autoadjust-vfloat; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, + <0x2 0x10 0x1 IRQ_TYPE_NONE>, + <0x2 0x10 0x2 IRQ_TYPE_NONE>, + <0x2 0x10 0x3 IRQ_TYPE_NONE>, + <0x2 0x10 0x4 IRQ_TYPE_NONE>, + <0x2 0x10 0x5 IRQ_TYPE_NONE>, + <0x2 0x10 0x6 IRQ_TYPE_NONE>, + <0x2 0x10 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "chg-error", + "chg-inhibit", + "chg-prechg-sft", + "chg-complete-chg-sft", + "chg-p2f-thr", + "chg-rechg-thr", + "chg-taper-thr", + "chg-tcc-thr"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>, + <0x2 0x11 0x1 IRQ_TYPE_NONE>, + <0x2 0x11 0x3 IRQ_TYPE_NONE>; + interrupt-names = "otg-fail", + "otg-oc", + "usbid-change"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>, + <0x2 0x12 0x1 IRQ_TYPE_NONE>, + <0x2 0x12 0x2 IRQ_TYPE_NONE>, + <0x2 0x12 0x3 IRQ_TYPE_NONE>, + <0x2 0x12 0x4 IRQ_TYPE_NONE>, + <0x2 0x12 0x5 IRQ_TYPE_NONE>, + <0x2 0x12 0x6 IRQ_TYPE_NONE>, + <0x2 0x12 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "batt-hot", + "batt-warm", + "batt-cold", + "batt-cool", + "batt-ov", + "batt-low", + "batt-missing", + "batt-term-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>, + <0x2 0x13 0x1 IRQ_TYPE_NONE>, + <0x2 0x13 0x2 IRQ_TYPE_NONE>, + <0x2 0x13 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "usbin-uv", + "usbin-ov", + "usbin-src-det", + "aicl-done"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>, + <0x2 0x14 0x1 IRQ_TYPE_NONE>; + interrupt-names = "dcin-uv", + "dcin-ov"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>, + <0x2 0x16 0x1 IRQ_TYPE_NONE>, + <0x2 0x16 0x2 IRQ_TYPE_NONE>, + <0x2 0x16 0x3 IRQ_TYPE_NONE>, + <0x2 0x16 0x4 IRQ_TYPE_NONE>, + <0x2 0x16 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "power-ok", + "temp-shutdown", + "wdog-timeout", + "flash-fail", + "otst2", + "otst3"; + }; + + smbcharger_charger_otg: qcom,smbcharger-boost-otg { + regulator-name = "smbcharger_charger_otg"; + }; + }; + + pmi8937_fg: qcom,fg { + compatible = "qcom,qpnp-fg"; + #address-cells = <1>; + #size-cells = <1>; + qcom,resume-soc = <95>; + status = "okay"; + qcom,bcl-lm-threshold-ma = <127>; + qcom,bcl-mh-threshold-ma = <405>; + qcom,fg-iterm-ma = <150>; + qcom,fg-chg-iterm-ma = <100>; + qcom,pmic-revid = <&pmi8937_revid>; + qcom,fg-cutoff-voltage-mv = <3500>; + qcom,cycle-counter-en; + qcom,capacity-learning-on; + + qcom,fg-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_NONE>, + <0x2 0x40 0x1 IRQ_TYPE_NONE>, + <0x2 0x40 0x2 IRQ_TYPE_NONE>, + <0x2 0x40 0x3 IRQ_TYPE_NONE>, + <0x2 0x40 0x4 IRQ_TYPE_NONE>, + <0x2 0x40 0x5 IRQ_TYPE_NONE>, + <0x2 0x40 0x6 IRQ_TYPE_NONE>; + + interrupt-names = "high-soc", + "low-soc", + "full-soc", + "empty-soc", + "delta-soc", + "first-est-done", + "update-soc"; + }; + + qcom,fg-batt@4100 { + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_NONE>, + <0x2 0x41 0x1 IRQ_TYPE_NONE>, + <0x2 0x41 0x2 IRQ_TYPE_NONE>, + <0x2 0x41 0x3 IRQ_TYPE_NONE>, + <0x2 0x41 0x4 IRQ_TYPE_NONE>, + <0x2 0x41 0x5 IRQ_TYPE_NONE>, + <0x2 0x41 0x6 IRQ_TYPE_NONE>, + <0x2 0x41 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "soft-cold", + "soft-hot", + "vbatt-low", + "batt-ided", + "batt-id-req", + "batt-unknown", + "batt-missing", + "batt-match"; + }; + + qcom,revid-tp-rev@1f1 { + reg = <0x1f1 0x1>; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0 IRQ_TYPE_NONE>, + <0x2 0x44 0x2 IRQ_TYPE_NONE>; + + interrupt-names = "mem-avail", + "data-rcvry-sug"; + }; + }; + + bcl@4200 { + compatible = "qcom,msm-bcl"; + reg = <0x4200 0xff>; + reg-names = "fg_user_adc"; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>, + <0x2 0x42 0x1 IRQ_TYPE_NONE>; + interrupt-names = "bcl-high-ibat-int", + "bcl-low-vbat-int"; + qcom,vbat-scaling-factor = <39000>; + qcom,vbat-gain-numerator = <1>; + qcom,vbat-gain-denominator = <128>; + qcom,vbat-polling-delay-ms = <100>; + qcom,ibat-scaling-factor = <39000>; + qcom,ibat-gain-numerator = <1>; + qcom,ibat-gain-denominator = <128>; + qcom,ibat-offset-numerator = <1200>; + qcom,ibat-offset-denominator = <1>; + qcom,ibat-polling-delay-ms = <100>; + }; + + qcom,leds@a100 { + compatible = "qcom,leds-qpnp"; + reg = <0xa100 0x100>; + label = "mpp"; + }; + }; + + qcom,pmi8937@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmi8937_pwm: pwm@b000 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xb000 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + + wled: qcom,leds@d800 { + compatible = "qcom,qpnp-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base"; + interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + status = "okay"; + linux,name = "wled"; + linux,default-trigger = "bkl-trigger"; + qcom,fdbk-output = "auto"; + qcom,vref-mv = <350>; + qcom,switch-freq-khz = <800>; + qcom,ovp-mv = <29500>; + qcom,ilim-ma = <980>; + qcom,boost-duty-ns = <26>; + qcom,mod-freq-khz = <9600>; + qcom,dim-mode = "hybrid"; + qcom,dim-method = "linear"; + qcom,hyb-thres = <625>; + qcom,sync-dly-us = <800>; + qcom,fs-curr-ua = <20000>; + qcom,led-strings-list = [00 01]; + qcom,en-ext-pfet-sc-pro; + qcom,pmic-revid = <&pmi8937_revid>; + qcom,cons-sync-write-delay-us = <1000>; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + qcom,headroom = <500>; + qcom,startup-dly = <128>; + qcom,clamp-curr = <200>; + qcom,pmic-charger-support; + qcom,self-check-enabled; + qcom,thermal-derate-enabled; + qcom,thermal-derate-threshold = <100>; + qcom,thermal-derate-rate = "5_PERCENT"; + qcom,current-ramp-enabled; + qcom,ramp_up_step = "6P7_US"; + qcom,ramp_dn_step = "6P7_US"; + qcom,vph-pwr-droop-enabled; + qcom,vph-pwr-droop-threshold = <3000>; + qcom,vph-pwr-droop-debounce-time = <10>; + qcom,headroom-sense-ch0-enabled; + qcom,headroom-sense-ch1-enabled; + qcom,pmic-revid = <&pmi8937_revid>; + + pmi8937_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,default-led-trigger = + "flash0_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <0>; + qcom,current = <625>; + }; + + pmi8937_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,default-led-trigger = + "flash1_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <1>; + qcom,current = <625>; + }; + + pmi8937_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,default-led-trigger = + "torch0_trigger"; + qcom,max-current = <200>; + qcom,id = <0>; + qcom,current = <120>; + }; + + pmi8937_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,default-led-trigger = + "torch1_trigger"; + qcom,max-current = <200>; + qcom,id = <1>; + qcom,current = <120>; + }; + + pmi8937_switch: qcom,switch { + label = "switch"; + qcom,led-name = "led:switch"; + qcom,default-led-trigger = + "switch_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <2>; + qcom,current = <625>; + reg0 { + regulator-name = "pon_spare_reg"; + }; + }; + }; + + pmi_haptic: qcom,haptic@c000 { + compatible = "qcom,qpnp-haptic"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pmi8937_revid>; + vcc_pon-supply = <&pon_perph_reg>; + qcom,play-mode = "direct"; + qcom,wave-play-rate-us = <5263>; + qcom,actuator-type = "lra"; + qcom,wave-shape = "square"; + qcom,vmax-mv = <2000>; + qcom,ilim-ma = <800>; + qcom,sc-deb-cycles = <8>; + qcom,int-pwm-freq-khz = <505>; + qcom,en-brake; + qcom,brake-pattern = [03 03 00 00]; + qcom,use-play-irq; + qcom,use-sc-irq; + qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wave-rep-cnt = <1>; + qcom,wave-samp-rep-cnt = <1>; + qcom,lra-auto-res-mode="qwd"; + qcom,lra-high-z="opt1"; + qcom,lra-res-cal-period = <4>; + qcom,correct-lra-drive-freq; + qcom,misc-trim-error-rc19p2-clk-reg-present; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c6d5c8775b3b3890b8c4af50b5635ff6da8bec76 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2016-2018, 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 + +&spmi_bus { + qcom,pmi8940@2 { + compatible ="qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmi8940_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = + ; + + pon_perph_reg: qcom,pon_perph_reg { + regulator-name = "pon_spare_reg"; + qcom,pon-spare-reg-addr = <0x8c>; + qcom,pon-spare-reg-bit = <1>; + }; + }; + + pmi8940_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + + chan@0 { + label = "usbin"; + reg = <0>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@1 { + label = "dcin"; + reg = <1>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@3 { + label = "vchg_sns"; + reg = <3>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@d { + label = "chg_temp"; + reg = <0xd>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <16>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@43 { + label = "usb_dp"; + reg = <0x43>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@44 { + label = "usb_dm"; + reg = <0x44>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + }; + + pmi8940_mpps: mpps { + compatible = "qcom,spmi-mpp"; + reg = <0xa000 0x400>; + interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>, + <0x2 0xa1 0 IRQ_TYPE_NONE>, + <0x2 0xa2 0 IRQ_TYPE_NONE>, + <0x2 0xa3 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi8940_mpp1", "pmi8940_mpp2", + "pmi8940_mpp3", "pmi8940_mpp4"; + gpio-controller; + #gpio-cells = <2>; + }; + + pmi8940_charger: qcom,qpnp-smbcharger { + compatible = "qcom,qpnp-smbcharger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,iterm-ma = <100>; + qcom,float-voltage-mv = <4200>; + qcom,resume-delta-mv = <200>; + qcom,chg-inhibit-fg; + qcom,rparasitic-uohm = <100000>; + qcom,bms-psy-name = "bms"; + qcom,thermal-mitigation = <1500 700 600 0>; + qcom,pmic-revid = <&pmi8940_revid>; + qcom,force-aicl-rerun; + qcom,aicl-rerun-period-s = <180>; + qcom,autoadjust-vfloat; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, + <0x2 0x10 0x1 IRQ_TYPE_NONE>, + <0x2 0x10 0x2 IRQ_TYPE_NONE>, + <0x2 0x10 0x3 IRQ_TYPE_NONE>, + <0x2 0x10 0x4 IRQ_TYPE_NONE>, + <0x2 0x10 0x5 IRQ_TYPE_NONE>, + <0x2 0x10 0x6 IRQ_TYPE_NONE>, + <0x2 0x10 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "chg-error", + "chg-inhibit", + "chg-prechg-sft", + "chg-complete-chg-sft", + "chg-p2f-thr", + "chg-rechg-thr", + "chg-taper-thr", + "chg-tcc-thr"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>, + <0x2 0x11 0x1 IRQ_TYPE_NONE>, + <0x2 0x11 0x3 IRQ_TYPE_NONE>; + interrupt-names = "otg-fail", + "otg-oc", + "usbid-change"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>, + <0x2 0x12 0x1 IRQ_TYPE_NONE>, + <0x2 0x12 0x2 IRQ_TYPE_NONE>, + <0x2 0x12 0x3 IRQ_TYPE_NONE>, + <0x2 0x12 0x4 IRQ_TYPE_NONE>, + <0x2 0x12 0x5 IRQ_TYPE_NONE>, + <0x2 0x12 0x6 IRQ_TYPE_NONE>, + <0x2 0x12 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "batt-hot", + "batt-warm", + "batt-cold", + "batt-cool", + "batt-ov", + "batt-low", + "batt-missing", + "batt-term-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>, + <0x2 0x13 0x1 IRQ_TYPE_NONE>, + <0x2 0x13 0x2 IRQ_TYPE_NONE>, + <0x2 0x13 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "usbin-uv", + "usbin-ov", + "usbin-src-det", + "aicl-done"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>, + <0x2 0x14 0x1 IRQ_TYPE_NONE>; + interrupt-names = "dcin-uv", + "dcin-ov"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>, + <0x2 0x16 0x1 IRQ_TYPE_NONE>, + <0x2 0x16 0x2 IRQ_TYPE_NONE>, + <0x2 0x16 0x3 IRQ_TYPE_NONE>, + <0x2 0x16 0x4 IRQ_TYPE_NONE>, + <0x2 0x16 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "power-ok", + "temp-shutdown", + "wdog-timeout", + "flash-fail", + "otst2", + "otst3"; + }; + + smbcharger_charger_otg: qcom,smbcharger-boost-otg { + regulator-name = "smbcharger_charger_otg"; + }; + }; + + pmi8940_fg: qcom,fg { + compatible = "qcom,qpnp-fg"; + #address-cells = <1>; + #size-cells = <1>; + qcom,resume-soc = <95>; + status = "okay"; + qcom,bcl-lm-threshold-ma = <127>; + qcom,bcl-mh-threshold-ma = <405>; + qcom,fg-iterm-ma = <150>; + qcom,fg-chg-iterm-ma = <100>; + qcom,pmic-revid = <&pmi8940_revid>; + qcom,fg-cutoff-voltage-mv = <3500>; + qcom,cycle-counter-en; + qcom,capacity-learning-on; + + qcom,fg-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_NONE>, + <0x2 0x40 0x1 IRQ_TYPE_NONE>, + <0x2 0x40 0x2 IRQ_TYPE_NONE>, + <0x2 0x40 0x3 IRQ_TYPE_NONE>, + <0x2 0x40 0x4 IRQ_TYPE_NONE>, + <0x2 0x40 0x5 IRQ_TYPE_NONE>, + <0x2 0x40 0x6 IRQ_TYPE_NONE>; + + interrupt-names = "high-soc", + "low-soc", + "full-soc", + "empty-soc", + "delta-soc", + "first-est-done", + "update-soc"; + }; + + qcom,fg-batt@4100 { + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_NONE>, + <0x2 0x41 0x1 IRQ_TYPE_NONE>, + <0x2 0x41 0x2 IRQ_TYPE_NONE>, + <0x2 0x41 0x3 IRQ_TYPE_NONE>, + <0x2 0x41 0x4 IRQ_TYPE_NONE>, + <0x2 0x41 0x5 IRQ_TYPE_NONE>, + <0x2 0x41 0x6 IRQ_TYPE_NONE>, + <0x2 0x41 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "soft-cold", + "soft-hot", + "vbatt-low", + "batt-ided", + "batt-id-req", + "batt-unknown", + "batt-missing", + "batt-match"; + }; + + qcom,revid-tp-rev@1f1 { + reg = <0x1f1 0x1>; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0 IRQ_TYPE_NONE>, + <0x2 0x44 0x2 IRQ_TYPE_NONE>; + + interrupt-names = "mem-avail", + "data-rcvry-sug"; + }; + }; + + bcl@4200 { + compatible = "qcom,msm-bcl"; + reg = <0x4200 0xff>; + reg-names = "fg_user_adc"; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>, + <0x2 0x42 0x1 IRQ_TYPE_NONE>; + interrupt-names = "bcl-high-ibat-int", + "bcl-low-vbat-int"; + qcom,vbat-scaling-factor = <39000>; + qcom,vbat-gain-numerator = <1>; + qcom,vbat-gain-denominator = <128>; + qcom,vbat-polling-delay-ms = <100>; + qcom,ibat-scaling-factor = <39000>; + qcom,ibat-gain-numerator = <1>; + qcom,ibat-gain-denominator = <128>; + qcom,ibat-offset-numerator = <1200>; + qcom,ibat-offset-denominator = <1>; + qcom,ibat-polling-delay-ms = <100>; + }; + + qcom,leds@a100 { + compatible = "qcom,leds-qpnp"; + reg = <0xa100 0x100>; + label = "mpp"; + }; + }; + + qcom,pmi8940@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmi8940_pwm: pwm@b000 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xb000 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + + labibb: qpnp-labibb-regulator { + status = "disabled"; + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-labibb-mode = "lcd"; + qcom,pmic-revid = <&pmi8940_revid>; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-use-default-voltage; + qcom,qpnp-ibb-init-voltage = <5500000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + qcom,qpnp-ibb-init-lcd-voltage = <5500000>; + + qcom,qpnp-ibb-soft-start = <1000>; + + qcom,qpnp-ibb-discharge-resistor = <32>; + qcom,qpnp-ibb-lab-pwrup-delay = <8000>; + qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; + qcom,qpnp-ibb-en-discharge; + + qcom,qpnp-ibb-full-pull-down; + qcom,qpnp-ibb-pull-down-enable; + qcom,qpnp-ibb-switching-clock-frequency = + <1480>; + qcom,qpnp-ibb-limit-maximum-current = <1550>; + qcom,qpnp-ibb-debounce-cycle = <16>; + qcom,qpnp-ibb-limit-max-current-enable; + qcom,qpnp-ibb-ps-enable; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-use-default-voltage; + qcom,qpnp-lab-init-voltage = <5500000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + qcom,qpnp-lab-init-lcd-voltage = <5500000>; + + qcom,qpnp-lab-soft-start = <800>; + + qcom,qpnp-lab-full-pull-down; + qcom,qpnp-lab-pull-down-enable; + qcom,qpnp-lab-switching-clock-frequency = + <1600>; + qcom,qpnp-lab-limit-maximum-current = <800>; + qcom,qpnp-lab-limit-max-current-enable; + qcom,qpnp-lab-ps-threshold = <40>; + qcom,qpnp-lab-ps-enable; + qcom,qpnp-lab-nfet-size = <100>; + qcom,qpnp-lab-pfet-size = <100>; + qcom,qpnp-lab-max-precharge-time = <500>; + }; + }; + + wled: qcom,leds@d800 { + compatible = "qcom,qpnp-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base"; + interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + status = "okay"; + linux,name = "wled"; + linux,default-trigger = "bkl-trigger"; + qcom,fdbk-output = "auto"; + qcom,vref-mv = <350>; + qcom,switch-freq-khz = <800>; + qcom,ovp-mv = <29500>; + qcom,ilim-ma = <980>; + qcom,boost-duty-ns = <26>; + qcom,mod-freq-khz = <9600>; + qcom,dim-mode = "hybrid"; + qcom,dim-method = "linear"; + qcom,hyb-thres = <625>; + qcom,sync-dly-us = <800>; + qcom,fs-curr-ua = <20000>; + qcom,en-phase-stag; + qcom,led-strings-list = [00 01]; + qcom,en-ext-pfet-sc-pro; + qcom,pmic-revid = <&pmi8940_revid>; + qcom,cons-sync-write-delay-us = <1000>; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + qcom,headroom = <500>; + qcom,startup-dly = <128>; + qcom,clamp-curr = <200>; + qcom,pmic-charger-support; + qcom,self-check-enabled; + qcom,thermal-derate-enabled; + qcom,thermal-derate-threshold = <100>; + qcom,thermal-derate-rate = "5_PERCENT"; + qcom,current-ramp-enabled; + qcom,ramp_up_step = "6P7_US"; + qcom,ramp_dn_step = "6P7_US"; + qcom,vph-pwr-droop-enabled; + qcom,vph-pwr-droop-threshold = <3000>; + qcom,vph-pwr-droop-debounce-time = <10>; + qcom,headroom-sense-ch0-enabled; + qcom,headroom-sense-ch1-enabled; + qcom,pmic-revid = <&pmi8940_revid>; + + pmi8940_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,default-led-trigger = + "flash0_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <0>; + qcom,current = <625>; + }; + + pmi8940_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,default-led-trigger = + "flash1_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <1>; + qcom,current = <625>; + }; + + pmi8940_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,default-led-trigger = + "torch0_trigger"; + qcom,max-current = <200>; + qcom,id = <0>; + qcom,current = <120>; + }; + + pmi8940_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,default-led-trigger = + "torch1_trigger"; + qcom,max-current = <200>; + qcom,id = <1>; + qcom,current = <120>; + }; + + pmi8940_switch: qcom,switch { + label = "switch"; + qcom,led-name = "led:switch"; + qcom,default-led-trigger = + "switch_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <2>; + qcom,current = <625>; + reg0 { + regulator-name = "pon_spare_reg"; + }; + }; + }; + + pmi_haptic: qcom,haptic@c000 { + compatible = "qcom,qpnp-haptic"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pmi8940_revid>; + vcc_pon-supply = <&pon_perph_reg>; + qcom,play-mode = "direct"; + qcom,wave-play-rate-us = <5263>; + qcom,actuator-type = "lra"; + qcom,wave-shape = "square"; + qcom,vmax-mv = <2000>; + qcom,ilim-ma = <800>; + qcom,sc-deb-cycles = <8>; + qcom,int-pwm-freq-khz = <505>; + qcom,en-brake; + qcom,brake-pattern = [03 03 00 00]; + qcom,use-play-irq; + qcom,use-sc-irq; + qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wave-rep-cnt = <1>; + qcom,wave-samp-rep-cnt = <1>; + qcom,lra-auto-res-mode="qwd"; + qcom,lra-high-z="opt1"; + qcom,lra-res-cal-period = <4>; + qcom,correct-lra-drive-freq; + qcom,misc-trim-error-rc19p2-clk-reg-present; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..97be32de84730d44337f421d2bd7ccdabf68ef8b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi @@ -0,0 +1,612 @@ +/* Copyright (c) 2015-2018, 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 + +&spmi_bus { + qcom,pmi8950@2 { + compatible ="qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmi8950_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = + ; + + pon_perph_reg: qcom,pon_perph_reg { + regulator-name = "pon_spare_reg"; + qcom,pon-spare-reg-addr = <0x8c>; + qcom,pon-spare-reg-bit = <1>; + }; + }; + + pmi8950_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-bit-resolution = <15>; + qcom,adc-vdd-reference = <1800>; + qcom,vadc-poll-eoc; + + chan@0 { + label = "usbin"; + reg = <0>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@1 { + label = "dcin"; + reg = <1>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <4>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@3 { + label = "vchg_sns"; + reg = <3>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@9 { + label = "ref_625mv"; + reg = <9>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@a { + label = "ref_1250v"; + reg = <0xa>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@d { + label = "chg_temp"; + reg = <0xd>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <16>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,vadc-thermal-node; + }; + + chan@43 { + label = "usb_dp"; + reg = <0x43>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@44 { + label = "usb_dm"; + reg = <0x44>; + qcom,decimation = <0>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + }; + + pmi8950_gpios: gpios { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x200>; + + interrupts = <0x2 0xc0 0 IRQ_TYPE_NONE>, + <0x2 0xc1 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi8950_gpio1", "pmi8950_gpio2"; + + gpio-controller; + #gpio-cells = <2>; + }; + + pmi8950_mpps: mpps { + compatible = "qcom,spmi-mpp"; + reg = <0xa000 0x400>; + + interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>, + <0x2 0xa1 0 IRQ_TYPE_NONE>, + <0x2 0xa2 0 IRQ_TYPE_NONE>, + <0x2 0xa3 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi8950_mpp1", "pmi8950_mpp2", + "pmi8950_mpp3", "pmi8950_mpp4"; + + gpio-controller; + #gpio-cells = <2>; + }; + + pmi8950_charger: qcom,qpnp-smbcharger { + compatible = "qcom,qpnp-smbcharger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,iterm-ma = <100>; + qcom,float-voltage-mv = <4200>; + qcom,resume-delta-mv = <200>; + qcom,chg-inhibit-fg; + qcom,rparasitic-uohm = <100000>; + qcom,bms-psy-name = "bms"; + qcom,thermal-mitigation = <1500 700 600 0>; + qcom,parallel-usb-min-current-ma = <1400>; + qcom,parallel-usb-9v-min-current-ma = <900>; + qcom,parallel-allowed-lowering-ma = <500>; + qcom,pmic-revid = <&pmi8950_revid>; + qcom,force-aicl-rerun; + qcom,aicl-rerun-period-s = <180>; + qcom,autoadjust-vfloat; + dpdm-supply = <&qusb_phy>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, + <0x2 0x10 0x1 IRQ_TYPE_NONE>, + <0x2 0x10 0x2 IRQ_TYPE_NONE>, + <0x2 0x10 0x3 IRQ_TYPE_NONE>, + <0x2 0x10 0x4 IRQ_TYPE_NONE>, + <0x2 0x10 0x5 IRQ_TYPE_NONE>, + <0x2 0x10 0x6 IRQ_TYPE_NONE>, + <0x2 0x10 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "chg-error", + "chg-inhibit", + "chg-prechg-sft", + "chg-complete-chg-sft", + "chg-p2f-thr", + "chg-rechg-thr", + "chg-taper-thr", + "chg-tcc-thr"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>, + <0x2 0x11 0x1 IRQ_TYPE_NONE>, + <0x2 0x11 0x3 IRQ_TYPE_NONE>; + interrupt-names = "otg-fail", + "otg-oc", + "usbid-change"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>, + <0x2 0x12 0x1 IRQ_TYPE_NONE>, + <0x2 0x12 0x2 IRQ_TYPE_NONE>, + <0x2 0x12 0x3 IRQ_TYPE_NONE>, + <0x2 0x12 0x4 IRQ_TYPE_NONE>, + <0x2 0x12 0x5 IRQ_TYPE_NONE>, + <0x2 0x12 0x6 IRQ_TYPE_NONE>, + <0x2 0x12 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "batt-hot", + "batt-warm", + "batt-cold", + "batt-cool", + "batt-ov", + "batt-low", + "batt-missing", + "batt-term-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>, + <0x2 0x13 0x1 IRQ_TYPE_NONE>, + <0x2 0x13 0x2 IRQ_TYPE_NONE>, + <0x2 0x13 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "usbin-uv", + "usbin-ov", + "usbin-src-det", + "aicl-done"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>, + <0x2 0x14 0x1 IRQ_TYPE_NONE>; + interrupt-names = "dcin-uv", + "dcin-ov"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>, + <0x2 0x16 0x1 IRQ_TYPE_NONE>, + <0x2 0x16 0x2 IRQ_TYPE_NONE>, + <0x2 0x16 0x3 IRQ_TYPE_NONE>, + <0x2 0x16 0x4 IRQ_TYPE_NONE>, + <0x2 0x16 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "power-ok", + "temp-shutdown", + "wdog-timeout", + "flash-fail", + "otst2", + "otst3"; + }; + + smbcharger_charger_otg: qcom,smbcharger-boost-otg { + regulator-name = "smbcharger_charger_otg"; + }; + }; + + pmi8950_fg: qcom,fg { + compatible = "qcom,qpnp-fg"; + #address-cells = <1>; + #size-cells = <1>; + qcom,resume-soc = <95>; + status = "okay"; + qcom,bcl-lm-threshold-ma = <127>; + qcom,bcl-mh-threshold-ma = <405>; + qcom,fg-iterm-ma = <150>; + qcom,fg-chg-iterm-ma = <100>; + qcom,pmic-revid = <&pmi8950_revid>; + qcom,fg-cutoff-voltage-mv = <3500>; + qcom,cycle-counter-en; + qcom,capacity-learning-on; + + qcom,fg-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_NONE>, + <0x2 0x40 0x1 IRQ_TYPE_NONE>, + <0x2 0x40 0x2 IRQ_TYPE_NONE>, + <0x2 0x40 0x3 IRQ_TYPE_NONE>, + <0x2 0x40 0x4 IRQ_TYPE_NONE>, + <0x2 0x40 0x5 IRQ_TYPE_NONE>, + <0x2 0x40 0x6 IRQ_TYPE_NONE>; + + interrupt-names = "high-soc", + "low-soc", + "full-soc", + "empty-soc", + "delta-soc", + "first-est-done", + "update-soc"; + }; + + qcom,fg-batt@4100 { + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_NONE>, + <0x2 0x41 0x1 IRQ_TYPE_NONE>, + <0x2 0x41 0x2 IRQ_TYPE_NONE>, + <0x2 0x41 0x3 IRQ_TYPE_NONE>, + <0x2 0x41 0x4 IRQ_TYPE_NONE>, + <0x2 0x41 0x5 IRQ_TYPE_NONE>, + <0x2 0x41 0x6 IRQ_TYPE_NONE>, + <0x2 0x41 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "soft-cold", + "soft-hot", + "vbatt-low", + "batt-ided", + "batt-id-req", + "batt-unknown", + "batt-missing", + "batt-match"; + }; + + qcom,revid-tp-rev@1f1 { + reg = <0x1f1 0x1>; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0 IRQ_TYPE_NONE>, + <0x2 0x44 0x2 IRQ_TYPE_NONE>; + + interrupt-names = "mem-avail", + "data-rcvry-sug"; + }; + }; + + bcl@4200 { + compatible = "qcom,msm-bcl"; + reg = <0x4200 0xFF 0x88E 0x2>; + reg-names = "fg_user_adc", "pon_spare"; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>, + <0x2 0x42 0x1 IRQ_TYPE_NONE>; + interrupt-names = "bcl-high-ibat-int", + "bcl-low-vbat-int"; + qcom,vbat-scaling-factor = <39000>; + qcom,vbat-gain-numerator = <1>; + qcom,vbat-gain-denominator = <128>; + qcom,vbat-polling-delay-ms = <100>; + qcom,ibat-scaling-factor = <39000>; + qcom,ibat-gain-numerator = <1>; + qcom,ibat-gain-denominator = <128>; + qcom,ibat-offset-numerator = <1200>; + qcom,ibat-offset-denominator = <1>; + qcom,ibat-polling-delay-ms = <100>; + qcom,inhibit-derating-ua = <550000>; + }; + + qcom,leds@a100 { + compatible = "qcom,leds-qpnp"; + reg = <0xa100 0x100>; + label = "mpp"; + }; + }; + + qcom,pmi8950@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmi8950_pwm: pwm@b000 { + status = "disabled"; + compatible = "qcom,qpnp-pwm"; + reg = <0xb000 0x100>; + reg-names = "qpnp-lpg-channel-base"; + qcom,channel-id = <0>; + qcom,supported-sizes = <6>, <9>; + #pwm-cells = <2>; + }; + + labibb: qpnp-labibb-regulator { + status = "disabled"; + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pmi8950_revid>; + qcom,qpnp-labibb-mode = "lcd"; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-use-default-voltage; + qcom,qpnp-ibb-init-voltage = <5500000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + qcom,qpnp-ibb-init-lcd-voltage = <5500000>; + + qcom,qpnp-ibb-soft-start = <1000>; + + qcom,qpnp-ibb-discharge-resistor = <32>; + qcom,qpnp-ibb-lab-pwrup-delay = <8000>; + qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; + qcom,qpnp-ibb-en-discharge; + + qcom,qpnp-ibb-full-pull-down; + qcom,qpnp-ibb-pull-down-enable; + qcom,qpnp-ibb-switching-clock-frequency = + <1480>; + qcom,qpnp-ibb-limit-maximum-current = <1550>; + qcom,qpnp-ibb-debounce-cycle = <16>; + qcom,qpnp-ibb-limit-max-current-enable; + qcom,qpnp-ibb-ps-enable; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-use-default-voltage; + qcom,qpnp-lab-init-voltage = <5500000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + qcom,qpnp-lab-init-lcd-voltage = <5500000>; + + qcom,qpnp-lab-soft-start = <800>; + + qcom,qpnp-lab-full-pull-down; + qcom,qpnp-lab-pull-down-enable; + qcom,qpnp-lab-switching-clock-frequency = + <1600>; + qcom,qpnp-lab-limit-maximum-current = <800>; + qcom,qpnp-lab-limit-max-current-enable; + qcom,qpnp-lab-ps-threshold = <40>; + qcom,qpnp-lab-ps-enable; + qcom,qpnp-lab-nfet-size = <100>; + qcom,qpnp-lab-pfet-size = <100>; + qcom,qpnp-lab-max-precharge-time = <500>; + }; + + }; + + wled: qcom,leds@d800 { + compatible = "qcom,qpnp-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>, + <0xdc00 0x100>, + <0xde00 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base", + "qpnp-wled-ibb-base", + "qpnp-wled-lab-base"; + interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + status = "okay"; + linux,name = "wled"; + linux,default-trigger = "bkl-trigger"; + qcom,fdbk-output = "auto"; + qcom,vref-mv = <350>; + qcom,switch-freq-khz = <800>; + qcom,ovp-mv = <29500>; + qcom,ilim-ma = <980>; + qcom,boost-duty-ns = <26>; + qcom,mod-freq-khz = <9600>; + qcom,dim-mode = "hybrid"; + qcom,dim-method = "linear"; + qcom,hyb-thres = <625>; + qcom,sync-dly-us = <800>; + qcom,fs-curr-ua = <20000>; + qcom,led-strings-list = [00 01]; + qcom,en-ext-pfet-sc-pro; + qcom,pmic-revid = <&pmi8950_revid>; + qcom,cons-sync-write-delay-us = <1000>; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + qcom,headroom = <500>; + qcom,startup-dly = <128>; + qcom,clamp-curr = <200>; + qcom,pmic-charger-support; + qcom,self-check-enabled; + qcom,thermal-derate-enabled; + qcom,thermal-derate-threshold = <100>; + qcom,thermal-derate-rate = "5_PERCENT"; + qcom,current-ramp-enabled; + qcom,ramp_up_step = "6P7_US"; + qcom,ramp_dn_step = "6P7_US"; + qcom,vph-pwr-droop-enabled; + qcom,vph-pwr-droop-threshold = <3000>; + qcom,vph-pwr-droop-debounce-time = <10>; + qcom,headroom-sense-ch0-enabled; + qcom,headroom-sense-ch1-enabled; + qcom,pmic-revid = <&pmi8950_revid>; + + pmi8950_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,default-led-trigger = + "flash0_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <0>; + qcom,current = <625>; + }; + + pmi8950_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,default-led-trigger = + "flash1_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <1>; + qcom,current = <625>; + }; + + pmi8950_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,default-led-trigger = + "torch0_trigger"; + qcom,max-current = <200>; + qcom,id = <0>; + qcom,current = <120>; + }; + + pmi8950_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,default-led-trigger = + "torch1_trigger"; + qcom,max-current = <200>; + qcom,id = <1>; + qcom,current = <120>; + }; + + pmi8950_switch: qcom,switch { + label = "switch"; + qcom,led-name = "led:switch"; + qcom,default-led-trigger = + "switch_trigger"; + qcom,max-current = <1000>; + qcom,duration = <1280>; + qcom,id = <2>; + qcom,current = <625>; + reg0 { + regulator-name = "pon_spare_reg"; + }; + }; + }; + + pmi_haptic: qcom,haptic@c000 { + compatible = "qcom,qpnp-haptic"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "sc-irq", "play-irq"; + qcom,pmic-revid = <&pmi8950_revid>; + vcc_pon-supply = <&pon_perph_reg>; + qcom,play-mode = "direct"; + qcom,wave-play-rate-us = <5263>; + qcom,actuator-type = "erm"; + qcom,wave-shape = "square"; + qcom,vmax-mv = <2000>; + qcom,ilim-ma = <800>; + qcom,sc-deb-cycles = <8>; + qcom,int-pwm-freq-khz = <505>; + qcom,en-brake; + qcom,brake-pattern = [03 03 00 00]; + qcom,use-play-irq; + qcom,use-sc-irq; + qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wave-rep-cnt = <1>; + qcom,wave-samp-rep-cnt = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index 923804f49148ab36567e1fb2f18fd4bd538a9cad..2f4b00e0ccd637bfd8184f5dc5dfa51327362801 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -12,9 +12,10 @@ #include #include +#include &spmi_bus { - qcom,pmi8998@2 { + pmi8998_lsid0: qcom,pmi8998@2 { compatible = "qcom,spmi-pmic"; reg = <0x2 SPMI_USID>; #address-cells = <2>; @@ -26,16 +27,23 @@ qcom,fab-id-valid; }; + pmi8998_misc: qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + }; + qcom,power-on@800 { compatible = "qcom,qpnp-power-on"; reg = <0x800 0x100>; }; - qcom,temp-alarm@2400 { - compatible = "qcom,qpnp-temp-alarm"; + pmi8998_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>; - label = "pmi8998_tz"; + io-channels = <&pmi8998_rradc 7>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; }; pmi8998_gpios: pinctrl@c000 { @@ -63,7 +71,7 @@ qcom,gpios-disallowed = <4 7 13>; }; - qcom,qpnp-qnovo@1500 { + pmi8998_qnovo: qcom,qpnp-qnovo@1500 { compatible = "qcom,qpnp-qnovo"; reg = <0x1500 0x100>; interrupts = <0x2 0x15 0x0 IRQ_TYPE_NONE>; @@ -75,6 +83,7 @@ compatible = "qcom,qpnp-smb2"; #address-cells = <1>; #size-cells = <1>; + #cooling-cells = <2>; qcom,pmic-revid = <&pmi8998_revid>; @@ -89,9 +98,12 @@ qcom,boost-threshold-ua = <100000>; qcom,wipower-max-uw = <5000000>; + dpdm-supply = <&qusb_phy0>; qcom,thermal-mitigation = <3000000 1500000 1000000 500000>; + qcom,auto-recharge-soc; + qcom,suspend-input-on-debug-batt; qcom,chgr@1000 { reg = <0x1000 0x100>; @@ -209,7 +221,7 @@ compatible = "qcom,qpnp-pdphy"; reg = <0x1700 0x100>; vdd-pdphy-supply = <&pm8998_l24>; - vbus-supply = <&smb2_vbus>; + vbus-supply = <&ext_5v_boost>; vconn-supply = <&smb2_vconn>; interrupts = <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>, <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>, @@ -268,9 +280,13 @@ 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,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; qcom,cycle-counter-en; + qcom,hold-soc-while-full; + qcom,fg-auto-recharge-soc; + qcom,fg-recharge-soc-thr = <98>; status = "okay"; qcom,fg-batt-soc@4000 { @@ -317,7 +333,8 @@ reg = <0x4400 0x100>; interrupts = <0x2 0x44 0x0 IRQ_TYPE_EDGE_BOTH>, <0x2 0x44 0x1 IRQ_TYPE_EDGE_BOTH>, - <0x2 0x44 0x2 IRQ_TYPE_EDGE_BOTH>; + <0x2 0x44 0x2 + IRQ_TYPE_EDGE_RISING>; interrupt-names = "ima-rdy", "mem-xcp", "dma-grant"; @@ -325,7 +342,7 @@ }; }; - qcom,pmi8998@3 { + pmi8998_lsid1: qcom,pmi8998@3 { compatible ="qcom,spmi-pmic"; reg = <0x3 SPMI_USID>; #address-cells = <2>; @@ -427,7 +444,6 @@ qcom,max-current = <12>; qcom,default-state = "off"; linux,name = "red"; - linux,default-trigger = "battery-charging"; }; green_led: qcom,rgb_1 { @@ -439,7 +455,6 @@ qcom,max-current = <12>; qcom,default-state = "off"; linux,name = "green"; - linux,default-trigger = "battery-full"; }; blue_led: qcom,rgb_2 { @@ -451,7 +466,6 @@ qcom,max-current = <12>; qcom,default-state = "off"; linux,name = "blue"; - linux,default-trigger = "boot-indication"; }; }; @@ -470,6 +484,10 @@ regulator-min-microvolt = <4600000>; regulator-max-microvolt = <6000000>; + interrupts = <0x3 0xdc 0x2 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ibb-sc-err"; + qcom,qpnp-ibb-min-voltage = <1400000>; qcom,qpnp-ibb-step-size = <100000>; qcom,qpnp-ibb-slew-rate = <2000000>; @@ -503,8 +521,11 @@ regulator-max-microvolt = <6000000>; interrupts = <0x3 0xde 0x0 + IRQ_TYPE_EDGE_RISING>, + <0x3 0xde 0x1 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "lab-vreg-ok"; + interrupt-names = "lab-vreg-ok", "lab-sc-err"; + qcom,qpnp-lab-min-voltage = <4600000>; qcom,qpnp-lab-step-size = <100000>; qcom,qpnp-lab-slew-rate = <5000>; @@ -521,7 +542,7 @@ <1600>; qcom,qpnp-lab-limit-maximum-current = <1600>; qcom,qpnp-lab-limit-max-current-enable; - qcom,qpnp-lab-ps-threshold = <20>; + qcom,qpnp-lab-ps-threshold = <70>; qcom,qpnp-lab-ps-enable; qcom,qpnp-lab-nfet-size = <100>; qcom,qpnp-lab-pfet-size = <100>; @@ -556,6 +577,7 @@ qcom,en-ext-pfet-sc-pro; qcom,pmic-revid = <&pmi8998_revid>; qcom,loop-auto-gm-en; + qcom,auto-calibration-enable; status = "disabled"; }; @@ -667,6 +689,36 @@ qcom,led-mask = <4>; qcom,default-led-trigger = "switch1_trigger"; }; + + pmi8998_switch2: qcom,led_switch_2 { + label = "switch"; + qcom,led-name = "led:switch_2"; + qcom,led-mask = <4>; + qcom,default-led-trigger = "switch2_trigger"; + }; + + }; + + pmi8998_haptics: qcom,haptics@c000 { + compatible = "qcom,qpnp-haptics"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hap-sc-irq", "hap-play-irq"; + qcom,pmic-revid = <&pmi8998_revid>; + qcom,pmic-misc = <&pmi8998_misc>; + qcom,misc-clk-trim-error-reg = <0xf3>; + qcom,actuator-type = <0>; + qcom,play-mode = "direct"; + qcom,vmax-mv = <3200>; + qcom,ilim-ma = <800>; + qcom,sc-dbc-cycles = <8>; + qcom,wave-play-rate-us = <6667>; + qcom,en-brake; + qcom,lra-high-z = "opt1"; + qcom,lra-auto-res-mode = "qwd"; + qcom,lra-res-cal-period = <4>; + status = "disabled"; }; }; }; @@ -680,7 +732,7 @@ trips { ibat_high: low-ibat { - temperature = <4200>; + temperature = <5000>; hysteresis = <200>; type = "passive"; }; @@ -694,7 +746,7 @@ trips { ibat_vhigh: ibat_vhigh { - temperature = <4300>; + temperature = <6000>; hysteresis = <100>; type = "passive"; }; @@ -709,7 +761,7 @@ trips { low_vbat: low-vbat { - temperature = <3300>; + temperature = <3200>; hysteresis = <100>; type = "passive"; }; @@ -717,19 +769,27 @@ cooling-maps { vbat_cpu4 { trip = <&low_vbat>; - cooling-device = <&CPU4 22 22>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; vbat_cpu5 { trip = <&low_vbat>; - cooling-device = <&CPU5 22 22>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; vbat_map6 { trip = <&low_vbat>; - cooling-device = <&CPU6 22 22>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; vbat_map7 { trip = <&low_vbat>; - cooling-device = <&CPU7 22 22>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; @@ -742,7 +802,7 @@ trips { low-vbat { - temperature = <3100>; + temperature = <2800>; hysteresis = <0>; type = "passive"; }; @@ -757,7 +817,7 @@ trips { low-vbat { - temperature = <2900>; + temperature = <2600>; hysteresis = <0>; type = "passive"; }; @@ -780,19 +840,51 @@ cooling-maps { soc_cpu4 { trip = <&low_soc>; - cooling-device = <&CPU4 22 22>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; soc_cpu5 { trip = <&low_soc>; - cooling-device = <&CPU5 22 22>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; soc_map6 { trip = <&low_soc>; - cooling-device = <&CPU6 22 22>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; soc_map7 { trip = <&low_soc>; - cooling-device = <&CPU7 22 22>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pmi8998_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmi8998_tz>; + + trips { + pmi8998_trip0: pmi8998-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pmi8998_trip1: pmi8998-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pmi8998_trip2: pmi8998-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-360camera-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..820f877e13a0ed437850dd6c69ee850966d3ced1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-360camera-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017-2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "qcs605-360camera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660+PM660L VRcamera"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <8 5>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera.dts b/arch/arm64/boot/dts/qcom/qcs605-360camera.dts new file mode 100644 index 0000000000000000000000000000000000000000..c62f39d862e6c256ed71f2232313f5afeadbafa2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2018, 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 "qcs605.dtsi" +#include "qcs605-360camera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L 360camera"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,board-id = <8 5>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0983acf1bf8f845147b2f365a5422d3b44dc2e8c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm670-mtp.dtsi" +#include "sdm670-camera-sensor-360camera.dtsi" +#include "sdm670-audio-overlay.dtsi" + +&qupv3_se3_i2c { + status = "disabled"; +}; + +&qupv3_se10_i2c { + status = "okay"; +}; + +&qupv3_se12_2uart { + status = "okay"; +}; + +&qupv3_se6_4uart { + status = "okay"; +}; + +&qupv3_se13_i2c { + status = "disabled"; +}; + +&qupv3_se13_spi { + status = "disabled"; +}; + +&dsi_dual_nt36850_truly_cmd_display { + status = "disabled"; +}; + +&dsi_dual_nt35597_truly_video { + status = "disabled"; +}; + +&int_codec { + qcom,model = "sdm670-360cam-snd-card"; + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "INT_LDO_H", "INT_MCLK0", + "DMIC1", "MIC BIAS External", + "MIC BIAS External", "Digital Mic1", + "DMIC2", "MIC BIAS External", + "MIC BIAS External", "Digital Mic2", + "DMIC3", "MIC BIAS External2", + "MIC BIAS External2", "Digital Mic3", + "DMIC4", "MIC BIAS External2", + "MIC BIAS External2", "Digital Mic4", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT"; + qcom,wsa-max-devs = <0>; +}; + +&tlmm { + pwr_led_green_default: pwr_led_green_default { + mux { + pins = "gpio106"; + function = "gpio"; + }; + config { + pins = "gpio106"; + drive-strength = <8>; /* 8 mA */ + bias-disable; + output-low; + }; + }; + + pwr_led_red_default: pwr_led_red_default { + mux { + pins = "gpio111"; + function = "gpio"; + }; + config { + pins = "gpio111"; + drive-strength = <8>; /* 8 mA */ + bias-disable; + output-low; + }; + }; + + wifi_led_green_default: wifi_led_green_default { + mux { + pins = "gpio114"; + function = "gpio"; + }; + config { + pins = "gpio114"; + drive-strength = <8>; /* 8 mA */ + bias-disable; + output-low; + }; + }; + + wifi_led_red_default: wifi_led_red_default { + mux { + pins = "gpio115"; + function = "gpio"; + }; + config { + pins = "gpio115"; + drive-strength = <8>; /* 8 mA */ + bias-disable; + output-low; + }; + }; + + key_wcnss_default: key_wcnss_default { + mux { + pins = "gpio120"; + function = "gpio"; + }; + config { + pins = "gpio120"; + drive-strength = <8>; /* 8 mA */ + bias-pull-up; + input-enable; + }; + }; + + key_record_default: key_record_default { + mux { + pins = "gpio119"; + function = "gpio"; + }; + config { + pins = "gpio119"; + drive-strength = <8>; /* 8 mA */ + bias-pull-up; + input-enable; + }; + }; + + key_snapshot_default: key_snapshot_default { + mux { + pins = "gpio91"; + function = "gpio"; + }; + config { + pins = "gpio91"; + drive-strength = <8>; /* 8 mA */ + bias-pull-up; + input-enable; + }; + }; +}; + +&soc { + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pwr_led_green_default + &pwr_led_red_default + &wifi_led_green_default + &wifi_led_red_default>; + status = "okay"; + + led@1 { + label = "PWR_LED:red:106"; + gpios = <&tlmm 106 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "wlan"; + default-state = "off"; + }; + + led@2 { + label = "PWR_LED:green:111"; + gpios = <&tlmm 111 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "wlan"; + default-state = "on"; + }; + + led@3 { + label = "WIFI_LED:red:114"; + gpios = <&tlmm 114 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "wlan"; + default-state = "on"; + }; + + led@4 { + label = "WIFI_LED:green:115"; + gpios = <&tlmm 115 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "wlan"; + default-state = "off"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_snapshot_default + &key_record_default + &key_wcnss_default>; + status = "okay"; + cam_snapshot { + label = "cam_snapshot"; + gpios = <&tlmm 91 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <766>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + cam_record { + label = "cam_record"; + gpios = <&tlmm 119 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <766>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + wcnss_key { + label = "wcnss_key"; + gpios = <&tlmm 120 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <528>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; +&pm660_vadc{ + + chan@4e { + label = "emmc_therm"; + reg = <0x4e>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4f { + label = "pa_therm0"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm660_adc_tm{ + + chan@4e { + label = "emmc_therm"; + reg = <0x4e>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x80>; + qcom,thermal-node; + }; + + chan@4f { + label = "pa_therm0"; + reg = <0x4f>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x88>; + qcom,thermal-node; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..01471b65cba3e86876535132278748307d927c86 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L CDP"; + compatible = "qcom,qcs605-cdp", "qcom,qcs605", "qcom,cdp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ea10fa0be87315251fdf0d87a5feb68fb5624978 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, 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 "qcs605.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L CDP"; + compatible = "qcom,qcs605-cdp", "qcom,qcs605", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..44fae6ab54d8433b47e05fb19eddac40de8af17f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..abc3f2da8a2507cc158c9ac9b89331d7eb0863dc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, 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 "qcs605.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..e27baba4f8d4dbd2f30f0dbcb5b3a9bde30d12f1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "qcs605-lc-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <8 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm830-sim.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts similarity index 62% rename from arch/arm64/boot/dts/qcom/sdm830-sim.dts rename to arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts index 57cd155c66b75b3143f31178b58ab5840f5c05c8..194bfeb2db287d34f0fec25dee0fba6edb9c00e5 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-sim.dts +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts @@ -1,4 +1,5 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,16 +11,14 @@ * GNU General Public License for more details. */ - /dts-v1/; -/memreserve/ 0x90000000 0x00000100; -#include "sdm830.dtsi" -#include "sdm830-sim.dtsi" +#include "qcs605.dtsi" +#include "qcs605-lc-mtp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM830 SIM"; - compatible = "qcom,sdm830-sim", "qcom,sdm830", "qcom,sim"; - qcom,board-id = <16 0>; -}; + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,board-id = <8 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..025d9a2b61aa40d96c9b517373441fcaa44a1d62 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi @@ -0,0 +1,205 @@ +/* Copyright (c) 2017, 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 "pm8005.dtsi" +#include "sdm670-pmic-overlay.dtsi" +#include "qcs605-pm660-pm8005-regulator.dtsi" + +/ { + cpus { + /delete-node/ cpu@200; + /delete-node/ cpu@300; + /delete-node/ cpu@400; + /delete-node/ cpu@500; + + cpu-map { + cluster0 { + /delete-node/ core2; + /delete-node/ core3; + /delete-node/ core4; + /delete-node/ core5; + }; + }; + }; + + +}; + +&soc { + /delete-node/ jtagmm@7240000; + /delete-node/ jtagmm@7340000; + /delete-node/ jtagmm@7440000; + /delete-node/ jtagmm@7540000; + /delete-node/ cti@7220000; + /delete-node/ cti@7320000; + /delete-node/ cti@7420000; + /delete-node/ cti@7520000; + /delete-node/ etm@7240000; + /delete-node/ etm@7340000; + /delete-node/ etm@7440000; + /delete-node/ etm@7540000; + cpuss_dump { + /delete-node/ qcom,l1_i_cache200; + /delete-node/ qcom,l1_i_cache300; + /delete-node/ qcom,l1_i_cache400; + /delete-node/ qcom,l1_i_cache500; + /delete-node/ qcom,l1_d_cache200; + /delete-node/ qcom,l1_d_cache300; + /delete-node/ qcom,l1_d_cache400; + /delete-node/ qcom,l1_d_cache500; + /delete-node/ qcom,l1_tlb_dump200; + /delete-node/ qcom,l1_tlb_dump300; + /delete-node/ qcom,l1_tlb_dump400; + /delete-node/ qcom,l1_tlb_dump500; + }; + + devfreq_memlat_0: qcom,cpu0-memlat-mon { + qcom,cpulist = <&CPU0 &CPU1>; + }; + + devfreq_l3lat_0: qcom,cpu0-l3lat-mon { + qcom,cpulist = <&CPU0 &CPU1>; + }; + devfreq_compute0: qcom,devfreq-compute0 { + qcom,cpulist = <&CPU0 &CPU1>; + }; + + funnel_apss: funnel@7800000 { + ports { + /delete-node/ port@3; + /delete-node/ port@4; + /delete-node/ port@5; + /delete-node/ port@6; + }; + }; + + qcom,lpm-levels { + qcom,pm-cluster@0 { + qcom,pm-cpu@0 { + qcom,cpu = <&CPU0 &CPU1>; + }; + }; + }; +}; + +&pm660_temp_alarm { + cooling-maps { + /delete-node/ trip0_cpu2; + /delete-node/ trip0_cpu3; + /delete-node/ trip0_cpu4; + /delete-node/ trip0_cpu5; + /delete-node/ trip1_cpu2; + /delete-node/ trip1_cpu3; + /delete-node/ trip1_cpu4; + /delete-node/ trip1_cpu5; + }; +}; + +&thermal_zones { + + xo-therm-cpu-step { + cooling-maps { + /delete-node/ skin_cpu2; + /delete-node/ skin_cpu3; + /delete-node/ skin_cpu4; + /delete-node/ skin_cpu5; + }; + }; +}; + +&spmi_bus { + /delete-node/ qcom,pm660l@2; + /delete-node/ qcom,pm660l@3; +}; + +&thermal_zones { + pm660l_tz { + /delete-property/ thermal-sensors; + }; +}; + +&soc { + qcom,turing@8300000 { + /delete-property/ vdd_cx-supply; + }; + + qcom,lpass@62400000 { + /delete-property/ vdd_cx-supply; + }; +}; + +&clock_cpucc { + /delete-property/ vdd_l3_mx_ao-supply; + /delete-property/ vdd_pwrcl_mx_ao-supply; +}; + +&clock_gcc { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_cx_ao-supply; +}; + +&clock_videocc { + /delete-property/ vdd_cx-supply; +}; + +&clock_camcc { + /delete-property/ vdd_mx-supply; + /delete-property/ vdd_cx-supply; +}; + +&clock_dispcc { + /delete-property/ vdd_cx-supply; +}; + +&clock_gpucc { + /delete-property/ vdd_mx-supply; + /delete-property/ vdd_cx-supply; +}; + +&pil_modem { + /delete-property/ vdd_mx-supply; + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_mss-supply; +}; + +&clock_gfx { + /delete-property/ vdd_gfx-supply; +}; + +&gpu_gx_gdsc { + /delete-property/ parent-supply; +}; + +&mdss_dsi_phy0 { + /delete-property/ vdda-0p9-supply; +}; + +&mdss_dsi_phy1 { + /delete-property/ vdda-0p9-supply; +}; + +&sde_dp { + /delete-property/ vdda-0p9-supply; +}; + +&qusb_phy0 { + /delete-property/ vdd-supply; + /delete-property/ vdda33-supply; +}; + +&usb_qmp_dp_phy { + /delete-property/ vdd-supply; +}; + +&pm660_pdphy { + /delete-property/ vdd-pdphy-supply; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..65be2754ef9a56b331ce2ab66fc1b46971aa6351 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-mtp-overlay.dts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L MTP"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..b0ca9a32a7b08926035d0cea49ca1286da01b587 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-mtp.dts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, 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 "qcs605.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 PM660 + PM660L MTP"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..382ba65135b91538975c29e5da95daa2604ee3e0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi @@ -0,0 +1,491 @@ +/* Copyright (c) 2017, 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 PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + /* Delete all regulators */ + /delete-node/ rpmh-regulator-smpa4; + /delete-node/ rpmh-regulator-modemlvl; + /delete-node/ rpmh-regulator-smpa6; + /delete-node/ rpmh-regulator-mxlvl; + /delete-node/ rpmh-regulator-gfxlvl; + /delete-node/ rpmh-regulator-cxlvl; + /delete-node/ rpmh-regulator-ldoa1; + /delete-node/ rpmh-regulator-ldoa2; + /delete-node/ rpmh-regulator-ldoa3; + /delete-node/ rpmh-regulator-ldoa5; + /delete-node/ rpmh-regulator-ldoa6; + /delete-node/ rpmh-regulator-ldoa7; + /delete-node/ rpmh-regulator-ldoa8; + /delete-node/ rpmh-regulator-ldoa9; + /delete-node/ rpmh-regulator-ldoa10; + /delete-node/ rpmh-regulator-ldoa11; + /delete-node/ rpmh-regulator-ldoa12; + /delete-node/ rpmh-regulator-ldoa13; + /delete-node/ rpmh-regulator-ldoa14; + /delete-node/ rpmh-regulator-ldoa15; + /delete-node/ rpmh-regulator-ldoa16; + /delete-node/ rpmh-regulator-ldoa17; + /delete-node/ rpmh-regulator-ldoa19; + /delete-node/ rpmh-regulator-ldob1; + /delete-node/ rpmh-regulator-ldob2; + /delete-node/ rpmh-regulator-ldob3; + /delete-node/ rpmh-regulator-ldob4; + /delete-node/ rpmh-regulator-ldob5; + /delete-node/ rpmh-regulator-ldob6; + /delete-node/ rpmh-regulator-ldob7; + /delete-node/ rpmh-regulator-ldob8; + /delete-node/ rpmh-regulator-lcxlvl; + /delete-node/ rpmh-regulator-lmxlvl; + /delete-node/ rpmh-regulator-bobb1; + + /* RPMh regulators */ + + /* pm660 S2 - VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + pm660_s2_level: regulator-pm660-s2 { + regulator-name = "pm660_s2_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660_s2_level_ao: regulator-pm660-s2-level-ao { + regulator-name = "pm660_s2_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pm660_s2_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa4"; + pm660_s4: regulator-pm660-s4 { + regulator-name = "pm660_s4"; + qcom,set = ; + regulator-min-microvolt = <1640000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1640000>; + }; + }; + + /* pm8005 S1 + S4 - VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pm8005_s1_level-parent-supply = <&pm660_s2_level>; + pm8005_s1_level_ao-parent-supply = <&pm660_s2_level_ao>; + pm8005_s1_level: regulator-pm8005-s1-level { + regulator-name = "pm8005_s1_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + pm8005_s1_level_ao: regulator-pm8005-s1-level-ao { + regulator-name = "pm8005_s1_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpc2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc2"; + pm8005_s2: regulator-pm8005-s2 { + regulator-name = "pm8005_s2"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1000000>; + }; + }; + + /* pm8005 S3 - VDD_GFX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "gfx.lvl"; + pm8005_s3_level: regulator-pm8005-s3 { + regulator-name = "pm8005_s3_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l1: regulator-pm660-l1 { + regulator-name = "pm660_l1"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l2: regulator-pm660-l2 { + regulator-name = "pm660_l2"; + qcom,set = ; + regulator-min-microvolt = <1144000>; + regulator-max-microvolt = <1256000>; + qcom,init-voltage = <1144000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l3: regulator-pm660-l3 { + regulator-name = "pm660_l3"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1352000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l5: regulator-pm660-l5 { + regulator-name = "pm660_l5"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l6: regulator-pm660-l6 { + regulator-name = "pm660_l6"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + }; + + /* pm660 L7 = VDD_LPI_CX supply */ + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lcx.lvl"; + pm660_l7_level: regulator-pm660-l7-level { + regulator-name = "pm660_l7_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-ldoa8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l8: regulator-pm660-l8 { + regulator-name = "pm660_l8"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1952000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l9: regulator-pm660-l9 { + regulator-name = "pm660_l9"; + qcom,set = ; + regulator-min-microvolt = <1616000>; + regulator-max-microvolt = <1984000>; + qcom,init-voltage = <1616000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l10: regulator-pm660-l10 { + regulator-name = "pm660_l10"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1952000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l11: regulator-pm660-l11 { + regulator-name = "pm660_l11"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l12: regulator-pm660-l12 { + regulator-name = "pm660_l12"; + qcom,set = ; + regulator-min-microvolt = <1616000>; + regulator-max-microvolt = <1984000>; + qcom,init-voltage = <1616000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l13: regulator-pm660-l13 { + regulator-name = "pm660_l13"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l14: regulator-pm660-l14 { + regulator-name = "pm660_l14"; + qcom,set = ; + regulator-min-microvolt = <1696000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1696000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l15: regulator-pm660-l15 { + regulator-name = "pm660_l15"; + qcom,set = ; + regulator-min-microvolt = <2896000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <2896000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l16: regulator-pm660-l16 { + regulator-name = "pm660_l16"; + qcom,set = ; + regulator-min-microvolt = <2896000>; + regulator-max-microvolt = <3104000>; + qcom,init-voltage = <2896000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l17: regulator-pm660-l17 { + regulator-name = "pm660_l17"; + qcom,set = ; + regulator-min-microvolt = <2920000>; + regulator-max-microvolt = <3232000>; + qcom,init-voltage = <2920000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa18 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l18: regulator-pm660-l18 { + regulator-name = "pm660_l18"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa19 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa19"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l19: regulator-pm660-l19 { + regulator-name = "pm660_l19"; + qcom,set = ; + regulator-min-microvolt = <2944000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2944000>; + qcom,init-mode = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605.dts b/arch/arm64/boot/dts/qcom/qcs605.dts new file mode 100644 index 0000000000000000000000000000000000000000..28c417f644fb82216070556faf3c0f82aa85a3d8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017, 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 "qcs605.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS605 SoC"; + compatible = "qcom,qcs605"; + qcom,board-id = <0 0>; +}; diff --git a/include/linux/soundwire/swr-wcd.h b/arch/arm64/boot/dts/qcom/qcs605.dtsi similarity index 51% rename from include/linux/soundwire/swr-wcd.h rename to arch/arm64/boot/dts/qcom/qcs605.dtsi index 041b901fd954c0955220307d6cff5bc4152b66c4..6cf9a825aacb1d9d619c6b10c6db152b92d6a0b4 100644 --- a/include/linux/soundwire/swr-wcd.h +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -1,4 +1,5 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,26 +11,39 @@ * GNU General Public License for more details. */ -#ifndef _LINUX_SWR_WCD_H -#define _LINUX_SWR_WCD_H -#include -#include -#include -#include +#include "sda670.dtsi" -enum { - SWR_CH_MAP, - SWR_DEVICE_DOWN, - SWR_DEVICE_UP, - SWR_SUBSYS_RESTART, - SWR_SET_NUM_RX_CH, +/ { + model = "Qualcomm Technologies, Inc. QCS605"; + qcom,msm-id = <347 0x0>; }; -struct swr_mstr_port { - int num_port; - u8 *port; +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; }; -extern int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data); +&ipa_hw { + status = "disabled"; +}; + +&thermal_zones { + lmh-dcvs-00 { + trips { + active-config { + temperature = <105000>; + hysteresis = <40000>; + }; + }; + }; -#endif /* _LINUX_SWR_WCD_H */ + lmh-dcvs-01 { + trips { + active-config { + temperature = <105000>; + hysteresis = <40000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sda632.dtsi b/arch/arm64/boot/dts/qcom/sda632.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8a71b199cec2a4746418afd4fb14ecac02d39b23 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda632.dtsi @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, 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 "sdm632.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA632"; + compatible = "qcom,sda632"; + qcom,msm-id = <350 0x0>; +}; + +&secure_mem { + status = "disabled"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sda670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..12a130c8917b7ccae847dfcb0ef51fec66b0c7f6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L CDP"; + compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp"; + qcom,msm-id = <337 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-cdp.dts b/arch/arm64/boot/dts/qcom/sda670-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..9cd99604b2493fc5a0f3d0a3f89956f80e6c43d8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-cdp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, 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 "sda670.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L CDP"; + compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..b3f5a0b4ccd3ad53a96619a55399f263bebecd17 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L MTP"; + compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp"; + qcom,msm-id = <337 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-mtp.dts b/arch/arm64/boot/dts/qcom/sda670-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..253ec0c3687c62268fba85c4cd8be697e5108a43 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-mtp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, 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 "sda670.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660L MTP"; + compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7701c0b659e4681a54ae16e40e19df332b3efd13 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp-overlay.dts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A CDP"; + compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp"; + qcom,msm-id = <337 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..e6f8d505de275bda3ba280b528e2be9ebdd45d01 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-cdp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, 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 "sda670.dtsi" +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A CDP"; + compatible = "qcom,sda670-cdp", "qcom,sda670", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..0b355abfb5f248472c7edbc404d8e8dc732c839c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp-overlay.dts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A MTP"; + compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp"; + qcom,msm-id = <337 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..0d7e34ae9ca81baf2a0524e5c34d402c0a477888 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, 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 "sda670.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 PM660 + PM660A MTP"; + compatible = "qcom,sda670-mtp", "qcom,sda670", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670.dts b/arch/arm64/boot/dts/qcom/sda670.dts new file mode 100644 index 0000000000000000000000000000000000000000..8852e30848f10af4bfe5238b030ef9b450f11af5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017, 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 "sda670.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670 SoC"; + compatible = "qcom,sda670"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda670.dtsi b/arch/arm64/boot/dts/qcom/sda670.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d19aac34f57b06d70f22ca0ddedf8e22d2183d71 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda670.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2017, 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 "sdm670.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA670"; + qcom,msm-id = <337 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-4k-panel-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..980a57fdb621300ca0e2f2d791e73b6cfb2e6619 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-4k-panel-cdp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 4K Display Panel CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x10000>; + qcom,board-id = <1 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-4k-panel-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..46fb25959dc085df13d9a3d7e0f3e7856c105e6f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-4k-panel-mtp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 4K Display Panel MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x10000>; + qcom,board-id = <8 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-4k-panel-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1cbfe15bc526c04f1c19b5b77d42c3e1a75160d6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-4k-panel-qrd-overlay.dts @@ -0,0 +1,64 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 4K Display Panel QRD"; + compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd"; + qcom,msm-id = <341 0x10000>; + qcom,board-id = <11 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..20d4006a9feb2be3ba4ca014d1671add55b8f7ea --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-cdp-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v1 CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x10000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..9d58ebe5e768ddd88337e6af06f8eb34f4f4f80e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-mtp-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v1 MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x10000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..683cdae5ff3bb2cb22ad0382374b5c670d3062a3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-qrd-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v1 QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <341 0x10000>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..944ca3b49236342a8b972b2cf8db1afad51e6ec4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi @@ -0,0 +1,271 @@ +/* Copyright (c) 2017-2018, 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. + */ + +&mdm3 { + pinctrl-names = "default", "mdm_active", "mdm_suspend"; + pinctrl-0 = <&ap2mdm_pon_reset_default>; + pinctrl-1 = <&ap2mdm_active &mdm2ap_active>; + pinctrl-2 = <&ap2mdm_sleep &mdm2ap_sleep>; + interrupt-map = <0 &tlmm 24 0x3 + 1 &tlmm 21 0x3>; + qcom,mdm2ap-errfatal-gpio = <&tlmm 24 0x00>; + qcom,ap2mdm-errfatal-gpio = <&tlmm 23 0x00>; + qcom,mdm2ap-status-gpio = <&tlmm 22 0x00>; + qcom,ap2mdm-status-gpio = <&tlmm 21 0x00>; + qcom,ap2mdm-soft-reset-gpio = <&pm8998_gpios 10 0>; + qcom,mdm-link-info = "0304_00.01.00"; + status = "ok"; +}; + +&pm8998_gpios { + ap2mdm_pon_reset { + ap2mdm_pon_reset_default: ap2mdm_pon_reset_default { + /* MDM PON conrol*/ + pins = "gpio10"; + function = "normal"; + output-low; + power-source = <0>; + }; + }; +}; + +&pil_modem { + status = "disabled"; +}; + +&pcie0_wake_default { + config { + /delete-property/ bias-pull-down; + }; +}; + +&led_flash_rear { + status = "disabled"; +}; + +&led_flash_front { + status = "disabled"; +}; + +&ois_rear { + status = "disabled"; +}; + +&eeprom_rear { + status = "disabled"; +}; + +&eeprom_rear_aux { + status = "disabled"; +}; + +&eeprom_front { + status = "disabled"; +}; + +&soc { + qcom,cam-req-mgr { + status = "disabled"; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + status = "disabled"; + }; + + cam_csiphy1: qcom,csiphy@ac66000 { + status = "disabled"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + status = "disabled"; + }; + + cam_cci: qcom,cci@ac4a000 { + status = "disabled"; + + i2c_freq_100Khz: qcom,i2c_standard_mode { + status = "disabled"; + }; + + i2c_freq_400Khz: qcom,i2c_fast_mode { + status = "disabled"; + }; + + i2c_freq_custom: qcom,i2c_custom_mode { + status = "disabled"; + }; + + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + status = "disabled"; + }; + }; + + qcom,cam_smmu { + status = "disabled"; + + msm_cam_smmu_ife { + ife_iova_mem_map: iova-mem-map { + iova-mem-region-io { + status = "disabled"; + }; + }; + }; + + msm_cam_smmu_jpeg { + jpeg_iova_mem_map: iova-mem-map { + iova-mem-region-io { + status = "disabled"; + }; + }; + }; + + msm_cam_smmu_icp { + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + status = "disabled"; + }; + + iova-mem-region-shared { + status = "disabled"; + }; + + iova-mem-region-io { + status = "disabled"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + status = "disabled"; + }; + }; + }; + + msm_cam_smmu_fd { + fd_iova_mem_map: iova-mem-map { + iova-mem-region-io { + status = "disabled"; + }; + }; + }; + }; + + qcom,cam-cpas@ac40000 { + status = "disabled"; + }; + + qcom,cam-cdm-intf { + status = "disabled"; + }; + + qcom,cpas-cdm0@ac48000 { + status = "disabled"; + }; + + qcom,cam-isp { + status = "disabled"; + }; + + cam_csid0: qcom,csid0@acb3000 { + status = "disabled"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + status = "disabled"; + }; + + cam_csid1: qcom,csid1@acba000 { + status = "disabled"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + status = "disabled"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + status = "disabled"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + status = "disabled"; + }; + + qcom,cam-icp { + status = "disabled"; + }; + + cam_a5: qcom,a5@ac00000 { + status = "disabled"; + }; + + cam_ipe0: qcom,ipe0 { + status = "disabled"; + }; + + cam_ipe1: qcom,ipe1 { + status = "disabled"; + }; + + cam_bps: qcom,bps { + status = "disabled"; + }; + + clock_camcc: qcom,camcc@ad00000 { + status = "disabled"; + }; + + qcom,cam-jpeg { + status = "disabled"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + status = "disabled"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000 { + status = "disabled"; + }; + + qcom,cam-fd { + status = "disabled"; + }; + + cam_fd: qcom,fd@ac5a000 { + status = "disabled"; + }; + + qcom,cam-sensor@0 { + status = "disabled"; + }; + + qcom,cam-sensor@1 { + status = "disabled"; + }; + + qcom,cam-sensor@2 { + status = "disabled"; + }; + + qcom,cam-sensor@3 { + status = "disabled"; + }; + + cam_csiphy3: qcom,csiphy@ac68000 { + status = "disabled"; + }; +}; + +&wil6210 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..9b7449e998fb9f911e89b6d324fcd3ae4714b1cf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <1 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..bb310d3a339b1e9a189d9cca6f618e0e1390aade --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <8 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ab61f2efafc3e459a16be8c861ae971519d8b0c3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts @@ -0,0 +1,64 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel QRD"; + compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <11 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7de66c0ba27ea8391a92aa7822ddea375bc47eeb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-cdp-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2 CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-hdk-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-hdk-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..bae7ee1cfd50cade396ede16c93124929b2b40c9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-hdk-overlay.dts @@ -0,0 +1,54 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include "sda845-v2-hdk.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-hdk-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2 HDK"; + compatible = "qcom,sda845-hdk", "qcom,sda845", "qcom,hdk"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <0x01001F 0x00>; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt36850_truly_cmd_display { + qcom,dsi-display-active; +}; + +&labibb { + status = "ok"; + qcom,qpnp-labibb-mode = "lcd"; +}; + +&pmi8998_wled { + status = "okay"; + qcom,led-strings-list = [01 02]; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dts b/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dts new file mode 100644 index 0000000000000000000000000000000000000000..17f832485a49907f040f76659100fe3562032358 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017, 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 "sda845-v2.dtsi" +#include "sda845-v2-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 HDK"; + compatible = "qcom,sda845-hdk", "qcom,sda845", "qcom,hdk"; + qcom,board-id = <0x01001F 0x00>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..378c4a138c59f3bf7eb579b2e40223f508adc53c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dtsi @@ -0,0 +1,93 @@ +/* Copyright (c) 2017, 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 "sdm845-qvr.dtsi" +#include "sdm845-camera-sensor-mtp.dtsi" + +&vendor { + qcom,battery-data { + #include "fg-gen3-batterydata-mlp356477-2800mah.dtsi" + }; +}; + +&sdhc_2 { + cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>; +}; + +&usb1 { + status = "ok"; + dwc3@a800000 { + maximum-speed = "high-speed"; + dr_mode = "host"; + }; +}; + +&qusb_phy1 { + status = "ok"; +}; + +&usb_qmp_phy { + status = "ok"; +}; + +&tlmm { + pmx_ts_rst_active { + ts_rst_active: ts_rst_active { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + + pmx_ts_rst_suspend { + ts_rst_suspend: ts_rst_suspend { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; + +&soc { + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm8998_l28>; + vcc_dig-supply = <&pm8998_l14>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3000000>; + qcom,afe-vtg-max = <3000000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1800000>; + qcom,dig-vtg-max = <1800000>; + qcom,fb-resume-delay-us = <1000>; + qcom,afe-force-power-on; + qcom,afe-power-on-delay-us = <6>; + qcom,afe-power-off-delay-us = <6>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a5d20694e3bbbe2a0df125ecb88a53c01e631faa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2 MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5377813c56b578177a5c68c2bb45ec463a8ccd07 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "external-soc.dtsi" +#include "sda845-sdxpoorwills.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2 + SDXPOORWILLS MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <8 5>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a2da1b8c17d64af7e45a979471d43ae672701169 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2-qrd-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2 QRD"; + compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd"; + qcom,msm-id = <341 0x20000>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d49fdb6a8d057189618a6c0d66a33b64be5d7329 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-cdp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2.1 4K Display Panel CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <1 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c79749214a41635f37947a6ffe024368681c8421 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-mtp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2.1 4K Display Panel MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <8 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..221a1d73d83e83787b0c6106e4be11e3065754d7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-4k-panel-qrd-overlay.dts @@ -0,0 +1,64 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2.1 4K Display Panel QRD"; + compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <11 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..64af617da73a1ddf8277c82dd6632afdf802c6bc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2.1 CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..10e4a32edcb88b4d5108ad7f0fd84a82b24de568 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "external-soc.dtsi" +#include "sda845-sdxpoorwills.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2.1 + SDXPOORWILLS CDP"; + compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <1 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..931f0e259226ffaa9cb0154523815a7a4945d24a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sda845 v2.1 MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..09fa20f2aaaec0fd5216bd9d85d347df8e025027 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "external-soc.dtsi" +#include "sda845-sdxpoorwills.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2.1 + SDXPOORWILLS MTP"; + compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <8 5>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d279fce20301fea054bf7dafc7075f02d2b20a88 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-qrd-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2.1 QRD"; + compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd"; + qcom,msm-id = <341 0x20001>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1.dts new file mode 100644 index 0000000000000000000000000000000000000000..97065874fe523c227da7c228f3055dec26df05c7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sda845-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2.1 SoC"; + compatible = "qcom,sda845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1.dtsi b/arch/arm64/boot/dts/qcom/sda845-v2.1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fe70be151ca761edddcdf7ed00576c65794c93d2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.1.dtsi @@ -0,0 +1,18 @@ +/* Copyright (c) 2017, 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 "sdm845-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 845 V2.1"; + qcom,msm-id = <341 0x20001>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.dts b/arch/arm64/boot/dts/qcom/sda845-v2.dts new file mode 100644 index 0000000000000000000000000000000000000000..38ab5ca7698beffbcc006903a0286efa324af9be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sda845-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v2 SoC"; + compatible = "qcom,sda845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.dtsi b/arch/arm64/boot/dts/qcom/sda845-v2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..df1f0d10f3b137af0c7b71d8df7258844d06a523 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845-v2.dtsi @@ -0,0 +1,18 @@ +/* Copyright (c) 2017, 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 "sdm845-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 845 V2"; + qcom,msm-id = <341 0x20000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845.dts b/arch/arm64/boot/dts/qcom/sda845.dts new file mode 100644 index 0000000000000000000000000000000000000000..698388c88ff2a755a11dc6ac2344dd38836eb1a0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sda845.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA845 v1 SoC"; + compatible = "qcom,sda845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sda845.dtsi b/arch/arm64/boot/dts/qcom/sda845.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..aa9b733083b5b91c241a8f91eca4ad6e48fb36e6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda845.dtsi @@ -0,0 +1,18 @@ +/* Copyright (c) 2017, 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 "sdm845.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 845"; + qcom,msm-id = <341 0x10000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..c55622abcfc8814f8d7e0d4dc84b17806655bfa5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-cdp.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm450.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 CDP"; + compatible = "qcom,sdm450-cdp", "qcom,sdm450", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-iot-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-iot-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..9c8cd38dab6abede620c162b7c7ec64e169d207f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-iot-mtp.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm450.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 IOT MTP"; + compatible = "qcom,sdm450-mtp", "qcom,sdm450", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..040b4ba13abb76c96aade65ea510a781933c4d55 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm450.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 MTP"; + compatible = "qcom,sdm450-mtp", "qcom,sdm450", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts new file mode 100644 index 0000000000000000000000000000000000000000..68f02a8577735dd9b98f86de6bbb91d56612b0c8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, 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 "sdm450.dtsi" +#include "sdm450-pmi632-cdp-s2.dtsi" +#include "sdm450-pmi632.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI632 CDP S2"; + compatible = "qcom,sdm450-cdp", "qcom,sdm450", "qcom,cdp"; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..220ec2059826b4b9c8188e1f8a36ccec1b6a9c61 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-cdp-s2.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018, 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 "msm8953-cdp.dtsi" + diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts new file mode 100644 index 0000000000000000000000000000000000000000..b9aadc190880fcfbd71c1c2c140e3bd46edfcedb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, 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 "sdm450.dtsi" +#include "sdm450-pmi632-mtp-s3.dtsi" +#include "sdm450-pmi632.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI632 MTP S3"; + compatible = "qcom,sdm450-mtp", "qcom,sdm450", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..adb7f47d61976267df3b7a44285625f898838d36 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018, 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 "msm8953-mtp.dtsi" + diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..413612d0cf1c1d24e6c97925c046fca606c7426f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017-2018, 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 "pmi632.dtsi" + +&spmi_bus { + /delete-node/ qcom,pmi8950@2; + /delete-node/ qcom,pmi8950@3; +}; + +&pm8953_typec { + status = "disabled"; +}; + +&pmi632_pon { + qcom,ps-hold-hard-reset-disable; + qcom,ps-hold-shutdown-disable; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..4964a5f55dd93ae42ca87857940d4bb80c5705a6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937-mtp.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016-2018, 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 "sdm450.dtsi" +#include "pmi8937.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 MTP"; + compatible = "qcom,sdm450-mtp", "qcom,sdm450", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x010016 0x020037 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts new file mode 100644 index 0000000000000000000000000000000000000000..700e9506de45486fbccf4b9fa13ef4158247aaab --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, 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 "sdm450.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC"; + compatible = "qcom,sdm450"; + qcom,pmic-id = <0x010016 0x020037 0x0 0x0>; + qcom,pmic-name = "PMI8937"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..9bed8d3ca61e294151908855ab5cfaa7a5b2b7ce --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940-mtp.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016-2018, 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 "sdm450.dtsi" +#include "pmi8940.dtsi" +#include "msm8953-mtp.dtsi" +#include "msm8953-pmi8940.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 MTP"; + compatible = "qcom,sdm450-mtp", "qcom,sdm450", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x010016 0x020040 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts new file mode 100644 index 0000000000000000000000000000000000000000..f50d1775ee494e5a4b5c35e95c8a0225ba239259 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, 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 "sdm450.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC"; + compatible = "qcom,sdm450"; + qcom,pmic-id = <0x010016 0x020040 0x0 0x0>; + qcom,pmic-name = "PMI8940"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts new file mode 100644 index 0000000000000000000000000000000000000000..977a9783107e39ab9a148f1340acb15c43033515 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, 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 "sdm450.dtsi" +#include "sdm450-qrd-sku4.dtsi" +#include "sdm450-pmi632.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI632 QRD SKU4"; + compatible = "qcom,sdm450-qrd", "qcom,sdm450", "qcom,qrd"; + qcom,board-id = <0xb 1>; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0a9852860269ffc720c38252b8630d5ed14043e3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018, 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 "msm8953-qrd.dtsi" + +&i2c_3 { + status = "disabled"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..3c2e25b21edd4598add584a6d6cebeb2e4e9c983 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-qrd.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, 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 "sdm450.dtsi" +#include "msm8953-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 QRD"; + compatible = "qcom,sdm450-qrd", "qcom,sdm450", "qcom,qrd"; + qcom,board-id = <0x5000b 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-rcm.dts b/arch/arm64/boot/dts/qcom/sdm450-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..1b7831b32ad6c56c0336f79a09aee93e2d2a9f4f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450-rcm.dts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm450.dtsi" +#include "pmi8950.dtsi" +#include "msm8953-cdp.dtsi" +#include "msm8953-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 RCM"; + compatible = "qcom,sdm450-cdp", "qcom,sdm450", "qcom,cdp"; + qcom,board-id = <21 0>; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts new file mode 100644 index 0000000000000000000000000000000000000000..b829b8186bf431649a89a50dcee3054054fc0e68 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, 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 "sdm450.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC"; + compatible = "qcom,sdm450"; + qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; + qcom,pmic-name = "PMI8950"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3e247145f8338d54762898429e0d6ca62a36b44e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm450.dtsi @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2018, 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 "msm8953.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM450"; + compatible = "qcom,sdm450"; + qcom,msm-id = <338 0x0>; + qcom,msm-name = "SDM450"; +}; + +&CPU4 { + efficiency = <1024>; +}; + +&CPU5 { + efficiency = <1024>; +}; + +&CPU6 { + efficiency = <1024>; +}; + +&CPU7 { + efficiency = <1024>; +}; + +&clock_gcc_gfx { + compatible = "qcom,gcc-gfx-sdm450"; + qcom,gfxfreq-corner = + < 0 0 >, + < 133330000 1 >, /* Min SVS */ + < 216000000 2 >, /* Low SVS */ + < 320000000 3 >, /* SVS */ + < 400000000 4 >, /* SVS Plus */ + < 510000000 5 >, /* NOM */ + < 560000000 6 >, /* Nom Plus */ + < 600000000 7 >; /* Turbo */ +}; diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..031fd7e4d69b14a8de84ffa282e498265c0534c7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2018, 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. + */ + +/ { + /delete-node/ cpus; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + core1 { + cpu = <&CPU5>; + }; + core2 { + cpu = <&CPU6>; + }; + core3 { + cpu = <&CPU7>; + }; + }; + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + /* A53 L2 dump not supported */ + qcom,dump-size = <0x0>; + }; + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x1>; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + L1_I_1: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_1: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_1: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x2>; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + L1_I_2: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_2: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_2: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x3>; + efficiency = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + next-level-cache = <&L2_0>; + L1_I_3: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_3: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_3: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x100>; + efficiency = <1638>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + L2_1: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x101>; + efficiency = <1638>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + L1_I_101: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_101: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_101: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x102>; + efficiency = <1638>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + L1_I_102: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_102: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_102: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a53","arm,armv8"; + enable-method = "psci"; + reg = <0x0 0x103>; + efficiency = <1638>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>; + next-level-cache = <&L2_1>; + L1_I_103: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_103: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_103: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + }; +}; + +&cpuss_dump { + qcom,l1_tlb_dump0 { + qcom,dump-node = <&L1_TLB_0>; + qcom,dump-id = <0x20>; + }; + qcom,l1_tlb_dump1 { + qcom,dump-node = <&L1_TLB_1>; + qcom,dump-id = <0x21>; + }; + qcom,l1_tlb_dump2 { + qcom,dump-node = <&L1_TLB_2>; + qcom,dump-id = <0x22>; + }; + qcom,l1_tlb_dump3 { + qcom,dump-node = <&L1_TLB_3>; + qcom,dump-id = <0x23>; + }; + qcom,l1_tlb_dump100 { + qcom,dump-node = <&L1_TLB_100>; + qcom,dump-id = <0x24>; + }; + qcom,l1_tlb_dump101 { + qcom,dump-node = <&L1_TLB_101>; + qcom,dump-id = <0x25>; + }; + qcom,l1_tlb_dump102 { + qcom,dump-node = <&L1_TLB_102>; + qcom,dump-id = <0x26>; + }; + qcom,l1_tlb_dump103 { + qcom,dump-node = <&L1_TLB_103>; + qcom,dump-id = <0x27>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm830-rumi.dts b/arch/arm64/boot/dts/qcom/sdm632-rumi.dts similarity index 65% rename from arch/arm64/boot/dts/qcom/sdm830-rumi.dts rename to arch/arm64/boot/dts/qcom/sdm632-rumi.dts index 2485051c4ed4a3147f70bffe7a36188ee07fdda8..5a6f88aa4f5f2c311aed1520939ed21a48df81da 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-rumi.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-rumi.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, 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 @@ -12,14 +12,13 @@ */ /dts-v1/; -/memreserve/ 0x90000000 0x00000100; -#include "sdm830.dtsi" -#include "sdm830-rumi.dtsi" +#include "sdm632.dtsi" +#include "sdm632-rumi.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM830 RUMI"; - compatible = "qcom,sdm830-rumi", "qcom,sdm830", "qcom,rumi"; + model = "Qualcomm Technologies, Inc. SDM632 RUMI"; + compatible = "qcom,sdm632-rumi", "qcom,sdm632", "qcom,rumi"; qcom,board-id = <15 0>; + qcom,pmic-id = <0 0 0 0>; }; - diff --git a/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3ba8a4d8ff286640af5afaee17ae546e271e2fab --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018, 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. + */ + +&blsp1_serial1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_console_active>; +}; + +&wdog { + status = "disabled"; +}; + +&modem_mem { + status = "disabled"; +}; + +&adsp_fw_mem { + status = "disabled"; +}; + +&wcnss_fw_mem { + status = "disabled"; +}; + +&venus_mem { + status = "disabled"; +}; + +&secure_mem { + status = "disabled"; +}; + +&qseecom_mem { + status = "disabled"; +}; + +&adsp_mem { + status = "disabled"; +}; + +&dfps_data_mem { + status = "disabled"; +}; + +&cont_splash_mem { + status = "disabled"; +}; + +&gpu_mem { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3ebd50e72e44f61568204bcc9f8123f3a690465e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, 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 "msm8953.dtsi" +#include "sdm632-cpu.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM632"; + compatible = "qcom,sdm632"; + qcom,msm-id = <349 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2b3cb3970dfe53a9dd56bba99467193388c2b560 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm670-wcd.dtsi" +#include "sdm670-wsa881x.dtsi" +#include "sdm670-lpi.dtsi" +#include + +&tavil_snd { + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,msm-mclk-freq = <9600000>; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&tasha_snd { + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-mclk-freq = <9600000>; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&int_codec { + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "INT_LDO_H", "INT_MCLK0", + "RX_I2S_CLK", "INT_MCLK0", + "TX_I2S_CLK", "INT_MCLK0", + "MIC BIAS External", "Handset Mic", + "MIC BIAS External2", "Headset Mic", + "MIC BIAS External", "Secondary Mic", + "AMIC1", "MIC BIAS External", + "AMIC2", "MIC BIAS External2", + "AMIC3", "MIC BIAS External", + "DMIC1", "MIC BIAS External", + "MIC BIAS External", "Digital Mic1", + "DMIC2", "MIC BIAS External", + "MIC BIAS External", "Digital Mic2", + "DMIC3", "MIC BIAS External", + "MIC BIAS External", "Digital Mic3", + "DMIC4", "MIC BIAS External", + "MIC BIAS External", "Digital Mic4", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT"; + + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-micbias2-ext-cap; + qcom,msm-hs-micbias-type = "external"; + qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>; + qcom,cdc-comp-gpios = <&cdc_comp_gpios>; + qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>; + + asoc-codec = <&stub_codec>, <&msm_digital_codec>, + <&pmic_analog_codec>, <&msm_sdw_codec>, + <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec", + "analog-codec", "msm_sdw_codec", + "msm-ext-disp-audio-codec-rx"; + + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>, + <&wsa881x_213_en>, <&wsa881x_214_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&soc { + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; + + cdc_pdm_gpios: cdc_pdm_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active + &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active + &cdc_pdm_2_gpios_active>; + pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep + &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep + &cdc_pdm_2_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_comp_gpios: cdc_comp_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>; + pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic_gpios: cdc_dmic_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic12_gpios_active + &cdc_dmic34_gpios_active>; + pinctrl-1 = <&cdc_dmic12_gpios_sleep + &cdc_dmic34_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_sdw_gpios: sdw_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sdw_clk_active &sdw_data_active>; + pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>; + }; + + wsa_spkr_en1: wsa_spkr_en1_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_en2: wsa_spkr_en2_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + msm_sdw_codec: msm-sdw-codec@62ec1000 { + status = "okay"; + compatible = "qcom,msm-sdw-codec"; + reg = <0x62ec1000 0x0>; + interrupts = <0 88 0>; + interrupt-names = "swr_master_irq"; + qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>; + + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211_en: wsa881x_en@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_212_en: wsa881x_en@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + + wsa881x_213_en: wsa881x_en@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_214_en: wsa881x_en@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + }; + }; + + wcd9xxx_intc: wcd9xxx-irq { + status = "disabled"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 80 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio_native: audio_ext_clk_native { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + #clock-cells = <1>; + qcom,lpass-mclk-id = <0x116>; + qcom,codec-mclk-clk-freq = <11289600>; + qcom,audio-ref-clk-gpio = <&lpi_tlmm 19 0>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&lpi_mclk0_sleep>; + pinctrl-1 = <&lpi_mclk0_active>; + }; + + clock_audio: audio_ext_clk { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&tasha_mclk_default>; + pinctrl-1 = <&tasha_mclk_default>; + qcom,audio-ref-clk-gpio = <&pm660_gpios 3 0>; + clock-names = "osr_clk"; + clocks = <&pm660_div_clk>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + status = "disabled"; + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&lpi_cdc_reset_active>; + pinctrl-1 = <&lpi_cdc_reset_sleep>; + qcom,lpi-gpios; + }; + + wdsp_mgr: qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi_xprt_wdsp 2>; + qcom,img-filename = "cpe_9340"; + }; + + wdsp_glink: qcom,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + }; +}; + +&slim_aud { + wcd9335: tasha_codec { + status = "disabled"; + compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 a0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk", "wcd_native_clk"; + clocks = <&clock_audio AUDIO_PMI_CLK>, + <&clock_audio_native AUDIO_LPASS_MCLK>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; + + wcd934x_cdc: tavil_codec { + status = "disabled"; + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <0>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + }; +}; + +&pm660l_3 { + pmic_analog_codec: analog-codec@f000 { + status = "okay"; + compatible = "qcom,pmic-analog-codec"; + reg = <0xf000 0x200>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x3 0xf0 0x0 IRQ_TYPE_NONE>, + <0x3 0xf0 0x1 IRQ_TYPE_NONE>, + <0x3 0xf0 0x2 IRQ_TYPE_NONE>, + <0x3 0xf0 0x3 IRQ_TYPE_NONE>, + <0x3 0xf0 0x4 IRQ_TYPE_NONE>, + <0x3 0xf0 0x5 IRQ_TYPE_NONE>, + <0x3 0xf0 0x6 IRQ_TYPE_NONE>, + <0x3 0xf0 0x7 IRQ_TYPE_NONE>, + <0x3 0xf1 0x0 IRQ_TYPE_NONE>, + <0x3 0xf1 0x1 IRQ_TYPE_NONE>, + <0x3 0xf1 0x2 IRQ_TYPE_NONE>, + <0x3 0xf1 0x3 IRQ_TYPE_NONE>, + <0x3 0xf1 0x4 IRQ_TYPE_NONE>, + <0x3 0xf1 0x5 IRQ_TYPE_NONE>; + interrupt-names = "spk_cnp_int", + "spk_clip_int", + "spk_ocp_int", + "ins_rem_det1", + "but_rel_det", + "but_press_det", + "ins_rem_det", + "mbhc_int", + "ear_ocp_int", + "hphr_ocp_int", + "hphl_ocp_det", + "ear_cnp_int", + "hphr_cnp_int", + "hphl_cnp_int"; + + cdc-vdda-cp-supply = <&pm660_s4>; + qcom,cdc-vdda-cp-voltage = <1900000 2050000>; + qcom,cdc-vdda-cp-current = <50000>; + + cdc-vdd-pa-supply = <&pm660_s4>; + qcom,cdc-vdd-pa-voltage = <2040000 2040000>; + qcom,cdc-vdd-pa-current = <260000>; + + cdc-vdd-mic-bias-supply = <&pm660l_l7>; + qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>; + qcom,cdc-vdd-mic-bias-current = <5000>; + + qcom,cdc-mclk-clk-rate = <9600000>; + + qcom,cdc-static-supplies = "cdc-vdda-cp", + "cdc-vdd-pa"; + + qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias"; + + /* + * Not marking address @ as driver searches this child + * with name msm-dig-codec + */ + msm_digital_codec: msm-dig-codec { + compatible = "qcom,msm-digital-codec"; + reg = <0x62ec0000 0x0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..faaf644430234535e1836850c8de0594c8deb6f9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2017-2018, 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 "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x1801 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&soc { + audio_load_mod { + compatible = "qcom,audio-load-mod"; + audio_test_mod { + compatible = "qcom,audio-test-mod"; + }; + }; + + qcom,avtimer@62cf700c { + compatible = "qcom,avtimer"; + reg = <0x62cf700c 0x4>, + <0x62cf7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <192>; + qcom,clk-mult = <10>; + }; + + tavil_snd: sound-tavil { + status = "disabled"; + compatible = "qcom,sdm670-asoc-snd-tavil"; + qcom,model = "sdm670-tavil-snd-card"; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,ext-disp-audio-rx; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s4>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&dai_quin_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_rx>, <&sb_5_tx>, + <&sb_6_rx>, <&sb_7_rx>, <&sb_7_tx>, + <&sb_8_rx>, <&sb_8_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16394", "msm-dai-q6-dev.16395", + "msm-dai-q6-dev.16396", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929"; + }; + + tasha_snd: sound-tasha { + status = "disabled"; + compatible = "qcom,sdm670-asoc-snd-tasha"; + qcom,model = "sdm670-tasha-snd-card"; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>, <&cpe3>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq", + "msm-cpe-lsm.3"; + asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s4>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&dai_quin_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_rx>, <&sb_5_tx>, + <&sb_6_rx>, <&sb_7_rx>, <&sb_7_tx>, + <&sb_8_rx>, <&sb_8_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16394", "msm-dai-q6-dev.16395", + "msm-dai-q6-dev.16396", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929"; + }; + + int_codec: sound { + status = "okay"; + compatible = "qcom,sdm670-asoc-snd"; + qcom,model = "sdm670-mtp-snd-card"; + qcom,wcn-btfm; + qcom,ext-disp-audio-rx; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s4>, + <&dai_int_mi2s0>, <&dai_int_mi2s1>, + <&dai_int_mi2s2>, <&dai_int_mi2s3>, + <&dai_int_mi2s4>, <&dai_int_mi2s5>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_7_rx>, <&sb_7_tx>, + <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0","msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", + "msm-dai-q6-mi2s.7", "msm-dai-q6-mi2s.8", + "msm-dai-q6-mi2s.9", "msm-dai-q6-mi2s.10", + "msm-dai-q6-mi2s.11", "msm-dai-q6-mi2s.12", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16401", "msm-dai-q6-dev.16400", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929"; + }; + + cpe: qcom,msm-cpe-lsm { + compatible = "qcom,msm-cpe-lsm"; + }; + + cpe3: qcom,msm-cpe-lsm@3 { + compatible = "qcom,msm-cpe-lsm"; + qcom,msm-cpe-lsm-id = <3>; + }; +}; + +&slim_aud { + status = "disabled"; + dai_slim: msm_dai_slim { + status = "disabled"; + compatible = "qcom,msm-dai-slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; +}; + +&msm_dai_mi2s { + dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <7>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <8>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <9>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <10>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <11>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <12>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <13>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4f5a9b1555955ec03de9b411657869e08d9a6818 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi @@ -0,0 +1,1871 @@ +/* Copyright (c) 2017, 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 +#include +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x016E0000 0x40000>, + <0x1700000 0x40000>, + <0x1500000 0x40000>, + <0x14E0000 0x40000>, + <0x17900000 0x40000>, + <0x1380000 0x40000>, + <0x1380000 0x40000>, + <0x1740000 0x40000>, + <0x1620000 0x40000>, + <0x1620000 0x40000>, + <0x1620000 0x40000>; + + reg-names = "aggre1_noc-base", "aggre2_noc-base", + "config_noc-base", "dc_noc-base", + "gladiator_noc-base", "mc_virt-base", "mem_noc-base", + "mmss_noc-base", "system_noc-base", "ipa_virt-base", + "camnoc_virt-base"; + + mbox-names = "apps_rsc", "disp_rsc"; + mboxes = <&apps_rsc 0 &disp_rsc 0>; + + /*RSCs*/ + rsc_apps: rsc-apps { + cell-id = ; + label = "apps_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + rsc_disp: rsc-disp { + cell-id = ; + label = "disp_rsc"; + qcom,rsc-dev; + qcom,req_state = <3>; + }; + + /*BCMs*/ + bcm_acv: bcm-acv { + cell-id = ; + label = "ACV"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_alc: bcm-alc { + cell-id = ; + label = "ALC"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mc0: bcm-mc0 { + cell-id = ; + label = "MC0"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh0: bcm-sh0 { + cell-id = ; + label = "SH0"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm0: bcm-mm0 { + cell-id = ; + label = "MM0"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh1: bcm-sh1 { + cell-id = ; + label = "SH1"; + qcom,bcm-name = "SH1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm1: bcm-mm1 { + cell-id = ; + label = "MM1"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh2: bcm-sh2 { + cell-id = ; + label = "SH2"; + qcom,bcm-name = "SH2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm2: bcm-mm2 { + cell-id = ; + label = "MM2"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh3: bcm-sh3 { + cell-id = ; + label = "SH3"; + qcom,bcm-name = "SH3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm3: bcm-mm3 { + cell-id = ; + label = "MM3"; + qcom,bcm-name = "MM3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh5: bcm-sh5 { + cell-id = ; + label = "SH5"; + qcom,bcm-name = "SH5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn0: bcm-sn0 { + cell-id = ; + label = "SN0"; + qcom,bcm-name = "SN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ce0: bcm-ce0 { + cell-id = ; + label = "CE0"; + qcom,bcm-name = "CE0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn0: bcm-cn0 { + cell-id = ; + label = "CN0"; + qcom,bcm-name = "CN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_qup0: bcm-qup0 { + cell-id = ; + label = "QUP0"; + qcom,bcm-name = "QUP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn2: bcm-sn2 { + cell-id = ; + label = "SN2"; + qcom,bcm-name = "SN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn4: bcm-sn4 { + cell-id = ; + label = "SN4"; + qcom,bcm-name = "SN4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn5: bcm-sn5 { + cell-id = ; + label = "SN5"; + qcom,bcm-name = "SN5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn8: bcm-sn8 { + cell-id = ; + label = "SN8"; + qcom,bcm-name = "SN8"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn10: bcm-sn10 { + cell-id = ; + label = "SN10"; + qcom,bcm-name = "SN10"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn11: bcm-sn11 { + cell-id = ; + label = "SN11"; + qcom,bcm-name = "SN11"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn13: bcm-sn13 { + cell-id = ; + label = "SN13"; + qcom,bcm-name = "SN13"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mc0_display: bcm-mc0_display { + cell-id = ; + label = "MC0_DISPLAY"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_sh0_display: bcm-sh0_display { + cell-id = ; + label = "SH0_DISPLAY"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm0_display: bcm-mm0_display { + cell-id = ; + label = "MM0_DISPLAY"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm1_display: bcm-mm1_display { + cell-id = ; + label = "MM1_DISPLAY"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm2_display: bcm-mm2_display { + cell-id = ; + label = "MM2_DISPLAY"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm3_display: bcm-mm3_display { + cell-id = ; + label = "MM3_DISPLAY"; + qcom,bcm-name = "MM3"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + /*Buses*/ + fab_aggre1_noc: fab-aggre1_noc { + cell-id = ; + label = "fab-aggre1_noc"; + qcom,fab-dev; + qcom,base-name = "aggre1_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_aggre2_noc: fab-aggre2_noc { + cell-id = ; + label = "fab-aggre2_noc"; + qcom,fab-dev; + qcom,base-name = "aggre2_noc-base"; + qcom,qos-off = <2048>; + qcom,base-offset = <12288>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_camnoc_virt: fab-camnoc_virt { + cell-id = ; + label = "fab-camnoc_virt"; + qcom,fab-dev; + qcom,base-name = "camnoc_virt-base"; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_dc_noc: fab-dc_noc { + cell-id = ; + label = "fab-dc_noc"; + qcom,fab-dev; + qcom,base-name = "dc_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gladiator_noc: fab-gladiator_noc { + cell-id = ; + label = "fab-gladiator_noc"; + qcom,fab-dev; + qcom,base-name = "gladiator_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_ipa_virt: fab-ipa_virt { + cell-id = ; + label = "fab-ipa_virt"; + qcom,fab-dev; + qcom,base-name = "ipa_virt-base"; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mc_virt: fab-mc_virt { + cell-id = ; + label = "fab-mc_virt"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mem_noc: fab-mem_noc { + cell-id = ; + label = "fab-mem_noc"; + qcom,fab-dev; + qcom,base-name = "mem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mmss_noc: fab-mmss_noc { + cell-id = ; + label = "fab-mmss_noc"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_system_noc: fab-system_noc { + cell-id = ; + label = "fab-system_noc"; + qcom,fab-dev; + qcom,base-name = "system_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mc_virt_display: fab-mc_virt_display { + cell-id = ; + label = "fab-mc_virt_display"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mem_noc_display: fab-mem_noc_display { + cell-id = ; + label = "fab-mem_noc_display"; + qcom,fab-dev; + qcom,base-name = "mem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mmss_noc_display: fab-mmss_noc_display { + cell-id = ; + label = "fab-mmss_noc_display"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + /*Masters*/ + + mas_qhm_a1noc_cfg: mas-qhm-a1noc-cfg { + cell-id = ; + label = "mas-qhm-a1noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre1_noc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_qhm_qup1: mas-qhm-qup1 { + cell-id = ; + label = "mas-qhm-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qhm_tsif: mas-qhm-tsif { + cell-id = ; + label = "mas-qhm-tsif"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_xm_emmc: mas-xm-emmc { + cell-id = ; + label = "mas-xm-emmc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_xm_sdc4: mas-xm-sdc4 { + cell-id = ; + label = "mas-xm-sdc4"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg { + cell-id = ; + label = "mas-qhm-a2noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre2_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qup2: mas-qhm-qup2 { + cell-id = ; + label = "mas-qhm-qup2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qnm_cnoc: mas-qnm-cnoc { + cell-id = ; + label = "mas-qnm-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_ce0>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <16>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <22>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-usb3-prim-axi-no-rate"; + }; + }; + + mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf0-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_hf1_uncomp: mas-qxm-camnoc-hf1-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf1-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_sf_uncomp: mas-qxm-camnoc-sf-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-sf-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qhm_spdm: mas-qhm-spdm { + cell-id = ; + label = "mas-qhm-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_cnoc_a2noc>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qhm_tic: mas-qhm-tic { + cell-id = ; + label = "mas-qhm-tic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_tlmm_south + &slv_qhs_camera_cfg &slv_qhs_sdc4 + &slv_qhs_sdc2 &slv_qhs_mnoc_cfg + &slv_qhs_ufs_mem_cfg &slv_qhs_glm + &slv_qhs_pdm &slv_qhs_a2_noc_cfg + &slv_qhs_qdss_cfg &slv_qhs_display_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc + &slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south + &slv_qhs_gpuss_cfg &slv_qhs_venus_cfg + &slv_qhs_tsif &slv_qhs_compute_dsp_cfg + &slv_qhs_aop &slv_qhs_qupv3_north + &slv_srvc_cnoc &slv_qhs_usb3_0 + &slv_qhs_ipa &slv_qhs_cpr_cx + &slv_qhs_a1_noc_cfg &slv_qhs_aoss + &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg + &slv_qhs_emmc_cfg &slv_qhs_qupv3_south + &slv_qhs_spdm &slv_qhs_crypto0_cfg + &slv_qhs_pimem_cfg &slv_qhs_tlmm_north + &slv_qhs_clk_ctl &slv_qhs_imem_cfg>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qnm_snoc: mas-qnm-snoc { + cell-id = ; + label = "mas-qnm-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_tlmm_south + &slv_qhs_camera_cfg &slv_qhs_sdc4 + &slv_qhs_sdc2 &slv_qhs_mnoc_cfg + &slv_qhs_ufs_mem_cfg &slv_qhs_glm + &slv_qhs_pdm &slv_qhs_a2_noc_cfg + &slv_qhs_qdss_cfg &slv_qhs_display_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qhs_snoc_cfg + &slv_qhs_phy_refgen_south &slv_qhs_gpuss_cfg + &slv_qhs_venus_cfg &slv_qhs_tsif + &slv_qhs_compute_dsp_cfg &slv_qhs_aop + &slv_qhs_qupv3_north &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_ipa + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_vsense_ctrl_cfg &slv_qhs_emmc_cfg + &slv_qhs_qupv3_south &slv_qhs_spdm + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_tlmm_north &slv_qhs_clk_ctl + &slv_qhs_imem_cfg>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_xm_qdss_dap: mas-xm-qdss-dap { + cell-id = ; + label = "mas-xm-qdss-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_tlmm_south + &slv_qhs_camera_cfg + &slv_qhs_sdc4 + &slv_qhs_sdc2 &slv_qhs_mnoc_cfg + &slv_qhs_ufs_mem_cfg &slv_qhs_glm + &slv_qhs_pdm &slv_qhs_a2_noc_cfg + &slv_qhs_qdss_cfg &slv_qhs_display_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc + &slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south + &slv_qhs_gpuss_cfg &slv_qhs_venus_cfg + &slv_qhs_tsif &slv_qhs_compute_dsp_cfg + &slv_qhs_aop &slv_qhs_qupv3_north + &slv_srvc_cnoc &slv_qhs_usb3_0 + &slv_qhs_ipa &slv_qhs_cpr_cx + &slv_qhs_a1_noc_cfg &slv_qhs_aoss + &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg + &slv_qhs_qupv3_south &slv_qhs_spdm + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_tlmm_north &slv_qhs_clk_ctl + &slv_qhs_imem_cfg>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qhm_cnoc: mas-qhm-cnoc { + cell-id = ; + label = "mas-qhm-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_memnoc &slv_qhs_llcc>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + mas_acm_l3: mas-acm-l3 { + cell-id = ; + label = "mas-acm-l3"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_gnoc + &slv_qns_gladiator_sodv &slv_qns_gnoc_memnoc>; + qcom,bus-dev = <&fab_gladiator_noc>; + }; + + mas_pm_gnoc_cfg: mas-pm-gnoc-cfg { + cell-id = ; + label = "mas-pm-gnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_gnoc>; + qcom,bus-dev = <&fab_gladiator_noc>; + }; + + mas_ipa_core_master: mas-ipa-core-master { + cell-id = ; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ipa_core_slave>; + qcom,bus-dev = <&fab_ipa_virt>; + }; + + mas_llcc_mc: mas-llcc-mc { + cell-id = ; + label = "mas-llcc-mc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_mc_virt>; + }; + + mas_acm_tcu: mas-acm-tcu { + cell-id = ; + label = "mas-acm-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_apps_io &slv_qns_llcc + &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <7>; + }; + + mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg { + cell-id = ; + label = "mas-qhm-memnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_memnoc + &slv_qhs_mdsp_ms_mpu_cfg>; + qcom,bus-dev = <&fab_mem_noc>; + }; + + mas_qnm_apps: mas-qnm-apps { + cell-id = ; + label = "mas-qnm-apps"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <2 3>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh5>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { + cell-id = ; + label = "mas-qnm-mnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <4 5>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { + cell-id = ; + label = "mas-qnm-mnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_apps_io + &slv_qns_llcc &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc_sf: mas-qnm-snoc-sf { + cell-id = ; + label = "mas-qnm-snoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <9>; + qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_gpu: mas-qxm-gpu { + cell-id = ; + label = "mas-qxm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <10 11>; + qcom,connections = <&slv_qns_apps_io + &slv_qns_llcc &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { + cell-id = ; + label = "mas-qhm-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + mas_qxm_camnoc_hf0: mas-qxm-camnoc-hf0 { + cell-id = ; + label = "mas-qxm-camnoc-hf0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 { + cell-id = ; + label = "mas-qxm-camnoc-hf1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { + cell-id = ; + label = "mas-qxm-camnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp1: mas-qxm-mdp1 { + cell-id = ; + label = "mas-qxm-mdp1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_rot: mas-qxm-rot { + cell-id = ; + label = "mas-qxm-rot"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus0: mas-qxm-venus0 { + cell-id = ; + label = "mas-qxm-venus0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus1: mas-qxm-venus1 { + cell-id = ; + label = "mas-qxm-venus1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus_arm9: mas-qxm-venus-arm9 { + cell-id = ; + label = "mas-qxm-venus-arm9"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { + cell-id = ; + label = "mas-qhm-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qnm_aggre1_noc: mas-qnm-aggre1-noc { + cell-id = ; + label = "mas-qnm-aggre1-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem + &slv_qns_memnoc_sf &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn8>; + }; + + mas_qnm_aggre2_noc: mas-qnm-aggre2-noc { + cell-id = ; + label = "mas-qnm-aggre2-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem + &slv_qns_memnoc_sf &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn10>; + }; + + mas_qnm_gladiator_sodv: mas-qnm-gladiator-sodv { + cell-id = ; + label = "mas-qnm-gladiator-sodv"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss + &slv_qns_cnoc &slv_xs_sys_tcu_cfg + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn11>; + }; + + mas_qnm_memnoc: mas-qnm-memnoc { + cell-id = ; + label = "mas-qnm-memnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_imem + &slv_qhs_apss &slv_qxs_pimem + &slv_qns_cnoc &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn13>; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_gic: mas-xm-gic { + cell-id = ; + label = "mas-xm-gic"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn11>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_alc: mas-alc { + cell-id = ; + label = "mas-alc"; + qcom,buswidth = <1>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_alc>; + }; + + mas_llcc_mc_display: mas-llcc-mc_display { + cell-id = ; + label = "mas-llcc-mc_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi_display>; + qcom,bus-dev = <&fab_mc_virt_display>; + }; + + mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display { + cell-id = ; + label = "mas-qnm-mnoc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <4 5>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_mem_noc_display>; + }; + + mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display { + cell-id = ; + label = "mas-qnm-mnoc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_mem_noc_display>; + }; + + mas_qxm_mdp0_display: mas-qxm-mdp0_display { + cell-id = ; + label = "mas-qxm-mdp0_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_mdp1_display: mas-qxm-mdp1_display { + cell-id = ; + label = "mas-qxm-mdp1_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_rot_display: mas-qxm-rot_display { + cell-id = ; + label = "mas-qxm-rot_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns2_mem_noc_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm3_display>; + }; + + /*Internal nodes*/ + + /*Slaves*/ + + slv_qns_a1noc_snoc:slv-qns-a1noc-snoc { + cell-id = ; + label = "slv-qns-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_aggre1_noc>; + }; + + slv_srvc_aggre1_noc:slv-srvc-aggre1-noc { + cell-id = ; + label = "slv-srvc-aggre1-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_sn8>; + }; + + slv_qns_a2noc_snoc:slv-qns-a2noc-snoc { + cell-id = ; + label = "slv-qns-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_aggre2_noc>; + }; + + slv_srvc_aggre2_noc:slv-srvc-aggre2-noc { + cell-id = ; + label = "slv-srvc-aggre2-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_sn10>; + }; + + slv_qns_camnoc_uncomp:slv-qns-camnoc-uncomp { + cell-id = ; + label = "slv-qns-camnoc-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_camnoc_virt>; + }; + + slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg { + cell-id = ; + label = "slv-qhs-a1-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a1noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_a2_noc_cfg:slv-qhs-a2-noc-cfg { + cell-id = ; + label = "slv-qhs-a2-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a2noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_aop:slv-qhs-aop { + cell-id = ; + label = "slv-qhs-aop"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_aoss:slv-qhs-aoss { + cell-id = ; + label = "slv-qhs-aoss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_cfg:slv-qhs-camera-cfg { + cell-id = ; + label = "slv-qhs-camera-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_compute_dsp_cfg:slv-qhs-compute-dsp-cfg { + cell-id = ; + label = "slv-qhs-compute-dsp-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_cx:slv-qhs-cpr-cx { + cell-id = ; + label = "slv-qhs-cpr-cx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_dcc_cfg:slv-qhs-dcc-cfg { + cell-id = ; + label = "slv-qhs-dcc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cnoc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ddrss_cfg:slv-qhs-ddrss-cfg { + cell-id = ; + label = "slv-qhs-ddrss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_cfg:slv-qhs-display-cfg { + cell-id = ; + label = "slv-qhs-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_emmc_cfg:slv-qhs-emmc-cfg { + cell-id = ; + label = "slv-qhs-emmc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_glm:slv-qhs-glm { + cell-id = ; + label = "slv-qhs-glm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg { + cell-id = ; + label = "slv-qhs-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg { + cell-id = ; + label = "slv-qhs-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_mnoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_phy_refgen_south:slv-qhs-phy-refgen-south { + cell-id = ; + label = "slv-qhs-phy-refgen-south"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qupv3_north:slv-qhs-qupv3-north { + cell-id = ; + label = "slv-qhs-qupv3-north"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qupv3_south:slv-qhs-qupv3-south { + cell-id = ; + label = "slv-qhs-qupv3-south"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc4:slv-qhs-sdc4 { + cell-id = ; + label = "slv-qhs-sdc4"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_snoc_cfg:slv-qhs-snoc-cfg { + cell-id = ; + label = "slv-qhs-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_snoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_spdm:slv-qhs-spdm { + cell-id = ; + label = "slv-qhs-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_north:slv-qhs-tlmm-north { + cell-id = ; + label = "slv-qhs-tlmm-north"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_south:slv-qhs-tlmm-south { + cell-id = ; + label = "slv-qhs-tlmm-south"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tsif:slv-qhs-tsif { + cell-id = ; + label = "slv-qhs-tsif"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg { + cell-id = ; + label = "slv-qhs-ufs-mem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_usb3_0:slv-qhs-usb3-0 { + cell-id = ; + label = "slv-qhs-usb3-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qns_cnoc_a2noc:slv-qns-cnoc-a2noc { + cell-id = ; + label = "slv-qns-cnoc-a2noc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qnm_cnoc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_llcc:slv-qhs-llcc { + cell-id = ; + label = "slv-qhs-llcc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + slv_qhs_memnoc:slv-qhs-memnoc { + cell-id = ; + label = "slv-qhs-memnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + qcom,connections = <&mas_qhm_memnoc_cfg>; + }; + + slv_qns_gladiator_sodv:slv-qns-gladiator-sodv { + cell-id = ; + label = "slv-qns-gladiator-sodv"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gladiator_noc>; + qcom,connections = <&mas_qnm_gladiator_sodv>; + }; + + slv_qns_gnoc_memnoc:slv-qns-gnoc-memnoc { + cell-id = ; + label = "slv-qns-gnoc-memnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_gladiator_noc>; + qcom,connections = <&mas_qnm_apps>; + }; + + slv_srvc_gnoc:slv-srvc-gnoc { + cell-id = ; + label = "slv-srvc-gnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gladiator_noc>; + }; + + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_ipa_virt>; + qcom,bcms = <&bcm_ip0>; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_mc0>, <&bcm_acv>; + }; + + slv_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mdsp-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + }; + + slv_qns_apps_io:slv-qns-apps-io { + cell-id = ; + label = "slv-qns-apps-io"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh1>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_qns_memnoc_snoc:slv-qns-memnoc-snoc { + cell-id = ; + label = "slv-qns-memnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,connections = <&mas_qnm_memnoc>; + qcom,bcms = <&bcm_sh2>; + }; + + slv_srvc_memnoc:slv-srvc-memnoc { + cell-id = ; + label = "slv-srvc-memnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + }; + + slv_qns2_mem_noc:slv-qns2-mem-noc { + cell-id = ; + label = "slv-qns2-mem-noc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_sf>; + qcom,bcms = <&bcm_mm2>; + }; + + slv_qns_mem_noc_hf:slv-qns-mem-noc-hf { + cell-id = ; + label = "slv-qns-mem-noc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_hf>; + qcom,bcms = <&bcm_mm0>; + }; + + slv_srvc_mnoc:slv-srvc-mnoc { + cell-id = ; + label = "slv-srvc-mnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_cnoc:slv-qns-cnoc { + cell-id = ; + label = "slv-qns-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_qns_memnoc_gc:slv-qns-memnoc-gc { + cell-id = ; + label = "slv-qns-memnoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_gc>; + qcom,bcms = <&bcm_sn2>; + }; + + slv_qns_memnoc_sf:slv-qns-memnoc-sf { + cell-id = ; + label = "slv-qns-memnoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_sf>; + qcom,bcms = <&bcm_sn0>; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn1>; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn5>; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_ebi_display:slv-ebi_display { + cell-id = ; + label = "slv-ebi_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mc_virt_display>; + qcom,bcms = <&bcm_mc0_display>; + }; + + slv_qns_llcc_display:slv-qns-llcc_display { + cell-id = ; + label = "slv-qns-llcc_display"; + qcom,buswidth = <16>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mem_noc_display>; + qcom,connections = <&mas_llcc_mc_display>; + qcom,bcms = <&bcm_sh0_display>; + }; + + slv_qns2_mem_noc_display:slv-qns2-mem-noc_display { + cell-id = ; + label = "slv-qns2-mem-noc_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_sf_display>; + qcom,bcms = <&bcm_mm2_display>; + }; + + slv_qns_mem_noc_hf_display:slv-qns-mem-noc-hf_display { + cell-id = ; + label = "slv-qns-mem-noc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_hf_display>; + qcom,bcms = <&bcm_mm0_display>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c40fff684e60877d56bab7bd903a8e0cdf1a3146 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2016-2017, 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. + */ + +&led_flash_rear { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash0 &pm660l_flash1>; + torch-source = <&pm660l_torch0 &pm660l_torch1>; + switch-source = <&pm660l_switch0>; + status = "ok"; +}; + +&led_flash_front { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash2>; + torch-source = <&pm660l_torch2>; + switch-source = <&pm660l_switch1>; + status = "ok"; +}; + +&actuator_regulator { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; +}; + +&camera_ldo { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm660_s6>; +}; + +&camera_rear_ldo { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm660_s6>; +}; + +&camera_vio_ldo { + compatible = "regulator-fixed"; + reg = <0x03 0x00>; + regulator-name = "camera_vio_ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 29 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vio>; + vin-supply = <&pm660_s4>; +}; + +&camera_vana_ldo { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "camera_vana_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vana>; + vin-supply = <&pm660l_bob>; +}; + +&actuator_rear { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; +}; + +&actuator_front { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; +}; + +&ois_rear { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; +}; + +&eeprom_rear { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; +}; + +&eeprom_rear_aux { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; +}; + +&eeprom_front { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; +}; + +&cam_cci { + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8b94ca27e0700d6080f86558e2bb9497e8bbf518 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2016-2017, 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 { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash0 &pm660l_flash1>; + torch-source = <&pm660l_torch0 &pm660l_torch1>; + switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash2>; + torch-source = <&pm660l_torch2>; + switch-source = <&pm660l_switch1>; + status = "ok"; + }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + }; + + camera_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm660_s6>; + }; + + camera_rear_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm660_s6>; + }; + + camera_vio_ldo: gpio-regulator@3 { + compatible = "regulator-fixed"; + reg = <0x03 0x00>; + regulator-name = "camera_vio_ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 29 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vio>; + vin-supply = <&pm660_s4>; + }; + + camera_vana_ldo: gpio-regulator@4 { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "camera_vana_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vana>; + vin-supply = <&pm660l_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8b94ca27e0700d6080f86558e2bb9497e8bbf518 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2016-2017, 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 { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash0 &pm660l_flash1>; + torch-source = <&pm660l_torch0 &pm660l_torch1>; + switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash2>; + torch-source = <&pm660l_torch2>; + switch-source = <&pm660l_switch1>; + status = "ok"; + }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + }; + + camera_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm660_s6>; + }; + + camera_rear_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm660_s6>; + }; + + camera_vio_ldo: gpio-regulator@3 { + compatible = "regulator-fixed"; + reg = <0x03 0x00>; + regulator-name = "camera_vio_ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 29 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vio>; + vin-supply = <&pm660_s4>; + }; + + camera_vana_ldo: gpio-regulator@4 { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "camera_vana_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vana>; + vin-supply = <&pm660l_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1352000 0>; + rgltr-max-voltage = <1800000 2850000 1352000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7ab99a3e7c9dac6079b51c761407496cb11b0527 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2017, 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 { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm660l_flash0 &pm660l_flash1>; + torch-source = <&pm660l_torch0 &pm660l_torch1>; + switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_avdd_gpio_regulator: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "cam_avdd_gpio_regulator"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&tlmm 100 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_dvdd_gpio_regulator: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "cam_dvdd_gpio_regulator"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + vin-supply = <&pm660_s6>; + }; + + cam_iovdd_gpio_regulator: gpio-regulator@3 { + compatible = "regulator-fixed"; + reg = <0x03 0x00>; + regulator-name = "cam_iovdd_gpio_regulator"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 29 0>; + vin-supply = <&pm660_s4>; + }; + + cam_rear_avdd_gpio_regulator: gpio-regulator@4 { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "cam_rear_avdd_gpio_regulator"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_rear_dvdd_gpio_regulator: gpio-regulator@5 { + compatible = "regulator-fixed"; + reg = <0x05 0x00>; + regulator-name = "cam_rear_dvdd_gpio_regulator"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + vin-supply = <&pm660_s6>; + }; +}; + +&tlmm { + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&cam_cci { + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_aux: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&cam_iovdd_gpio_regulator>; + cam_vana-supply = <&cam_rear_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&cam_iovdd_gpio_regulator>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 1800000 2850000 0 2800000>; + rgltr-max-voltage = <1200000 1800000 2850000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + 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>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&cam_iovdd_gpio_regulator>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + 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>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&cam_iovdd_gpio_regulator>; + cam_vana-supply = <&cam_rear_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&cam_iovdd_gpio_regulator>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 1800000 2850000 0>; + rgltr-max-voltage = <1200000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + 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>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + cam_vio-supply = <&cam_iovdd_gpio_regulator>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&pm660l_gpios { + gpio@c300 { /* GPIO4 -CAMERA SENSOR 1/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"; + }; + + gpio@c200 { /* GPIO3 -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"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..715affdb0ec35b996f2541b133edfad9f5d72833 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -0,0 +1,1132 @@ +/* + * Copyright (c) 2017, 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 { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm660_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm660_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm660_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_cci: qcom,cci@ac4a000 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x4000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = <0 460 0>; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CCI_CLK>, + <&clock_camcc CAM_CC_CCI_CLK_SRC>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cci_clk", + "cci_clk_src"; + src-clock-name = "cci_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 0 0 0 0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + non-fatal-fault-disabled; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1038 0x0>, + <&apps_smmu 0x1058 0x0>, + <&apps_smmu 0x1039 0x0>, + <&apps_smmu 0x1059 0x0>; + label = "lrme"; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x808 0x0>, + <&apps_smmu 0x810 0x8>, + <&apps_smmu 0xc08 0x0>, + <&apps_smmu 0xc10 0x8>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1060 0x8>, + <&apps_smmu 0x1068 0x8>; + label = "jpeg"; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x107A 0x0>, + <&apps_smmu 0x1020 0x8>, + <&apps_smmu 0x1040 0x8>, + <&apps_smmu 0x1030 0x0>, + <&apps_smmu 0x1050 0x0>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0xd800000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.3 GB */ + iova-region-name = "io"; + iova-region-start = <0xd900000>; + iova-region-len = <0xd2700000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1000 0x0>; + label = "cpas-cdm0"; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + msm_cam_smmu_fd { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1070 0x0>; + label = "fd"; + fd_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 19200000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas0"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "fd", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "gcc_camera_ahb", + "gcc_camera_axi", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = <0 464 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = <0 465 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 480000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = <0 466 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = <0 467 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 480000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <2>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = <0 468 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <2>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = <0 469 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0>, + <0 0 0 0 0 0 480000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,ipe1", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <2>; + num-bps = <1>; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_fast_ahb", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_clk", + "icp_clk_src"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <0 0 200000000 0 0 0 0 400000000>, + <0 0 200000000 0 0 0 0 600000000>; + clock-cntl-level = "svs", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x77 0x1DF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_ipe1: qcom,ipe1 { + cell-index = <1>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe1-vdd"; + ipe1-vdd-supply = <&ipe_1_gdsc>; + clock-names = "ipe_1_ahb_clk", + "ipe_1_areg_clk", + "ipe_1_axi_clk", + "ipe_1_clk", + "ipe_1_clk_src"; + src-clock-name = "ipe_1_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_1_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_1_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = <0 0 0 0 200000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 600000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + status = "ok"; + }; + + cam_fd: qcom,fd@ac5a000 { + cell-index = <0>; + compatible = "qcom,fd41"; + reg-names = "fd_core", "fd_wrapper"; + reg = <0xac5a000 0x1000>, + <0xac5b000 0x400>; + reg-cam-base = <0x5a000 0x5b000>; + interrupt-names = "fd"; + interrupts = <0 462 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "fd_core_clk_src", + "fd_core_clk", + "fd_core_uar_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_FD_CORE_CLK_SRC>, + <&clock_camcc CAM_CC_FD_CORE_CLK>, + <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; + src-clock-name = "fd_core_clk_src"; + clock-cntl-level = "svs", "svs_l1", "turbo"; + clock-rates = + <0 0 0 0 0 400000000 0 0>, + <0 0 0 0 0 538000000 0 0>, + <0 0 0 0 0 600000000 0 0>; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 200000000 200000000>, + <0 0 0 0 0 269000000 269000000>, + <0 0 0 0 0 320000000 320000000>, + <0 0 0 0 0 400000000 400000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..2b5ed1a2396c83726a9e9bd0d1ba870bfd502140 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..5a1b945a21fd23526987440322db1a4e9e0c9653 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bd88087d94fec230c20235d1d893cd9e9ddf6e2d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi @@ -0,0 +1,310 @@ +/* Copyright (c) 2017, 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 +#include "sdm670-pmic-overlay.dtsi" +#include "sdm670-sde-display.dtsi" +#include "sdm670-camera-sensor-cdp.dtsi" + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&pm660l_l1>; /* 0.88v */ + vdda-pll-supply = <&pm660_l1>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vcc-voltage-level = <2960000 2960000>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm660_l1>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&pm660l_switch1 { + pinctrl-names = "led_enable", "led_disable"; + pinctrl-0 = <&flash_led3_front_en>; + pinctrl-1 = <&flash_led3_front_dis>; +}; + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&qupv3_se8_spi { + status = "disabled"; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 44 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 43 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <44 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; +}; + +&qupv3_se10_i2c { + status = "disabled"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 96 0x1>; + + status = "ok"; +}; + +&pm660_charger { + qcom,batteryless-platform; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_cam_snapshot_default + &key_cam_focus_default + &key_vol_up_default>; + + cam_snapshot { + label = "cam_snapshot"; + gpios = <&tlmm 91 0>; + linux,input-type = <1>; + linux,code = <766>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + cam_focus { + label = "cam_focus"; + gpios = <&tlmm 92 0>; + linux,input-type = <1>; + linux,code = <528>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&dsi_dual_nt35597_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_dual_nt35597_truly_video_display { + qcom,dsi-display-active; +}; + +&pm660l_wled { + status = "okay"; + qcom,led-strings-list = [01 02]; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6dc5c2c705e4ca2641164f636fdcf7fd4129f0dc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi @@ -0,0 +1,2432 @@ +/* Copyright (c) 2017-2018, 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 { + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + arm,buffer-size = <0x400000>; + arm,sg-enable; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti8>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + replicator_swao: replicator@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6b0a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_replicator_swao>; + }; + }; + }; + }; + + tmc_etf_swao: tmc@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6b09000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + }; + + funnel_swao:funnel@0x6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b08000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <6>; + funnel_swao_in_sensor_etm0: endpoint { + slave-mode; + remote-endpoint= + <&sensor_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <7>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b01000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + }; + }; + }; + + tpdm_swao0: tpdm@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6b02000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b03000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0 &cti8>; + arm,default-sink; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator: endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <1>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + + port@3 { + reg = <2>; + funnel_merg_in_funnel_in2: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in2_out_funnel_merg>; + }; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + hwevent: hwevent@0x014066f0 { + compatible = "qcom,coresight-hwevent"; + reg = <0x14066f0 0x4>, + <0x14166f0 0x4>, + <0x1406038 0x4>, + <0x1416038 0x4>; + reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl", + "ddr-ch23-ctrl"; + + coresight-name = "coresight-hwevent"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + + qcom,blk-size = <1>; + }; + + funnel_in0: funnel@0x6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_in1: funnel@0x6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <0>; + funnel_in1_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_in1>; + }; + }; + }; + }; + + funnel_in2: funnel@0x6043000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6043000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in2_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in2>; + }; + }; + + port@1 { + reg = <0>; + funnel_in2_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in2>; + }; + + }; + + port@2 { + reg = <1>; + funnel_in2_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_funnel_in2>; + }; + }; + port@3 { + reg = <2>; + funnel_in2_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_in2>; + }; + }; + port@4 { + reg = <5>; + funnel_in2_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in2>; + }; + }; + port@5 { + reg = <6>; + funnel_in2_in_funnel_gfx: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gfx_out_funnel_in2>; + }; + }; + }; + }; + + funnel_gfx: funnel@0x6943000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6943000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_gfx>; + }; + }; + + port@1 { + reg = <0>; + funnel_in2_in_gfx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_out_funnel_in2>; + }; + }; + + port@2 { + reg = <1>; + funnel_in2_in_gfx_cx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_cx_out_funnel_in2>; + }; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <9 64>, + <13 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + + }; + + port@1 { + reg = <0>; + tpda_in_tpdm_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_center_out_tpda>; + }; + }; + + port@2 { + reg = <2>; + tpda_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_tpda>; + }; + }; + + port@3 { + reg = <3>; + tpda_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_tpda>; + }; + }; + + port@4 { + reg = <6>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + port@5 { + reg = <7>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@6 { + reg = <9>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@7 { + reg = <11>; + tpda_in_tpdm_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_north_out_tpda>; + }; + }; + + port@8 { + reg = <12>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + + port@9 { + reg = <13>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + }; + }; + + funnel_modem: funnel@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6832000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_out_funnel_modem>; + }; + }; + }; + }; + + tpda_modem: tpda@6831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6831000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_modem_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_modem_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + qcom,msr-fix-req; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_center>; + }; + }; + }; + + tpdm_north: tpdm@6a24000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6a24000 0x1000>; + reg-names = "tpdm-base"; + + qcom,msr-fix-req; + + coresight-name = "coresight-tpdm-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_north_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_north>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_qm>; + }; + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + + funnel_dl_mm: funnel@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6c0b000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_mm_in_tpdm_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_mm: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c08000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mm"; + + qcom,msr-fix-req; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_mm_out_funnel_dl_mm: endpoint { + remote-endpoint = <&funnel_dl_mm_in_tpdm_mm>; + }; + }; + }; + + funnel_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + funnel_turing_1: funnel_1@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867000 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-turing-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing_1>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 0x1000>; + reg-names = "tpdm-base"; + + qcom,msr-fix-req; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + funnel_ddr_0: funnel@69e2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x69e2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ddr_0_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@69e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69e0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + qcom,msr-fix-req; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <7>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; + }; + }; + + cti0_ddr0: cti@69e1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e1000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@69e4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@69e5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_wcss: cti@69a4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti0"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_wcss: cti@69a5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti1"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_wcss: cti@69a6000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a6000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti2"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@683b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x683b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing: cti@6867000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6867000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ssc_sdc: cti@6b10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_sdc_cti2"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ssc: cti@6b11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_cti1"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ssc_q6: cti@6b1b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b1b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_q6_cti0"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ssc_noc: cti@6b1e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b1e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_noc"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti6_ssc_noc: cti@6b1f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b1f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_noc_cti6"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao: cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao: cti@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b05000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao: cti@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b06000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao: cti@6b07000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b07000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-aop-m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_titan: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-titan"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_venus_arm9: cti@6c20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-venus-arm9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti_cpu0: cti@7020000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7020000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti_cpu1: cti@7120000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7120000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@7220000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7220000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@7320000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7320000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu4: cti@7420000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7420000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@7520000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7520000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@7620000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7620000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@7720000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7720000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_modem_etm0>; + }; + }; + }; + + sensor_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-sensor-etm0"; + qcom,inst-id = <8>; + + port { + sensor_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_sensor_etm0>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_audio_etm0>; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <4>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + port@4 { + reg = <5>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + port@5 { + reg = <6>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + coresight-name = "coresight-etm2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + coresight-name = "coresight-etm3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + coresight-name = "coresight-etm4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + coresight-name = "coresight-etm5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + coresight-name = "coresight-etm6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + coresight-name = "coresight-etm7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x6b0c000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-ext-cdc-usbc-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ext-cdc-usbc-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cd113b331428daacd855547a3ed5ef8a7fab57e5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-ext-cdc-usbc-audio.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2017, 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. + */ + +&tavil_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-ext-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ext-codec-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..14a3e93864a3615e786bdcead7b44cfa49c34662 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-ext-codec-audio-overlay.dtsi @@ -0,0 +1,84 @@ +/* Copyright (c) 2017, 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 "sdm670-audio-overlay.dtsi" + +&pmic_analog_codec { + status = "disabled"; +}; + +&msm_sdw_codec { + status = "disabled"; +}; + +&cdc_pdm_gpios { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&cdc_dmic_gpios { + status = "disabled"; +}; + +&cdc_sdw_gpios { + status = "disabled"; +}; + +&wsa_spkr_en1 { + status = "disabled"; +}; + +&wsa_spkr_en2 { + status = "disabled"; +}; + +&qupv3_se8_spi { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&wdsp_mgr { + status = "okay"; +}; + +&wdsp_glink { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd934x_cdc { + status = "okay"; +}; + +&clock_audio_lnbb { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5eb79194381099538dba75cb54f2a43b48f07711 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts @@ -0,0 +1,37 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,us-euro-gpios = <&tavil_us_euro_sw>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..88beca95bc96d99866aa8f055f3c2746aa24fe05 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,us-euro-gpios = <&tavil_us_euro_sw>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..970209cac8360ab3969f70a181c6f4c07f124530 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..87ac1908860e0e05f4f21ebe577eb816a40f887d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..2aa8512eaf321d26bbf70bf57b3659253b3b1529 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts @@ -0,0 +1,38 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,us-euro-gpios = <&tavil_us_euro_sw>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..43198bbd896918307035c82f8f12a7088e9af10f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,us-euro-gpios = <&tavil_us_euro_sw>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..8715ddc7a3060d37373487ce926e3c01e95094c0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..0beaddb36806d54497135ae1c249c8542bd15d38 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..dbcc6bd733624bc12908be5b0610ebbff8b0cd34 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi @@ -0,0 +1,29 @@ +/* Copyright (c) 2017, 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 "sdm670-ext-codec-audio-overlay.dtsi" + +&int_codec { + status = "disabled"; +}; + +&tavil_snd { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..75a27624b8b41e1d127686f4644267a1779d9980 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi @@ -0,0 +1,553 @@ +/* Copyright (c) 2017-2018, 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 { + + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a615_zap"; + memory-region = <&pil_gpu_mem>; + }; + + msm_bus: qcom,kgsl-busmon{ + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + qcom,bw-tbl = + < 0 /* off */ >, + < 381 /* 100 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1720 /* 451 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 3147 /* 825 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 5161 /* 1353 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; + }; + + msm_gpu: qcom,kgsl-3d0@5000000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x5000000 0x40000>, + <0x5061000 0x800>, + <0x780000 0x6300>; + reg-names = "kgsl_3d0_reg_memory", + "kgsl_3d0_cx_dbgc_memory", + "qfprom_memory"; + interrupts = <0 300 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x06010500>; + + qcom,initial-pwrlevel = <3>; + + qcom,gpu-quirk-hfi-use-reg; + qcom,gpu-quirk-limit-uche-gbif-rw; + + /* */ + qcom,idle-timeout = <80>; + qcom,no-nap; + + qcom,highest-bank-bit = <14>; + + qcom,min-access-length = <32>; + + qcom,ubwc-mode = <2>; + + /* size in bytes */ + qcom,snapshot-size = <1048576>; + + /* base addr, size */ + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; + #cooling-cells = <2>; + + clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>; + + clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 800000>, /* 2 bus=200 */ + <26 512 0 1200000>, /* 3 bus=300 */ + <26 512 0 1804000>, /* 4 bus=451 */ + <26 512 0 2188000>, /* 5 bus=547 */ + <26 512 0 2724000>, /* 6 bus=681 */ + <26 512 0 3300000>, /* 7 bus=825 */ + <26 512 0 4068000>, /* 8 bus=1017 */ + <26 512 0 5412000>, /* 9 bus=1353 */ + <26 512 0 6220000>, /* 10 bus=1555 */ + <26 512 0 7216000>; /* 11 bus=1804 */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* GPU related llc slices */ + cache-slice-names = "gpu", "gpuhtw"; + cache-slices = <&llcc 12>, <&llcc 11>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <899>; + qcom,pm-qos-wakeup-latency = <899>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <1>; + + qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>; + + qcom,gpu-coresights { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-coresight"; + + status = "disabled"; + + qcom,gpu-coresight@0 { + reg = <0>; + coresight-name = "coresight-gfx"; + coresight-atid = <50>; + port { + gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_gfx>; + }; + }; + }; + + qcom,gpu-coresight@1 { + reg = <1>; + coresight-name = "coresight-gfx-cx"; + coresight-atid = <51>; + port { + gfx_cx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_gfx_cx>; + }; + }; + }; + }; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calulated as FMAX/4.8 MHz round up to zero + * decimal places. + */ + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <8>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <90>; + + qcom,initial-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <8>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <146>; + + qcom,initial-pwrlevel = <6>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <8>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <163>; + + qcom,initial-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <267000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <4>; + qcom,bus-max = <8>; + }; + + /* MIN SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <180000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <4>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + }; + + }; + + kgsl_msm_iommu: qcom,kgsl-iommu { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x05040000 0x10000>; + qcom,protect = <0x40000 0x10000>; + qcom,micro-mmu-control = <0x6000>; + + clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + + clock-names = "iface_clk", "mem_clk", "mem_iface_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,gpu-offset = <0x48000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>; + }; + }; + + gmu: qcom,gmu { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = + <0x506a000 0x31000>, + <0xb200000 0x300000>; + reg-names = + "kgsl_gmu_reg", + "kgsl_gmu_pdc_reg"; + + interrupts = <0 304 0>, <0 305 0>; + interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq"; + + qcom,msm-bus,name = "cnoc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 10036 0 0>, /* CNOC off */ + <26 10036 0 100>; /* CNOC on */ + + regulator-names = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + + clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + + clock-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk"; + + qcom,gmu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gmu-pwrlevels"; + + qcom,gmu-pwrlevel@0 { + reg = <0>; + qcom,gmu-freq = <0>; + }; + + qcom,gmu-pwrlevel@1 { + reg = <1>; + qcom,gmu-freq = <200000000>; + }; + }; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 4>; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 5>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-int-cdc-usbc-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-int-cdc-usbc-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..22e9a7aaf4dfb5b37f3d486f6b0526080cc4faee --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-int-cdc-usbc-audio-overlay.dtsi @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sdm670-audio-overlay.dtsi" + +&int_codec { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2-gpio = <&tlmm 40 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en2_active>; + pinctrl-1 = <&wcd_usbc_analog_en2_idle>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3fd122901f914337695d5a46c31c43593c16217b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi @@ -0,0 +1,53 @@ +/* Copyright (c) 2017-2018, 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 { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@13 { /* SPSS HEAP */ + reg = <13>; + memory-region = <&sp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..948c51d8761cc5b1899aea6793c9793987caf431 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi @@ -0,0 +1,312 @@ +/* Copyright (c) 2017-2018, 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 { + lpi_tlmm: lpi_pinctrl@62b40000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0x62b40000 0x0>; + qcom,num-gpios = <32>; + gpio-controller; + #gpio-cells = <2>; + + lpi_mclk0_active: lpi_mclk0_active { + mux { + pins = "gpio19"; + function = "func1"; + }; + + config { + pins = "gpio19"; + drive-strength = <8>; + bias-disable; + output-low; + }; + }; + + lpi_mclk0_sleep: lpi_mclk0_sleep { + mux { + pins = "gpio19"; + function = "func1"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + bias-pull-down; + }; + }; + + cdc_pdm_clk_active: cdc_pdm_clk_active { + mux { + pins = "gpio18"; + function = "func2"; + }; + + config { + pins = "gpio18"; + drive-strength = <4>; + output-low; + }; + }; + + cdc_pdm_clk_sleep: cdc_pdm_clk_sleep { + mux { + pins = "gpio18"; + function = "func2"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_pdm_sync_active: cdc_pdm_sync_active { + mux { + pins = "gpio19"; + function = "func3"; + }; + + config { + pins = "gpio19"; + drive-strength = <4>; + output-low; + }; + }; + + cdc_pdm_sync_sleep: cdc_pdm_sync_sleep { + mux { + pins = "gpio19"; + function = "func3"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_pdm_rx0_active: cdc_pdm_rx0_active { + mux { + pins = "gpio21"; + function = "func2"; + }; + + config { + pins = "gpio21"; + drive-strength = <4>; + output-low; + }; + }; + + cdc_pdm_rx0_sleep: cdc_pdm_rx0_sleep { + mux { + pins = "gpio21"; + function = "func2"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_pdm_rx1_2_active: cdc_pdm_rx1_2_active { + mux { + pins = "gpio23", "gpio25"; + function = "func1"; + }; + + config { + pins = "gpio23", "gpio25"; + drive-strength = <4>; + output-low; + }; + }; + + cdc_pdm_rx1_2_sleep: cdc_pdm_rx1_2_sleep { + mux { + pins = "gpio23", "gpio25"; + function = "func1"; + }; + + config { + pins = "gpio23", "gpio25"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_pdm_2_gpios_active: cdc_pdm_2_gpios_active { + mux { + pins = "gpio20"; + function = "func2"; + }; + + config { + pins = "gpio20"; + drive-strength = <8>; + }; + }; + + cdc_pdm_2_gpios_sleep: cdc_pdm_2_gpios_sleep { + mux { + pins = "gpio20"; + function = "func2"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + cdc_rx0_comp_active: cdc_pdm_rx0_comp_active { + mux { + pins = "gpio22"; + function = "func2"; + }; + + config { + pins = "gpio22"; + drive-strength = <4>; + }; + }; + + cdc_rx0_comp_sleep: cdc_pdm_rx0_comp_sleep { + mux { + pins = "gpio22"; + function = "func2"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-disable; + }; + }; + + cdc_rx1_comp_active: cdc_pdm_rx1_comp_active { + mux { + pins = "gpio24"; + function = "func1"; + }; + + config { + pins = "gpio24"; + drive-strength = <4>; + }; + }; + + cdc_rx1_comp_sleep: cdc_pdm_rx1_comp_sleep { + mux { + pins = "gpio24"; + function = "func1"; + }; + + config { + pins = "gpio24"; + drive-strength = <2>; + bias-disable; + }; + }; + + lpi_cdc_reset_active: lpi_cdc_reset_active { + mux { + pins = "gpio29"; + function = "func2"; + }; + config { + pins = "gpio29"; + drive-strength = <16>; + output-high; + }; + }; + + lpi_cdc_reset_sleep: lpi_cdc_reset_sleep { + mux { + pins = "gpio29"; + function = "func2"; + }; + + config { + pins = "gpio29"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + cdc_dmic12_gpios_active: dmic12_gpios_active { + mux { + pins = "gpio26", "gpio28"; + function = "func1"; + }; + + config { + pins = "gpio26", "gpio28"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic12_gpios_sleep: dmic12_gpios_sleep { + mux { + pins = "gpio26", "gpio28"; + function = "func1"; + }; + + config { + pins = "gpio26", "gpio28"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic34_gpios_active: dmic34_gpios_active { + mux { + pins = "gpio27", "gpio29"; + function = "func1"; + }; + + config { + pins = "gpio27", "gpio29"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic34_gpios_sleep: dmic34_gpios_sleep { + mux { + pins = "gpio27", "gpio29"; + function = "func1"; + }; + + config { + pins = "gpio27", "gpio29"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ac254fd8e816a4c79388fe58395e1cc37ba70061 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..1241a20aa435088a42b65f13d081465499cb8140 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..de9e40e3661bda76d07582b8ce2162955125de17 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi @@ -0,0 +1,377 @@ +/* Copyright (c) 2017, 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 +#include "sdm670-pmic-overlay.dtsi" +#include "sdm670-sde-display.dtsi" +#include "sdm670-camera-sensor-mtp.dtsi" +#include "smb1355.dtsi" + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&pm660l_l1>; /* 0.88v */ + vdda-pll-supply = <&pm660_l1>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vcc-voltage-level = <2960000 2960000>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm660_l1>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&pm660l_switch1 { + pinctrl-names = "led_enable", "led_disable"; + pinctrl-0 = <&flash_led3_front_en>; + pinctrl-1 = <&flash_led3_front_dis>; +}; + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&qupv3_se8_spi { + status = "disabled"; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 44 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 43 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <44 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; +}; + +&qupv3_se10_i2c { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 96 0x1>; + + status = "ok"; +}; + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen3-batterydata-itech-3000mah.dtsi" + #include "fg-gen3-batterydata-ascent-3450mah.dtsi" + #include "fg-gen3-batterydata-demo-6000mah.dtsi" + }; +}; + +&pm660_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&tlmm { + smb_int_default: smb_int_default { + mux { + pins = "gpio54"; + function = "gpio"; + }; + config { + pins = "gpio54"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; +}; + +&smb1355_0 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default + &smb_shutdown_default>; + interrupt-parent = <&tlmm>; + interrupts = <54 IRQ_TYPE_LEVEL_LOW>; + smb1355_charger_0: qcom,smb1355-charger@1000 { + io-channels = <&pm660_rradc 2>, + <&pm660_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + status ="ok"; + }; +}; + +&smb1355_1 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default + &smb_shutdown_default>; + interrupt-parent = <&tlmm>; + interrupts = <54 IRQ_TYPE_LEVEL_LOW>; + smb1355_charger_1: qcom,smb1355-charger@1000 { + io-channels = <&pm660_rradc 2>, + <&pm660_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + status ="ok"; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_cam_snapshot_default + &key_cam_focus_default + &key_vol_up_default>; + + cam_snapshot { + label = "cam_snapshot"; + gpios = <&tlmm 91 0>; + linux,input-type = <1>; + linux,code = <766>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + cam_focus { + label = "cam_focus"; + gpios = <&tlmm 92 0>; + linux,input-type = <1>; + linux,code = <528>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&dsi_dual_nt35597_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_dual_nt35597_truly_video_display { + qcom,dsi-display-active; +}; + +&pm660l_wled { + status = "okay"; + qcom,led-strings-list = [01 02]; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&thermal_zones { + xo-therm-cpu-step { + status = "disabled"; + }; + xo-therm-mdm-step { + status = "disabled"; + }; + xo-therm-batt-step { + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5684e19e0be2b636c7487adac8f90d5bf4d42373 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi @@ -0,0 +1,2134 @@ +/* Copyright (c) 2017-2018, 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 { + compatible = "qcom,sdm670-pinctrl"; + reg = <0x03400000 0xc00000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&pdc>; + + /* QUPv3 South SE mappings */ + /* SE 0 pin mappings */ + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 1 pin mappings */ + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio17", "gpio18"; + function = "qup1"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio17", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + function = "qup1"; + }; + + config { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 2 pin mappings */ + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio27", "gpio28"; + function = "qup2"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio27", "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + function = "qup2"; + }; + + config { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 3 pin mappings */ + qupv3_se3_i2c_pins: qupv3_se3_i2c_pins { + qupv3_se3_i2c_active: qupv3_se3_i2c_active { + mux { + pins = "gpio41", "gpio42"; + function = "qup3"; + }; + + config { + pins = "gpio41", "gpio42"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep { + mux { + pins = "gpio41", "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio41", "gpio42"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se3_spi_pins: qupv3_se3_spi_pins { + qupv3_se3_spi_active: qupv3_se3_spi_active { + mux { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + function = "qup3"; + }; + + config { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se3_spi_sleep: qupv3_se3_spi_sleep { + mux { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 4 pin mappings */ + qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { + qupv3_se4_i2c_active: qupv3_se4_i2c_active { + mux { + pins = "gpio89", "gpio90"; + function = "qup4"; + }; + + config { + pins = "gpio89", "gpio90"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep { + mux { + pins = "gpio89", "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio89", "gpio90"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se4_spi_pins: qupv3_se4_spi_pins { + qupv3_se4_spi_active: qupv3_se4_spi_active { + mux { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + function = "qup4"; + }; + + config { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se4_spi_sleep: qupv3_se4_spi_sleep { + mux { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 5 pin mappings */ + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio85", "gpio86"; + function = "qup5"; + }; + + config { + pins = "gpio85", "gpio86"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio85", "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio85", "gpio86"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + function = "qup5"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 6 pin mappings */ + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio45", "gpio46"; + function = "qup6"; + }; + + config { + pins = "gpio45", "gpio46"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio45", "gpio46"; + function = "gpio"; + }; + + config { + pins = "gpio45", "gpio46"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se6_4uart_pins: qupv3_se6_4uart_pins { + qupv3_se6_ctsrx: qupv3_se6_ctsrx { + mux { + pins = "gpio45", "gpio48"; + function = "qup6"; + }; + + config { + pins = "gpio45", "gpio48"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + qupv3_se6_rts: qupv3_se6_rts { + mux { + pins = "gpio46"; + function = "qup6"; + }; + + config { + pins = "gpio46"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se6_tx: qupv3_se6_tx { + mux { + pins = "gpio47"; + function = "qup6"; + }; + + config { + pins = "gpio47"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + function = "qup6"; + }; + + config { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 7 pin mappings */ + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio93", "gpio94"; + function = "qup7"; + }; + + config { + pins = "gpio93", "gpio94"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio93", "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio93", "gpio94"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se7_4uart_pins: qupv3_se7_4uart_pins { + qupv3_se7_4uart_active: qupv3_se7_4uart_active { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "qup7"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_4uart_sleep: qupv3_se7_4uart_sleep { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se7_spi_pins: qupv3_se7_spi_pins { + qupv3_se7_spi_active: qupv3_se7_spi_active { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "qup7"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se7_spi_sleep: qupv3_se7_spi_sleep { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* QUPv3 North instances */ + /* SE 8 pin mappings */ + qupv3_se8_i2c_pins: qupv3_se8_i2c_pins { + qupv3_se8_i2c_active: qupv3_se8_i2c_active { + mux { + pins = "gpio65", "gpio66"; + function = "qup8"; + }; + + config { + pins = "gpio65", "gpio66"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep { + mux { + pins = "gpio65", "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio66"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se8_spi_pins: qupv3_se8_spi_pins { + qupv3_se8_spi_active: qupv3_se8_spi_active { + mux { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + function = "qup8"; + }; + + config { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se8_spi_sleep: qupv3_se8_spi_sleep { + mux { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 9 pin mappings */ + qupv3_se9_i2c_pins: qupv3_se9_i2c_pins { + qupv3_se9_i2c_active: qupv3_se9_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup9"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se9_2uart_pins: qupv3_se9_2uart_pins { + qupv3_se9_2uart_active: qupv3_se9_2uart_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup9"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_2uart_sleep: qupv3_se9_2uart_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se9_spi_pins: qupv3_se9_spi_pins { + qupv3_se9_spi_active: qupv3_se9_spi_active { + mux { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + function = "qup9"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se9_spi_sleep: qupv3_se9_spi_sleep { + mux { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 10 pin mappings */ + qupv3_se10_i2c_pins: qupv3_se10_i2c_pins { + qupv3_se10_i2c_active: qupv3_se10_i2c_active { + mux { + pins = "gpio55", "gpio56"; + function = "qup10"; + }; + + config { + pins = "gpio55", "gpio56"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep { + mux { + pins = "gpio55", "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio55", "gpio56"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se10_2uart_pins: qupv3_se10_2uart_pins { + qupv3_se10_2uart_active: qupv3_se10_2uart_active { + mux { + pins = "gpio53", "gpio54"; + function = "qup10"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_2uart_sleep: qupv3_se10_2uart_sleep { + mux { + pins = "gpio53", "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se10_spi_pins: qupv3_se10_spi_pins { + qupv3_se10_spi_active: qupv3_se10_spi_active { + mux { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + function = "qup10"; + }; + + config { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se10_spi_sleep: qupv3_se10_spi_sleep { + mux { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 11 pin mappings */ + qupv3_se11_i2c_pins: qupv3_se11_i2c_pins { + qupv3_se11_i2c_active: qupv3_se11_i2c_active { + mux { + pins = "gpio31", "gpio32"; + function = "qup11"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep { + mux { + pins = "gpio31", "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se11_spi_pins: qupv3_se11_spi_pins { + qupv3_se11_spi_active: qupv3_se11_spi_active { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "qup11"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se11_spi_sleep: qupv3_se11_spi_sleep { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 12 pin mappings */ + qupv3_se12_i2c_pins: qupv3_se12_i2c_pins { + qupv3_se12_i2c_active: qupv3_se12_i2c_active { + mux { + pins = "gpio49", "gpio50"; + function = "qup12"; + }; + + config { + pins = "gpio49", "gpio50"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se12_i2c_sleep: qupv3_se12_i2c_sleep { + mux { + pins = "gpio49", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio49", "gpio50"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se12_2uart_pins: qupv3_se12_2uart_pins { + qupv3_se12_2uart_active: qupv3_se12_2uart_active { + mux { + pins = "gpio51", "gpio52"; + function = "qup12"; + }; + + config { + pins = "gpio51", "gpio52"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se12_2uart_sleep: qupv3_se12_2uart_sleep { + mux { + pins = "gpio51", "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio51", "gpio52"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se12_spi_pins: qupv3_se12_spi_pins { + qupv3_se12_spi_active: qupv3_se12_spi_active { + mux { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + function = "qup12"; + }; + + config { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se12_spi_sleep: qupv3_se12_spi_sleep { + mux { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 13 pin mappings */ + qupv3_se13_i2c_pins: qupv3_se13_i2c_pins { + qupv3_se13_i2c_active: qupv3_se13_i2c_active { + mux { + pins = "gpio105", "gpio106"; + function = "qup13"; + }; + + config { + pins = "gpio105", "gpio106"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se13_i2c_sleep: qupv3_se13_i2c_sleep { + mux { + pins = "gpio105", "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio105", "gpio106"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se13_spi_pins: qupv3_se13_spi_pins { + qupv3_se13_spi_active: qupv3_se13_spi_active { + mux { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + function = "qup13"; + }; + + config { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se13_spi_sleep: qupv3_se13_spi_sleep { + mux { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + function = "gpio"; + }; + + config { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 14 pin mappings */ + qupv3_se14_i2c_pins: qupv3_se14_i2c_pins { + qupv3_se14_i2c_active: qupv3_se14_i2c_active { + mux { + pins = "gpio33", "gpio34"; + function = "qup14"; + }; + + config { + pins = "gpio33", "gpio34"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se14_i2c_sleep: qupv3_se14_i2c_sleep { + mux { + pins = "gpio33", "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio33", "gpio34"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se14_spi_pins: qupv3_se14_spi_pins { + qupv3_se14_spi_active: qupv3_se14_spi_active { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "qup14"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se14_spi_sleep: qupv3_se14_spi_sleep { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 15 pin mappings */ + qupv3_se15_i2c_pins: qupv3_se15_i2c_pins { + qupv3_se15_i2c_active: qupv3_se15_i2c_active { + mux { + pins = "gpio81", "gpio82"; + function = "qup15"; + }; + + config { + pins = "gpio81", "gpio82"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se15_i2c_sleep: qupv3_se15_i2c_sleep { + mux { + pins = "gpio81", "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio81", "gpio82"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se15_spi_pins: qupv3_se15_spi_pins { + qupv3_se15_spi_active: qupv3_se15_spi_active { + mux { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + function = "qup15"; + }; + + config { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se15_spi_sleep: qupv3_se15_spi_sleep { + mux { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio96"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio96"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* USB C analog configuration */ + wcd_usbc_analog_en1 { + wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle { + mux { + pins = "gpio49"; + function = "gpio"; + }; + + config { + pins = "gpio49"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active { + mux { + pins = "gpio49"; + function = "gpio"; + }; + + config { + pins = "gpio49"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + sdw_clk_pin { + sdw_clk_sleep: sdw_clk_sleep { + mux { + pins = "gpio65"; + function = "wsa_clk"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-bus-hold; + }; + }; + + sdw_clk_active: sdw_clk_active { + mux { + pins = "gpio65"; + function = "wsa_clk"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-bus-hold; + }; + }; + }; + + sdw_data_pin { + sdw_data_sleep: sdw_data_sleep { + mux { + pins = "gpio66"; + function = "wsa_data"; + }; + + config { + pins = "gpio66"; + drive-strength = <4>; + bias-bus-hold; + }; + }; + + sdw_data_active: sdw_data_active { + mux { + pins = "gpio66"; + function = "wsa_data"; + }; + + config { + pins = "gpio66"; + drive-strength = <4>; + bias-bus-hold; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 44 NFC Read Interrupt */ + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 44 NFC Read Interrupt */ + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 12: NFC ENABLE 43: FW DNLD */ + /* 116: ESE Enable */ + pins = "gpio12", "gpio43", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio43", "gpio116"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 12: NFC ENABLE 43: FW DNLD */ + /* 116: ESE Enable */ + pins = "gpio12", "gpio43", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio43", "gpio116"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + /* WSA speaker reset pins */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + /* Tasha WSA speaker reset pins */ + tasha_spkr_1_sd_n { + tasha_spkr_1_sd_n_sleep: tasha_spkr_1_sd_n_sleep { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + tasha_spkr_1_sd_n_active: tasha_spkr_1_sd_n_active { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + tasha_spkr_2_sd_n { + tasha_spkr_2_sd_n_sleep: tasha_spkr_2_sd_n_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + tasha_spkr_2_sd_n_active: tasha_spkr_2_sd_n_active { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + wcd_buck_vsel { + wcd_buck_vsel_default: wcd_buck_vsel_default{ + mux { + pins = "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio94"; + drive-strength = <8>; /* 8 mA */ + bias-pull-down; /* pull down */ + output-high; + }; + }; + }; + + wcd_usbc_analog_en2 { + wcd_usbc_analog_en2_idle: wcd_usbc_ana_en2_idle { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en2_active: wcd_usbc_ana_en2_active { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + wcd9xxx_intr { + wcd_intr_default: wcd_intr_default{ + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-enable; + }; + }; + }; + + flash_led3_front { + flash_led3_front_en: flash_led3_front_en { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_front_dis: flash_led3_front_dis { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; + + /* Pinctrl setting for CAMERA GPIO key */ + key_cam_snapshot { + key_cam_snapshot_default: key_cam_snapshot_default { + pins = "gpio91"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + key_cam_focus { + key_cam_focus_default: key_cam_focus_default { + pins = "gpio92"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio75", "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio75", "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + sde_dp_aux_active: sde_dp_aux_active { + mux { + pins = "gpio40", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio40", "gpio50"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; + }; + + sde_dp_aux_suspend: sde_dp_aux_suspend { + mux { + pins = "gpio40", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio40", "gpio50"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + bias-disable; + drive-strength = <16>; + }; + }; + + sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_suspend { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio17","gpio18"; + function = "cci_i2c"; + }; + + config { + pins = "gpio17","gpio18"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio17","gpio18"; + function = "cci_i2c"; + }; + + config { + pins = "gpio17","gpio18"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio19","gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19","gpio20"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio19","gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19","gpio20"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear_vana: cam_sensor_rear_vana { + /* AVDD LDO */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_vio: cam_sensor_rear_vio { + /* DOVDD LDO */ + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + nx30p6093_intr_default: nx30p6093_intr_default { + mux { + pins = "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio5"; + bias-disable; + input-enable; + }; + }; + }; +}; + +&pm660_gpios { + tasha_mclk { + tasha_mclk_default: tasha_mclk_default{ + pins = "gpio3"; + function = "func1"; + qcom,drive-strength = <2>; + power-source = <0>; + bias-disable; + output-low; + }; + }; +}; + +&pm660l_gpios { + camera_rear_dvdd_en { + camera_rear_dvdd_en_default: camera_rear_dvdd_en_default { + pins = "gpio4"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; + + camera_dvdd_en { + camera_dvdd_en_default: camera_dvdd_en_default { + pins = "gpio3"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; +}; + +&pm660l_gpios { + camera0_dvdd_en_default: camera0_dvdd_en_default { + pins = "gpio3"; + function = "normal"; + power-source = <0>; + output-low; + }; + + camera1_dvdd_en_default: camera1_dvdd_en_default { + pins = "gpio4"; + function = "normal"; + power-source = <0>; + output-low; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio7"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; + smb_shutdown_default: smb_shutdown_default { + pins = "gpio11"; + function = "normal"; + power-source = <0>; + qcom,drive-strength = <3>; + output-high; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5bf8df72c99dfd3bee6dd67cbdf745abb655abea --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi @@ -0,0 +1,192 @@ +/* Copyright (c) 2017, 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 { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "L3"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xfff>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "l3-wfi"; + qcom,psci-mode = <0x1>; + qcom,latency-us = <600>; + qcom,ss-power = <420>; + qcom,energy-overhead = <4254140>; + qcom,time-overhead = <1260>; + }; + + qcom,pm-cluster-level@1 { /* D4, D3 is not supported */ + reg = <1>; + label = "l3-pc"; + qcom,psci-mode = <0x4>; + qcom,latency-us = <3048>; + qcom,ss-power = <329>; + qcom,energy-overhead = <6189829>; + qcom,time-overhead = <5800>; + qcom,min-child-idx = <3>; + qcom,is-reset; + }; + + qcom,pm-cluster-level@2 { /* Cx off */ + reg = <2>; + label = "cx-off"; + qcom,psci-mode = <0x224>; + qcom,latency-us = <4562>; + qcom,ss-power = <290>; + qcom,energy-overhead = <6989829>; + qcom,time-overhead = <8200>; + qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cluster-level@3 { /* AOSS sleep */ + reg = <3>; + label = "llcc-off"; + qcom,psci-mode = <0xC24>; + qcom,latency-us = <6562>; + qcom,ss-power = <165>; + qcom,energy-overhead = <7000029>; + qcom,time-overhead = <9825>; + qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,use-prediction; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 + &CPU5>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <60>; + qcom,ss-power = <383>; + qcom,energy-overhead = <64140>; + qcom,time-overhead = <121>; + }; + + qcom,pm-cpu-level@1 { /* C2D */ + reg = <1>; + label = "ret"; + qcom,psci-cpu-mode = <0x2>; + qcom,latency-us = <282>; + qcom,ss-power = <370>; + qcom,energy-overhead = <238600>; + qcom,time-overhead = <559>; + }; + + qcom,pm-cpu-level@2 { /* C3 */ + reg = <2>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <901>; + qcom,ss-power = <364>; + qcom,energy-overhead = <579285>; + qcom,time-overhead = <1450>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@3 { /* C4 */ + reg = <3>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <915>; + qcom,ss-power = <353>; + qcom,energy-overhead = <666292>; + qcom,time-overhead = <1617>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + + qcom,pm-cpu@1 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <66>; + qcom,ss-power = <427>; + qcom,energy-overhead = <68410>; + qcom,time-overhead = <121>; + }; + + qcom,pm-cpu-level@1 { /* C2D */ + reg = <1>; + label = "ret"; + qcom,psci-cpu-mode = <0x2>; + qcom,latency-us = <282>; + qcom,ss-power = <388>; + qcom,energy-overhead = <281755>; + qcom,time-overhead = <553>; + }; + + qcom,pm-cpu-level@2 { /* C3 */ + reg = <2>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <1244>; + qcom,ss-power = <373>; + qcom,energy-overhead = <795006>; + qcom,time-overhead = <1767>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@3 { /* C4 */ + reg = <3>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <1854>; + qcom,ss-power = <359>; + qcom,energy-overhead = <1068095>; + qcom,time-overhead = <2380>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + + qcom,rpm-stats@c300000 { + compatible = "qcom,rpm-stats"; + reg = <0xc300000 0x1000>, <0xc3f0004 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; + + qcom,rpmh-master-stats { + compatible = "qcom,rpmh-master-stats"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3ea4fa7b18b999970d8a258e434a2ccc843e09c6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts @@ -0,0 +1,74 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&dsi_dual_nt35597_truly_video_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_panel_pwr_supply_labibb_amoled { + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4000000>; + qcom,supply-max-voltage = <6300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@4 { + reg = <4>; + qcom,supply-name = "oledb"; + qcom,supply-min-voltage = <5000000>; + qcom,supply-max-voltage = <8100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&dsi_rm67195_amoled_fhd_cmd_display { + qcom,dsi-display-active; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + oledb-supply = <&pm660a_oledb>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..64133dd10333cd061a76dcc5a057688e795f144d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts @@ -0,0 +1,68 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&dsi_dual_nt35597_truly_video_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_panel_pwr_supply_labibb_amoled { + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4000000>; + qcom,supply-max-voltage = <6300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@4 { + reg = <4>; + qcom,supply-name = "oledb"; + qcom,supply-min-voltage = <5000000>; + qcom,supply-max-voltage = <8100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&dsi_rm67195_amoled_fhd_cmd_display { + qcom,dsi-display-active; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + oledb-supply = <&pm660a_oledb>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..15506614d73ba3afb8b17600bfbfce131c5a483a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..14f48a067104ae3449577e3d419fd857dd6e723f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..b7cb8209728b275c8bc49e9a9c9ac911a99bf75b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts @@ -0,0 +1,74 @@ +/* Copyright (c) 2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A + Tasha Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 5>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&dsi_dual_nt35597_truly_video_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_panel_pwr_supply_labibb_amoled { + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4000000>; + qcom,supply-max-voltage = <6300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@4 { + reg = <4>; + qcom,supply-name = "oledb"; + qcom,supply-min-voltage = <5000000>; + qcom,supply-max-voltage = <8100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&dsi_rm67195_amoled_fhd_cmd_display { + qcom,dsi-display-active; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + oledb-supply = <&pm660a_oledb>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..1922b38437569640e22ef70719a29a1c618f3bce --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts @@ -0,0 +1,68 @@ +/* Copyright (c) 2018, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Tasha Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 5>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&dsi_dual_nt35597_truly_video_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_panel_pwr_supply_labibb_amoled { + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4000000>; + qcom,supply-max-voltage = <6300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@4 { + reg = <4>; + qcom,supply-name = "oledb"; + qcom,supply-min-voltage = <5000000>; + qcom,supply-max-voltage = <8100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&dsi_rm67195_amoled_fhd_cmd_display { + qcom,dsi-display-active; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + oledb-supply = <&pm660a_oledb>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5d3975c17fe720541de55cfbcc148aba83439a3b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi @@ -0,0 +1,447 @@ +/* Copyright (c) 2017, 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. + */ + +&pm660_0{ + pm660_charger: qcom,qpnp-smb2 { + compatible = "qcom,qpnp-smb2"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,pmic-revid = <&pm660_revid>; + + io-channels = <&pm660_rradc 8>, + <&pm660_rradc 10>, + <&pm660_rradc 3>, + <&pm660_rradc 4>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v"; + + qcom,wipower-max-uw = <5000000>; + + dpdm-supply = <&qusb_phy0>; + + qcom,thermal-mitigation + = <3000000 2500000 2000000 1500000 + 1000000 500000>; + qcom,auto-recharge-soc; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = + <0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>, + <0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; + smb2_vbus: qcom,smb2-vbus { + regulator-name = "smb2-vbus"; + }; + + smb2_vconn: qcom,smb2-vconn { + regulator-name = "smb2-vconn"; + }; + }; + + pm660_rradc: rradc@4500 { + compatible = "qcom,rradc"; + reg = <0x4500 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + qcom,pmic-revid = <&pm660_revid>; + }; + + pm660_fg: qpnp,fg { + compatible = "qcom,fg-gen3"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660_revid>; + io-channels = <&pm660_rradc 0>, + <&pm660_rradc 7>; + io-channel-names = "rradc_batt_id", + "rradc_die_temp"; + qcom,rradc-base = <0x4500>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; + qcom,cycle-counter-en; + qcom,hold-soc-while-full; + qcom,fg-auto-recharge-soc; + qcom,fg-recharge-soc-thr = <98>; + status = "okay"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x2 + IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 0x3 + IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x5 + IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta", + "msoc-low", + "msoc-empty", + "msoc-high", + "msoc-full"; + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbatt-pred-delta", + "vbatt-low", + "esr-delta", + "batt-missing", + "batt-temp-delta"; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "ima-rdy", + "mem-xcp", + "dma-grant"; + }; + }; +}; + +&pm660_1 { + pm660_haptics: qcom,haptics@c000 { + compatible = "qcom,qpnp-haptics"; + reg = <0xc000 0x100>; + interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hap-sc-irq", "hap-play-irq"; + qcom,pmic-revid = <&pm660_revid>; + qcom,pmic-misc = <&pm660_misc>; + qcom,misc-clk-trim-error-reg = <0xf3>; + qcom,actuator-type = <0>; + qcom,play-mode = "direct"; + qcom,vmax-mv = <3200>; + qcom,ilim-ma = <800>; + qcom,sc-dbc-cycles = <8>; + qcom,wave-play-rate-us = <6667>; + qcom,en-brake; + qcom,lra-high-z = "opt0"; + qcom,lra-auto-res-mode = "qwd"; + qcom,lra-res-cal-period = <4>; + }; +}; + +&pm660l_3 { + pm660l_wled: qcom,leds@d800 { + compatible = "qcom,qpnp-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base"; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq"; + linux,name = "wled"; + linux,default-trigger = "bkl-trigger"; + qcom,fdbk-output = "auto"; + qcom,vref-uv = <127500>; + qcom,switch-freq-khz = <800>; + qcom,ovp-mv = <29600>; + qcom,ilim-ma = <970>; + qcom,boost-duty-ns = <26>; + qcom,mod-freq-khz = <9600>; + qcom,dim-mode = "hybrid"; + qcom,hyb-thres = <625>; + qcom,sync-dly-us = <800>; + qcom,fs-curr-ua = <25000>; + qcom,cons-sync-write-delay-us = <1000>; + qcom,led-strings-list = [00 01 02]; + qcom,loop-auto-gm-en; + qcom,pmic-revid = <&pm660l_revid>; + qcom,auto-calibration-enable; + status = "ok"; + }; + + pm660l_lcdb: qpnp-lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + + qcom,pmic-revid = <&pm660l_revid>; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + }; + + pm660a_oledb: qpnp-oledb@e000 { + compatible = "qcom,qpnp-oledb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; + reg = <0xe000 0x100>; + qcom,pbs-client = <&pm660l_pbs>; + + label = "oledb"; + regulator-name = "regulator-oledb"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <8100000>; + + qcom,swire-control; + qcom,ext-pin-control; + status = "disabled"; + }; + + pm660a_labibb: qpnp-labibb-regulator { + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; + qcom,swire-control; + status = "disabled"; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6300000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-init-voltage = <4000000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6100000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-init-voltage = <4600000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + + qcom,notify-lab-vreg-ok-sts; + }; + }; +}; + +&pm660_pdphy { + vbus-supply = <&smb2_vbus>; + vconn-supply = <&smb2_vconn>; +}; + +&usb0 { + extcon = <&pm660_pdphy>, <&pm660_pdphy>, <&eud>, + <&pm660_charger>, <&pm660_charger>; + vbus_dwc3-supply = <&smb2_vbus>; + qcom,no-vbus-vote-with-type-C; +}; + +&thermal_zones { + xo-therm-batt-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4c>; + thermal-governor = "step_wise"; + + trips { + batt_trip1: batt-trip1 { + temperature = <40000>; + hysteresis = <2000>; + type = "passive"; + }; + batt_trip2: batt-trip2 { + temperature = <45000>; + hysteresis = <2000>; + type = "passive"; + }; + batt_trip3: batt-trip3 { + temperature = <48000>; + hysteresis = <3000>; + type = "passive"; + }; + batt_trip4: batt-trip4 { + temperature = <50000>; + hysteresis = <2000>; + type = "passive"; + }; + batt_trip5: batt-trip5 { + temperature = <52000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + + cooling-maps { + battery_lvl1 { + trip = <&batt_trip1>; + cooling-device = <&pm660_charger 1 1>; + }; + battery_lvl2 { + trip = <&batt_trip2>; + cooling-device = <&pm660_charger 2 2>; + }; + battery_lvl3 { + trip = <&batt_trip3>; + cooling-device = <&pm660_charger 3 3>; + }; + battery_lvl4 { + trip = <&batt_trip4>; + cooling-device = <&pm660_charger 4 4>; + }; + battery_lvl5 { + trip = <&batt_trip5>; + cooling-device = <&pm660_charger 5 5>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..36d485eb973d41256a4bac4d2b9bb7cce6af90cd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-overlay.dts @@ -0,0 +1,32 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD"; + compatible = "qcom,sdm670-qrd", "qcom,sdm670", "qcom,qrd"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <0x0002000b 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..73d19094b6ca33bb504e2af2af49005bcb58c539 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2-overlay.dts @@ -0,0 +1,51 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD SKU2"; + compatible = "qcom,sdm670-qrd", "qcom,sdm670", "qcom,qrd"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <0x0012000b 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&dsi_dual_nt36850_truly_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_hx8399_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_hx8399_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts new file mode 100644 index 0000000000000000000000000000000000000000..680bc17ccbaa5dbc52dc3d2862b1c987137f70ce --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd-sku2.dts @@ -0,0 +1,45 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD SKU2"; + compatible = "qcom,sdm670-qrd", "qcom,sdm670", "qcom,qrd"; + qcom,board-id = <0x0012000b 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&dsi_dual_nt36850_truly_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_hx8399_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_hx8399_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dts b/arch/arm64/boot/dts/qcom/sdm670-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..c22afa42c20164d5c3cb81d8f29812c08afa972e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L QRD"; + compatible = "qcom,sdm670-qrd", "qcom,sdm670", "qcom,qrd"; + qcom,board-id = <0x0002000b 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9a7e742d6aaaacb9a6b5701a91404818838f2315 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi @@ -0,0 +1,323 @@ +/* Copyright (c) 2017-2018, 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 +#include "sdm670-camera-sensor-qrd.dtsi" +#include "sdm670-pmic-overlay.dtsi" +#include "sdm670-audio-overlay.dtsi" +#include "smb1355.dtsi" +#include "sdm670-sde-display.dtsi" + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&qupv3_se8_spi { + status = "disabled"; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 44 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 43 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <44 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; +}; + +&qupv3_se10_i2c { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&vendor { + qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen3-batterydata-mlp356477-2800mah.dtsi" + }; +}; + +&eud { + vdda33-supply = <&pm660l_l7>; +}; + +&pm660_fg { + qcom,battery-data = <&qrd_batterydata>; + qcom,fg-bmd-en-delay-ms = <300>; +}; + +&pm660_charger { + qcom,thermal-mitigation = <4200000 3500000 3000000 2500000 + 2000000 1500000 1000000 500000>; + qcom,battery-data = <&qrd_batterydata>; + qcom,sw-jeita-enable; +}; + +&tlmm { + smb_int_default: smb_int_default { + mux { + pins = "gpio54"; + function = "gpio"; + }; + config { + pins = "gpio54"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; +}; + +&smb1355_0 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default + &smb_shutdown_default>; + interrupt-parent = <&tlmm>; + interrupts = <54 IRQ_TYPE_LEVEL_LOW>; + smb1355_charger_0: qcom,smb1355-charger@1000 { + io-channels = <&pm660_rradc 2>, + <&pm660_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + status = "ok"; + }; +}; + +&smb1355_1 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default + &smb_shutdown_default>; + interrupt-parent = <&tlmm>; + interrupts = <54 IRQ_TYPE_LEVEL_LOW>; + smb1355_charger_1: qcom,smb1355-charger@1000 { + io-channels = <&pm660_rradc 2>, + <&pm660_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + status = "ok"; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x00 0x220 /* IMP_CTRL1 */ + 0x1a 0x224 /* IMP_CTRL2 */ + 0x47 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; + +&pm660_haptics { + qcom,vmax-mv = <1800>; + qcom,wave-play-rate-us = <4255>; + qcom,lra-auto-mode; + status = "okay"; +}; + +&int_codec { + qcom,model = "sdm670-skuw-snd-card"; + qcom,msm-micbias1-ext-cap; + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "INT_LDO_H", "INT_MCLK0", + "MIC BIAS External2", "Headset Mic", + "AMIC2", "MIC BIAS External2", + "MIC BIAS External", "Handset Mic", + "AMIC1", "MIC BIAS External", + "MIC BIAS External", "Secondary Mic", + "AMIC3", "MIC BIAS External", + "SpkrLeft IN", "SPK1 OUT", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_213_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; + +&sdhc_1 { + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 96 0>; + + status = "ok"; +}; + +&tlmm { + pmx_ts_rst_active { + ts_rst_active: ts_rst_active { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + + pmx_ts_rst_suspend { + ts_rst_suspend: ts_rst_suspend { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; + +&soc { + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm660l_l3>; + vcc_dig-supply = <&pm660_l13>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3000000>; + qcom,afe-vtg-max = <3000000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1800000>; + qcom,dig-vtg-max = <1800000>; + qcom,fb-resume-delay-us = <1000>; + qcom,afe-force-power-on; + qcom,afe-power-on-delay-us = <6>; + qcom,afe-power-off-delay-us = <6>; + }; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_dual_nt36850_truly_cmd_display { + qcom,dsi-display-active; +}; + +&dsi_panel_pwr_supply { + qcom,panel-supply-entry@2 { + qcom,supply-post-off-sleep = <5>; + }; +}; + +&pm660l_wled { + status = "okay"; + qcom,led-strings-list = [00 01]; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6c143e4dacb13666f40898e3f521b09a12e14665 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi @@ -0,0 +1,814 @@ +/* Copyright (c) 2017-2018, 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 + +&soc { + /* QUPv3 South instances */ + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x003 0x0>; + }; + }; + + /* + * HS UART instances. HS UART usecases can be supported on these + * instances only. + */ + qupv3_se6_4uart: qcom,qup_uart@0x898000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x898000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, + <&qupv3_se6_tx>; + pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, + <&qupv3_se6_tx>; + interrupts-extended = <&pdc GIC_SPI 607 0>, + <&tlmm 48 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; + }; + + qupv3_se7_4uart: qcom,qup_uart@0x89c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x89c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_4uart_active>; + pinctrl-1 = <&qupv3_se7_4uart_sleep>; + interrupts-extended = <&pdc GIC_SPI 608 0>, + <&tlmm 96 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; + }; + + /* I2C */ + qupv3_se0_i2c: i2c@880000 { + compatible = "qcom,i2c-geni"; + reg = <0x880000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se1_i2c: i2c@884000 { + compatible = "qcom,i2c-geni"; + reg = <0x884000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@888000 { + compatible = "qcom,i2c-geni"; + reg = <0x888000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se3_i2c: i2c@88c000 { + compatible = "qcom,i2c-geni"; + reg = <0x88c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 3 3 64 0>, + <&gpi_dma0 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_i2c_active>; + pinctrl-1 = <&qupv3_se3_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se4_i2c: i2c@890000 { + compatible = "qcom,i2c-geni"; + reg = <0x890000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 4 3 64 0>, + <&gpi_dma0 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_i2c_active>; + pinctrl-1 = <&qupv3_se4_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se5_i2c: i2c@894000 { + compatible = "qcom,i2c-geni"; + reg = <0x894000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 5 3 64 0>, + <&gpi_dma0 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_i2c_active>; + pinctrl-1 = <&qupv3_se5_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se6_i2c: i2c@898000 { + compatible = "qcom,i2c-geni"; + reg = <0x898000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 6 3 64 0>, + <&gpi_dma0 1 6 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i2c_active>; + pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se7_i2c: i2c@89c000 { + compatible = "qcom,i2c-geni"; + reg = <0x89c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 7 3 64 0>, + <&gpi_dma0 1 7 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_i2c_active>; + pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se0_spi: spi@880000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x880000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se1_spi: spi@884000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x884000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_spi_active>; + pinctrl-1 = <&qupv3_se1_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se2_spi: spi@888000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x888000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_spi_active>; + pinctrl-1 = <&qupv3_se2_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se3_spi: spi@88c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x88c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_spi_active>; + pinctrl-1 = <&qupv3_se3_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 3 1 64 0>, + <&gpi_dma0 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se4_spi: spi@890000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x890000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_spi_active>; + pinctrl-1 = <&qupv3_se4_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 4 1 64 0>, + <&gpi_dma0 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se5_spi: spi@894000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x894000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_spi_active>; + pinctrl-1 = <&qupv3_se5_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se6_spi: spi@898000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x898000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_spi_active>; + pinctrl-1 = <&qupv3_se6_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 6 1 64 0>, + <&gpi_dma0 1 6 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se7_spi: spi@89c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x89c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_spi_active>; + pinctrl-1 = <&qupv3_se7_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 7 1 64 0>, + <&gpi_dma0 1 7 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* QUPv3 North Instances */ + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x6c3 0x0>; + }; + }; + + /* 2-wire UART */ + + /* Debug UART Instance for CDP/MTP platform */ + qupv3_se9_2uart: qcom,qup_uart@0xa84000 { + compatible = "qcom,msm-geni-console"; + reg = <0xa84000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_2uart_active>; + pinctrl-1 = <&qupv3_se9_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* Debug UART Instance for RUMI platform */ + qupv3_se10_2uart: qcom,qup_uart@0xa88000 { + compatible = "qcom,msm-geni-console"; + reg = <0xa88000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_2uart_active>; + pinctrl-1 = <&qupv3_se10_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* Debug UART Instance for CDP/MTP platform on SDM670 */ + qupv3_se12_2uart: qcom,qup_uart@0xa90000 { + compatible = "qcom,msm-geni-console"; + reg = <0xa90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_2uart_active>; + pinctrl-1 = <&qupv3_se12_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* I2C */ + qupv3_se8_i2c: i2c@a80000 { + compatible = "qcom,i2c-geni"; + reg = <0xa80000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_i2c_active>; + pinctrl-1 = <&qupv3_se8_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se9_i2c: i2c@a84000 { + compatible = "qcom,i2c-geni"; + reg = <0xa84000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_i2c_active>; + pinctrl-1 = <&qupv3_se9_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se10_i2c: i2c@a88000 { + compatible = "qcom,i2c-geni"; + reg = <0xa88000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_i2c_active>; + pinctrl-1 = <&qupv3_se10_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se11_i2c: i2c@a8c000 { + compatible = "qcom,i2c-geni"; + reg = <0xa8c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 3 3 64 0>, + <&gpi_dma1 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_i2c_active>; + pinctrl-1 = <&qupv3_se11_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se12_i2c: i2c@a90000 { + compatible = "qcom,i2c-geni"; + reg = <0xa90000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 4 3 64 0>, + <&gpi_dma1 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_i2c_active>; + pinctrl-1 = <&qupv3_se12_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se13_i2c: i2c@a94000 { + compatible = "qcom,i2c-geni"; + reg = <0xa94000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 5 3 64 0>, + <&gpi_dma1 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se13_i2c_active>; + pinctrl-1 = <&qupv3_se13_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se14_i2c: i2c@a98000 { + compatible = "qcom,i2c-geni"; + reg = <0xa98000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 6 3 64 0>, + <&gpi_dma1 1 6 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se14_i2c_active>; + pinctrl-1 = <&qupv3_se14_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se15_i2c: i2c@a9c000 { + compatible = "qcom,i2c-geni"; + reg = <0xa9c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 7 3 64 0>, + <&gpi_dma1 1 7 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se15_i2c_active>; + pinctrl-1 = <&qupv3_se15_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se8_spi: spi@a80000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa80000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_spi_active>; + pinctrl-1 = <&qupv3_se8_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se9_spi: spi@a84000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa84000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_spi_active>; + pinctrl-1 = <&qupv3_se9_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 1 1 64 0>, + <&gpi_dma1 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se10_spi: spi@a88000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa88000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_spi_active>; + pinctrl-1 = <&qupv3_se10_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 2 1 64 0>, + <&gpi_dma1 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se11_spi: spi@a8c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa8c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_spi_active>; + pinctrl-1 = <&qupv3_se11_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 3 1 64 0>, + <&gpi_dma1 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se12_spi: spi@a90000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_spi_active>; + pinctrl-1 = <&qupv3_se12_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 4 1 64 0>, + <&gpi_dma1 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se13_spi: spi@a94000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa94000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se13_spi_active>; + pinctrl-1 = <&qupv3_se13_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 5 1 64 0>, + <&gpi_dma1 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se14_spi: spi@a98000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa98000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se14_spi_active>; + pinctrl-1 = <&qupv3_se14_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 6 1 64 0>, + <&gpi_dma1 1 6 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se15_spi: spi@a9c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa9c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se15_spi_active>; + pinctrl-1 = <&qupv3_se15_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 7 1 64 0>, + <&gpi_dma1 1 7 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6b24593c9c4d7d79494bdb6d8276b70858f3dcb6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi @@ -0,0 +1,689 @@ +/* Copyright (c) 2017,2018 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 PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +/* Stub regulators */ + +/ { + apc0_pwrcl_vreg: regulator-pwrcl { + compatible = "qcom,stub-regulator"; + regulator-name = "apc0_pwrcl_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + }; + + apc0_l3_vreg: regulator-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "apc0_l3_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + }; + + apc1_perfcl_vreg: regulator-perfcl { + compatible = "qcom,stub-regulator"; + regulator-name = "apc1_perfcl_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + }; +}; + +&soc { + /* RPMh regulators: */ + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa4"; + pm660_s4: regulator-pm660-s4 { + regulator-name = "pm660_s4"; + qcom,set = ; + regulator-min-microvolt = <1808000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1808000>; + }; + }; + + /* pm660 S5 - VDD_MODEM supply */ + rpmh-regulator-modemlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mss.lvl"; + pm660_s5_level: regulator-pm660-s5 { + regulator-name = "pm660_s5_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-smpa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa6"; + pm660_s6: regulator-pm660-s6 { + regulator-name = "pm660_s6"; + qcom,set = ; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1352000>; + qcom,init-voltage = <1224000>; + }; + }; + + /* pm660l S1 - VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + pm660l_s1_level: regulator-pm660l-s1 { + regulator-name = "pm660l_s1_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_s1_level_ao: regulator-pm660l-s1-level-ao { + regulator-name = "pm660l_s1_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pm660l_s1_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + /* pm660l S2 - VDD_GFX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "gfx.lvl"; + pm660l_s2_level: regulator-pm660l-s2 { + regulator-name = "pm660l_s2_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* pm660l S3 + S4 - VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pm660l_s3_level-parent-supply = <&pm660l_s1_level>; + pm660l_s3_level_ao-parent-supply = <&pm660l_s1_level_ao>; + pm660l_s3_level: regulator-pm660l-s3-level { + regulator-name = "pm660l_s3_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + pm660l_s3_level_ao: regulator-pm660l-s3-level-ao { + regulator-name = "pm660l_s3_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm660_l1>; + pm660_l1: regulator-pm660-l1 { + regulator-name = "pm660_l1"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1250000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <43600>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l2: regulator-pm660-l2 { + regulator-name = "pm660_l2"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <1000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l3: regulator-pm660-l3 { + regulator-name = "pm660_l3"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <1000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l5: regulator-pm660-l5 { + regulator-name = "pm660_l5"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm660_l6: regulator-pm660-l6 { + regulator-name = "pm660_l6"; + qcom,set = ; + regulator-min-microvolt = <1248000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1248000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l7: regulator-pm660-l7 { + regulator-name = "pm660_l7"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l8: regulator-pm660-l8 { + regulator-name = "pm660_l8"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm660_l9: regulator-pm660-l9 { + regulator-name = "pm660_l9"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l10: regulator-pm660-l10 { + regulator-name = "pm660_l10"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm660_l11>; + pm660_l11: regulator-pm660-l11 { + regulator-name = "pm660_l11"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <115000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l12: regulator-pm660-l12 { + regulator-name = "pm660_l12"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l13: regulator-pm660-l13 { + regulator-name = "pm660_l13"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l14: regulator-pm660-l14 { + regulator-name = "pm660_l14"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l15: regulator-pm660-l15 { + regulator-name = "pm660_l15"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l16: regulator-pm660-l16 { + regulator-name = "pm660_l16"; + qcom,set = ; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + qcom,init-voltage = <2700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660_l17: regulator-pm660-l17 { + regulator-name = "pm660_l17"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa19 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa19"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm660_l19: regulator-pm660-l19 { + regulator-name = "pm660_l19"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob1"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm660l_l1>; + pm660l_l1: regulator-pm660l-l1 { + regulator-name = "pm660l_l1"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <900000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <72000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob2"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l2: regulator-pm660l-l2 { + regulator-name = "pm660l_l2"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob3"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l3: regulator-pm660l-l3 { + regulator-name = "pm660l_l3"; + qcom,set = ; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3008000>; + qcom,init-voltage = <2850000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob4"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l4: regulator-pm660l-l4 { + regulator-name = "pm660l_l4"; + qcom,set = ; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2960000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob5"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l5: regulator-pm660l-l5 { + regulator-name = "pm660l_l5"; + qcom,set = ; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2960000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob6"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l6: regulator-pm660l-l6 { + regulator-name = "pm660l_l6"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob7"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l7: regulator-pm660l-l7 { + regulator-name = "pm660l_l7"; + qcom,set = ; + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3100000>; + qcom,init-voltage = <3088000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldob8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldob8"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm660l_l8: regulator-pm660l-l8 { + regulator-name = "pm660l_l8"; + qcom,set = ; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3300000>; + qcom,init-mode = ; + }; + }; + + /* pm660l L9 = VDD_LPI_CX supply */ + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lcx.lvl"; + pm660l_l9_level: regulator-pm660l-l9-level { + regulator-name = "pm660l_l9_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + /* pm660l L10 = VDD_LPI_MX supply */ + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lmx.lvl"; + pm660l_l10_level: regulator-pm660l-l10-level { + regulator-name = "pm660l_l10_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-bobb1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "bobb1"; + pm660l_bob: regulator-pm660l-bob { + regulator-name = "pm660l_bob"; + qcom,set = ; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3312000>; + }; + }; + + refgen: refgen-regulator@ff1000 { + compatible = "qcom,refgen-regulator"; + reg = <0xff1000 0x60>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + proxy-supply = <&refgen>; + qcom,proxy-consumer-enable; + regulator-always-on; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4a24d8760e7f0737a588628adb77a354f0c4131b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include "sdm670-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 RUMI"; + compatible = "qcom,sdm670-rumi", "qcom,sdm670", "qcom,rumi"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <15 0>; +}; + +&soc { + wdog: qcom,wdt@17980000{ + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dts b/arch/arm64/boot/dts/qcom/sdm670-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..6201488f0212cb7df365fbf0989a36a4e4dce150 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, 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/; +/memreserve/ 0x90000000 0x00000100; + +#include "sdm670.dtsi" +#include "sdm670-rumi.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SDM670 RUMI"; + compatible = "qcom,sdm670-rumi", "qcom,sdm670", "qcom,rumi"; + qcom,board-id = <15 0>; +}; + +&soc { + wdog: qcom,wdt@17980000{ + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a50d9b6ed3c0a32f0d99040ac607ebb21abf2a46 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi @@ -0,0 +1,218 @@ +/* Copyright (c) 2017, 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 "sdm670-pmic-overlay.dtsi" + +&soc { + /* Delete all regulators */ + /delete-node/ rpmh-regulator-smpa4; + /delete-node/ rpmh-regulator-smpa6; + /delete-node/ rpmh-regulator-mxlvl; + /delete-node/ rpmh-regulator-modemlvl; + /delete-node/ rpmh-regulator-cxlvl; + /delete-node/ rpmh-regulator-ldoa1; + /delete-node/ rpmh-regulator-ldoa2; + /delete-node/ rpmh-regulator-ldoa3; + /delete-node/ rpmh-regulator-ldoa5; + /delete-node/ rpmh-regulator-ldoa6; + /delete-node/ rpmh-regulator-ldoa7; + /delete-node/ rpmh-regulator-ldoa8; + /delete-node/ rpmh-regulator-ldoa9; + /delete-node/ rpmh-regulator-ldoa10; + /delete-node/ rpmh-regulator-ldoa11; + /delete-node/ rpmh-regulator-ldoa12; + /delete-node/ rpmh-regulator-ldoa13; + /delete-node/ rpmh-regulator-ldoa14; + /delete-node/ rpmh-regulator-ldoa15; + /delete-node/ rpmh-regulator-ldoa16; + /delete-node/ rpmh-regulator-ldoa17; + /delete-node/ rpmh-regulator-ldoa19; + /delete-node/ rpmh-regulator-ldob1; + /delete-node/ rpmh-regulator-ldob2; + /delete-node/ rpmh-regulator-ldob3; + /delete-node/ rpmh-regulator-ldob4; + /delete-node/ rpmh-regulator-ldob5; + /delete-node/ rpmh-regulator-ldob6; + /delete-node/ rpmh-regulator-ldob7; + /delete-node/ rpmh-regulator-ldob8; + /delete-node/ rpmh-regulator-lcxlvl; + /delete-node/ rpmh-regulator-lmxlvl; + /delete-node/ rpmh-regulator-ldoa28; + /delete-node/ rpmh-regulator-bobb1; + /delete-node/ rpmh-regulator-gfxlvl; + /delete-node/ thermal-zones; +}; + +#include "sdm670-stub-regulator.dtsi" + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se8_spi { + status = "disabled"; +}; + +&qupv3_se10_2uart { + status = "ok"; +}; + +&qupv3_se3_i2c { + status = "disabled"; +}; + +&qupv3_se10_i2c { + status = "disabled"; +}; + +&qupv3_se6_4uart { + status = "disabled"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qrbtc-sdm845"; + + vdda-phy-supply = <&pm660l_l1>; /* 0.88v */ + vdda-pll-supply = <&pm660_l1>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + limit-tx-hs-gear = <1>; + limit-rx-hs-gear = <1>; + scsi-cmd-timeout = <300000>; + + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm660_l1>; + qcom,vddp-ref-clk-max-microamp = <100>; + + qcom,disable-lpm; + rpm-level = <0>; + spm-level = <0>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <200 570000>; + + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&usb0 { + /delete-property/ qcom,usb-dbm; + /delete-property/ extcon; + qcom,charging-disabled; + dwc3@a600000 { + maximum-speed = "high-speed"; + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + }; +}; + +&qusb_phy0 { + reg = <0x088e2000 0x4>, + <0x0a720000 0x9500>; + reg-names = "qusb_phy_base", + "emu_phy_base"; + qcom,emulation; + qcom,emu-init-seq = <0x19 0x1404 + 0x20 0x1414 + 0x79 0x1410 + 0x00 0x1418 + 0x99 0x1404 + 0x04 0x1408 + 0xd9 0x1404>; + + qcom,emu-dcm-reset-seq = <0x5 0x14 /* 0x1 0x14 for E1.2 */ + 0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 /* 0x220 0x20 for E1.2 */ + 0x80 0x28>; +}; + +&usb_qmp_dp_phy { + status = "disabled"; +}; + +&mdss_mdp { + status = "disabled"; +}; + +&sde_rscc { + status = "disabled"; +}; + +&mdss_rotator { + status = "disabled"; +}; + +&mdss_dsi0 { + status = "disabled"; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + +&mdss_dsi_phy0 { + status = "disabled"; +}; + +&mdss_dsi_phy1 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..007f937cf637148edff42c3dd7d2dc6284492523 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi @@ -0,0 +1,860 @@ +/* Copyright (c) 2017-2018, 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 "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" +#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi" +#include + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_vdd_no_labibb: dsi_panel_pwr_supply_vdd_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + }; + + dsi_panel_pwr_supply_labibb_amoled: dsi_panel_pwr_supply_labibb_amoled { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <32000>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdda-3p3"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <13200>; + qcom,supply-disable-load = <80>; + }; + }; + + dsi_dual_nt35597_truly_video_display: qcom,dsi-display@0 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_truly_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@1 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_truly_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@2 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@3 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_sim_vid_display: qcom,dsi-display@4 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_dual_sim_vid_display: qcom,dsi-display@5 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@6 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_dual_sim_cmd_display: qcom,dsi-display@7 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_cmd>; + }; + + dsi_sim_dsc_375_cmd_display: qcom,dsi-display@8 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; + }; + + dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@9 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; + }; + + dsi_dual_nt35597_video_display: qcom,dsi-display@10 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_video>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_dual_nt35597_cmd_display: qcom,dsi-display@11 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,panel-mode-gpio = <&tlmm 76 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_cmd>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_rm67195_amoled_fhd_cmd_display: qcom,dsi-display@12 { + compatible = "qcom,dsi-display"; + label = "dsi_rm67195_amoled_fhd_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_rm67195_amoled_fhd_cmd>; + vddio-supply = <&pm660_l11>; + vdda-3p3-supply = <&pm660l_l6>; + }; + + dsi_nt35695b_truly_fhd_video_display: qcom,dsi-display@13 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35695b_truly_fhd_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_video>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_nt35695b_truly_fhd_cmd_display: qcom,dsi-display@14 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35695b_truly_fhd_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_cmd>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_dual_nt36850_truly_cmd_display: qcom,dsi-display@15 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt36850_truly_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_dual_nt36850_truly_cmd>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_hx8399_truly_cmd_display: qcom,dsi-display@16 { + compatible = "qcom,dsi-display"; + label = "dsi_hx8399_truly_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_hx8399_truly_cmd>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pm660_pdphy>; + qcom,ext-disp = <&ext_disp>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 50 0>; + qcom,aux-sel-gpio = <&tlmm 40 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 128 720 128 1440 128>; + }; + }; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x0b>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,mdss-dsi-t-clk-post = <0x0b>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 04 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + timing@1{ + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + timing@2{ + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 03 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_video { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 128 720 128 1440 128>; + }; + }; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x1c>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c + 05 07 05 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x1c>; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c + 05 07 05 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,ulps-enabled; + qcom,mdss-mdp-transfer-time-us = <14500>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 + 07 07 05 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x28>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08 + 08 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_hx8399_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08 + 08 05 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..72e3f5f5537288caadeb15feaf0d9af75a069443 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-pll.dtsi @@ -0,0 +1,109 @@ +/* Copyright (c) 2017, 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 { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94a00 { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94a00 0x1e0>, + <0xae94400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96a00 { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96a00 0x1e0>, + <0xae96400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@88ea000 { + compatible = "qcom,mdss_dp_pll_10nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + gdsc-supply = <&mdss_core_gdsc>; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk", + "cfg_ahb_clk", "pipe_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + + }; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7c4e682dd7ad824e59e73a8b0616ceff30683270 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi @@ -0,0 +1,655 @@ +/* Copyright (c) 2017-2018, 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 + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x81d40>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0xf0>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc_iface", "gcc_bus", "iface_clk", + "bus_clk", "core_clk", "vsync_clk"; + clock-rate = <0 0 0 0 300000000 19200000 0>; + clock-max-rate = <0 0 0 0 412500000 19200000 0>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupt-parent = <&pdc>; + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + + #address-cells = <1>; + #size-cells = <0>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x45C>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800>; + qcom,sde-ctl-size = <0xE4>; + qcom,sde-ctl-display-pref = "primary", "primary", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 0x0 0x0 0x4a000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0xc>; + + qcom,sde-dspp-off = <0x55000 0x57000>; + qcom,sde-dspp-size = <0x17e0>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0xc>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0x800>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x3b8 24>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x280>; + + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000 0x72800 0x73000>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x1>; + qcom,sde-pp-size = <0xd4>; + + qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0 0x0>; + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000 0x81400>; + qcom,sde-dsc-size = <0x140>; + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0 0x0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "vig", + "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x7000 0x25000 0x27000 0x29000>; + qcom,sde-sspp-src-size = <0x1c8>; + + qcom,sde-sspp-xin-id = <0 4 1 5 9>; + qcom,sde-sspp-excl-rect = <1 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <4 5 1 2 3>; + qcom,sde-smart-dma-rev = "smart_dma_v2"; + + qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2b4 0>, + <0x2ac 8>, <0x2b4 8>, <0x2bc 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2560>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-smart-panel-align-mode = <0xc>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <6800000>; + qcom,sde-max-bw-high-kbps = <6800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ad-version = <0x00040000>; + qcom,sde-dspp-ad-off = <0x28000 0x27000>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 + 0x00000000>; + qcom,sde-safe-lut-linear = + <4 0xfff8>, + <0 0xfff0>; + qcom,sde-safe-lut-macrotile = + <10 0xfe00>, + <11 0xfc00>, + <12 0xf800>, + <0 0xf000>; + qcom,sde-safe-lut-nrt = + <0 0xffff>; + qcom,sde-safe-lut-cwb = + <0 0xffff>; + qcom,sde-qos-lut-linear = + <4 0x00000000 0x00000357>, + <5 0x00000000 0x00003357>, + <6 0x00000000 0x00023357>, + <7 0x00000000 0x00223357>, + <8 0x00000000 0x02223357>, + <9 0x00000000 0x22223357>, + <10 0x00000002 0x22223357>, + <11 0x00000022 0x22223357>, + <12 0x00000222 0x22223357>, + <13 0x00002222 0x22223357>, + <14 0x00012222 0x22223357>, + <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = + <10 0x00000003 0x44556677>, + <11 0x00000033 0x44556677>, + <12 0x00000233 0x44556677>, + <13 0x00002233 0x44556677>, + <14 0x00012233 0x44556677>, + <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-nrt = + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = + <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-inline-rotator = <&mdss_rotator 0>; + qcom,sde-inline-rot-xin = <10 11>; + qcom,sde-inline-rot-xin-type = "sspp", "wb"; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>; + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x1>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040000>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x881 0x8>, + <&apps_smmu 0xc81 0x8>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde_mnoc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 773 0 0>, <23 773 0 0>, + <22 773 0 6400000>, <23 773 0 6400000>, + <22 773 0 6400000>, <23 773 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "mdss_sde_llcc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <132 770 0 0>, + <132 770 0 6400000>, + <132 770 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "mdss_sde_ebi"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 6400000>, + <129 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <1>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "iface_clk"; + clock-rate = <0 0>; + + qcom,sde-dram-channels = <2>; + + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20515 0 0>, <20004 20515 0 0>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator@ae00000 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk", "axi_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + /* Inline rotator QoS Setting */ + /* setting default register values for RD - qos/danger/safe */ + qcom,mdss-inline-rot-qos-lut = <0x44556677 0x00112233 + 0x44556677 0x00112233>; + qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>; + qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>; + + qcom,mdss-rot-qos-cpu-mask = <0xf>; + qcom,mdss-rot-qos-cpu-dma-latency = <75>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x1090 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0x1091 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.2"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm660_l1>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,null-insertion-enabled; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { + compatible = "qcom,dsi-ctrl-hw-v2.2"; + label = "dsi-ctrl-1"; + cell-index = <1>; + reg = <0xae96000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <5 0>; + vdda-1p2-supply = <&pm660_l1>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + qcom,null-insertion-enabled; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x7c0>; + reg-names = "dsi_phy"; + gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm660l_l1>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy0@ae96400 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x7c0>; + reg-names = "dsi_phy"; + gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm660l_l1>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; + + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&pm660_l1>; + vdda-0p9-supply = <&pm660l_l1>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea030 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_pixel_clk", + "crypto_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13 23 1d]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 bb]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f3e5ddbb293e0df6fd88072efa7efdbd6fc0fe6f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi @@ -0,0 +1,271 @@ +/* Copyright (c) 2017, 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 + +&soc { + qcom,smp2p-modem@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <1>; + qcom,irq-bitmask = <0x4000>; + interrupts = ; + }; + + qcom,smp2p-adsp@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <2>; + qcom,irq-bitmask = <0x4000000>; + interrupts = ; + }; + + qcom,smp2p-cdsp@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <5>; + qcom,irq-bitmask = <0x40>; + interrupts = ; + }; + + + smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_in { + compatible = "qcom,smp2pgpio_test_smp2p_15_in"; + gpios = <&smp2pgpio_smp2p_15_in 0 0>; + }; + + smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_out { + compatible = "qcom,smp2pgpio_test_smp2p_15_out"; + gpios = <&smp2pgpio_smp2p_15_out 0 0>; + }; + + smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_in { + compatible = "qcom,smp2pgpio_test_smp2p_1_in"; + gpios = <&smp2pgpio_smp2p_1_in 0 0>; + }; + + smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_out { + compatible = "qcom,smp2pgpio_test_smp2p_1_out"; + gpios = <&smp2pgpio_smp2p_1_out 0 0>; + }; + + smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_2_in { + compatible = "qcom,smp2pgpio_test_smp2p_2_in"; + gpios = <&smp2pgpio_smp2p_2_in 0 0>; + }; + + smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_2_out { + compatible = "qcom,smp2pgpio_test_smp2p_2_out"; + gpios = <&smp2pgpio_smp2p_2_out 0 0>; + }; + + smp2pgpio_sleepstate_2_out: qcom,smp2pgpio-sleepstate-gpio-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "sleepstate"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio-sleepstate-2-out { + compatible = "qcom,smp2pgpio-sleepstate-out"; + gpios = <&smp2pgpio_sleepstate_2_out 0 0>; + }; + + smp2pgpio_smp2p_5_in: qcom,smp2pgpio-smp2p-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_5_in { + compatible = "qcom,smp2pgpio_test_smp2p_5_in"; + gpios = <&smp2pgpio_smp2p_5_in 0 0>; + }; + + smp2pgpio_smp2p_5_out: qcom,smp2pgpio-smp2p-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_5_out { + compatible = "qcom,smp2pgpio_test_smp2p_5_out"; + gpios = <&smp2pgpio_smp2p_5_out 0 0>; + }; + + /* ssr - inbound entry from lpass */ + smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to lpass */ + smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - outbound entry to mss */ + smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - inbound entry from mss */ + smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - inbound entry from mss */ + smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to mss */ + smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - inbound entry from cdsp */ + smp2pgpio_ssr_smp2p_5_in: qcom,smp2pgpio-ssr-smp2p-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to cdsp */ + smp2pgpio_ssr_smp2p_5_out: qcom,smp2pgpio-ssr-smp2p-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-stub-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-stub-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bcdc415f21db2883b7c6a57e9ad6dbd8bd69e7b7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-stub-regulator.dtsi @@ -0,0 +1,342 @@ +/* Copyright (c) 2017, 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 PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +/* Stub regulators */ + +/ { + pm660_s4: regulator-pm660-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s4"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <2040000>; + regulator-max-microvolt = <2040000>; + }; + + /* pm660 S5 - VDD_MODEM supply */ + pm660_s5_level: regulator-pm660-s5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s5_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660_s6: regulator-pm660-s6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s6"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + }; + + /* pm660l S1 - VDD_MX supply */ + pm660l_s1_level: regulator-pm660l-s1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_s1_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_s1_floor_level: regulator-pm660l-s1-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_s1_floor_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_s1_level_ao: regulator-pm660l-s1-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_s1_level_ao"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + /* pm660l S2 - VDD_GFX supply */ + pm660l_s2_level: regulator-pm660l-s2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_s2_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + /* pm660l S3 + S4 - VDD_CX supply */ + pm660l_s3_level: regulator-pm660l-s3-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_s3_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_s3_floor_level: regulator-pm660l-s3-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_s3_floor_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_s3_level_ao: regulator-pm660l-s3-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_s3_level_ao"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660_l1: regulator-pm660-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1250000>; + }; + + pm660_l2: regulator-pm660-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + pm660_l3: regulator-pm660-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + pm660_l5: regulator-pm660-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + }; + + pm660_l6: regulator-pm660-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + }; + + pm660_l7: regulator-pm660-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm660_l8: regulator-pm660-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l9: regulator-pm660-l9 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l9"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l10: regulator-pm660-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l11: regulator-pm660-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l12: regulator-pm660-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l12"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l13: regulator-pm660-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l13"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l14: regulator-pm660-l14 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l14"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm660_l15: regulator-pm660-l15 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l15"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pm660_l16: regulator-pm660-l16 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l16"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; + + pm660_l17: regulator-pm660-l17 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l17"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pm660_l19: regulator-pm660-l19 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660_l19"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; + }; + + pm660l_l1: regulator-pm660l-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <900000>; + }; + + pm660l_l2: regulator-pm660l-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l2"; + qcom,hpm-min-load = <5000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + }; + + pm660l_l3: regulator-pm660l-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3008000>; + }; + + pm660l_l4: regulator-pm660l-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + }; + + pm660l_l5: regulator-pm660l-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + }; + + pm660l_l6: regulator-pm660l-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l6"; + qcom,hpm-min-load = <5000>; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3300000>; + }; + + pm660l_l7: regulator-pm660l-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3100000>; + }; + + pm660l_l8: regulator-pm660l-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3312000>; + }; + + /* pm660l L9 = VDD_LPI_CX supply */ + pm660l_l9_level: regulator-pm660l-l9-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l9_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_l9_floor_level: regulator-pm660l-l9-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l9_floor_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + /* pm660l L10 = VDD_LPI_MX supply */ + pm660l_l10_level: regulator-pm660l-l10-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l10_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_l10_floor_level: regulator-pm660l-l10-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_l10_floor_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm660l_bob: regulator-pm660l-bob { + compatible = "qcom,stub-regulator"; + regulator-name = "pm660l_bob"; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..80d3879b1a9e622c28c95c219f080702f4599e9e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-audio-overlay.dtsi @@ -0,0 +1,80 @@ +/* Copyright (c) 2018, 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 "sdm670-audio-overlay.dtsi" + +&pmic_analog_codec { + status = "disabled"; +}; + +&msm_sdw_codec { + status = "disabled"; +}; + +&cdc_pdm_gpios { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&cdc_dmic_gpios { + status = "disabled"; +}; + +&cdc_sdw_gpios { + status = "disabled"; +}; + +&wsa_spkr_en1 { + status = "disabled"; +}; + +&wsa_spkr_en2 { + status = "disabled"; +}; + +&qupv3_se8_spi { + status = "disabled"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&clock_audio_native { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..af8244a445d71d0d0e5cc9c07d626cedb4e63778 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2018, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Tasha Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 5>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..55d2fc29c21ea0b36a0c5cbd2df081f6dd73c8c2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2018, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Tasha Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 5>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1fc0fd54437294d3296f73afd8070ddf4333cb08 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec.dtsi @@ -0,0 +1,33 @@ +/* Copyright (c) 2018, 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 "sdm670-tasha-codec-audio-overlay.dtsi" + +&int_codec { + status = "disabled"; +}; + +&pm660_div_clk { + status = "okay"; +}; + +&tasha_snd { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a0fa9cf0e757fdfe5d1b05ac512ab989c68555f4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi @@ -0,0 +1,692 @@ +/* Copyright (c) 2017-2018, 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 + +&clock_cpucc { + lmh_dcvs0: qcom,limits-dcvs@0 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + #thermal-sensor-cells = <0>; + }; + + lmh_dcvs1: qcom,limits-dcvs@1 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + #thermal-sensor-cells = <0>; + }; +}; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi_cooling_devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + aoss0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu0-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu1-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu2-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu3-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu4-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu5-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu0-gold-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu1-gold-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 12>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + aoss1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-dsp-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + ddr-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + wlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + compute-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 7>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-virt-max-step { + polling-delay-passive = <10>; + polling-delay = <100>; + thermal-governor = "step_wise"; + trips { + gpu_trip0: gpu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + gpu_cdev0 { + trip = <&gpu_trip0>; + cooling-device = + <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + hexa-silv-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + trips { + silver-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + dual-gold-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + trips { + gold-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pop-mem-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + thermal-governor = "step_wise"; + trips { + pop_trip: pop-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + pop_cdev6 { + trip = <&pop_trip>; + cooling-device = + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev7 { + trip = <&pop_trip>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; + + aoss0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + tracks-low; + trips { + aoss0_trip: aoss0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU0 2 2>; + }; + cpu6_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8) + (THERMAL_MAX_LIMIT-8)>; + }; + gpu_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&msm_gpu 0 0>; + }; + cx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + }; + }; + + aoss1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 0>; + tracks-low; + trips { + aoss1_trip: aoss1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&CPU0 2 2>; + }; + cpu6_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8) + (THERMAL_MAX_LIMIT-8)>; + }; + gpu_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&msm_gpu 0 0>; + }; + cx_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + }; + }; + + lmh-dcvs-01 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&lmh_dcvs1>; + + trips { + active-config { + temperature = <95000>; + hysteresis = <30000>; + type = "passive"; + }; + }; + }; + + lmh-dcvs-00 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&lmh_dcvs0>; + + trips { + active-config { + temperature = <95000>; + hysteresis = <30000>; + type = "passive"; + }; + }; + }; + + xo-therm-cpu-step { + polling-delay-passive = <2000>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4c>; + thermal-governor = "step_wise"; + + trips { + gold_trip0: gold-trip0 { + temperature = <45000>; + hysteresis = <0>; + type = "passive"; + }; + silver_trip1: silver-trip1 { + temperature = <50000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + skin_cpu6 { + trip = <&gold_trip0>; + cooling-device = + /* throttle from fmax to 1747200KHz */ + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-8)>; + }; + skin_cpu7 { + trip = <&gold_trip0>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-8)>; + }; + skin_cpu0 { + trip = <&silver_trip1>; + /* throttle from fmax to 1516800KHz */ + cooling-device = <&CPU0 THERMAL_NO_LIMIT 2>; + }; + skin_cpu1 { + trip = <&silver_trip1>; + cooling-device = <&CPU1 THERMAL_NO_LIMIT 2>; + }; + skin_cpu2 { + trip = <&silver_trip1>; + cooling-device = <&CPU2 THERMAL_NO_LIMIT 2>; + }; + skin_cpu3 { + trip = <&silver_trip1>; + cooling-device = <&CPU3 THERMAL_NO_LIMIT 2>; + }; + skin_cpu4 { + trip = <&silver_trip1>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT 2>; + }; + skin_cpu5 { + trip = <&silver_trip1>; + cooling-device = <&CPU5 THERMAL_NO_LIMIT 2>; + }; + }; + }; + + xo-therm-mdm-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm660_adc_tm 0x4c>; + thermal-governor = "step_wise"; + + trips { + modem_trip0: modem-trip0 { + temperature = <44000>; + hysteresis = <4000>; + type = "passive"; + }; + modem_trip1: modem-trip1 { + temperature = <46000>; + hysteresis = <3000>; + type = "passive"; + }; + modem_trip2: modem-trip2 { + temperature = <48000>; + hysteresis = <3000>; + type = "passive"; + }; + modem_trip3: modem-trip3 { + temperature = <55000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_lvl1 { + trip = <&modem_trip1>; + cooling-device = <&modem_pa 1 1>; + }; + modem_lvl2 { + trip = <&modem_trip2>; + cooling-device = <&modem_pa 2 2>; + }; + modem_lvl3 { + trip = <&modem_trip3>; + cooling-device = <&modem_pa 3 3>; + }; + modem_proc_lvl1 { + trip = <&modem_trip0>; + cooling-device = <&modem_proc 1 1>; + }; + modem_proc_lvl3 { + trip = <&modem_trip3>; + cooling-device = <&modem_proc 3 3>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..32864a084da5f7dee3874835ba7323cc7fb1f299 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017-2018, 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 "sdm845-670-usb-common.dtsi" + +&soc { + /delete-node/ ssusb@a800000; + /delete-node/ qusb@88e3000; + /delete-node/ ssphy@88eb000; + /delete-node/ usb_audio_qmi_dev; + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x180f 0x0>; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; +}; + +&usb0 { + /delete-property/ iommus; + /delete-property/ qcom,smmu-s1-bypass; + qcom,pm-qos-latency = <601>; /* CPU-CLUSTER-WFI-LVL latency +1 */ + extcon = <0>, <0>, <&eud>, <0>, <0>; +}; + +&qusb_phy0 { + vdd-supply = <&pm660l_l1>; + vdda18-supply = <&pm660_l10>; + vdda33-supply = <&pm660l_l7>; + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; + +&usb_qmp_dp_phy { + vdd-supply = <&pm660l_l1>; /* 0.88v */ + core-supply = <&pm660_l1>; /* 1.2v */ +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..e4e1db5967560d2d02f8fb87b772cf745184cb27 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..80a8423d07a638b79074907cfaa2507c7c0c5df8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c5bab55936a1943ade4d75477950da29a6fcefdc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..2c533342a28f6b3dec64afe9f49c21eae07049ef --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..09ba184fbf57436a79db6d81fe71e17b0dfa7ef1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..7a1981945069473317de4dd5864bbc97bd4535c5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..71db0f70b9d70c07dccf43a7ea846cb4f30a1a21 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts @@ -0,0 +1,36 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ff641e63c5d4e5c826e1453d3f9c9fee991c564c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c2e6f5806dd3d8e2512cf39a6110de2d579c5428 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts @@ -0,0 +1,35 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..2cd68f102bfe3615bfddd3115762e24fa6bda4a1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3d5c04ebab3f6624a1759a8ea2c5d5a6209bfaf4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..8449625b678fb6df7e7d834a7b0928afc2ef1a27 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..6a26d95dfaa145682870252b71c39be8f8747b9b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts @@ -0,0 +1,35 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..1871b45f31ce70ad36a1e87b03c6b81abe14aab0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-cdp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP"; + compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp"; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d565cddf728a0f1ca9cb13c7f424b7a25991181a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,msm-id = <336 0x0>; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..b28856957f47a0a709f5a3e5ab39504a3c49b943 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP"; + compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..01d405783b5d34f9514a06cb2ca9a9cdad53c8cf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi @@ -0,0 +1,214 @@ +/* Copyright (c) 2017, 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 +#include +#include + +&soc { + msm_vidc0: qcom,vidc0 { + compatible = "qcom,msm-vidc", "qcom,sdm670-vidc"; + status = "ok"; + sku-index = <0>; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + venus-supply = <&venus_gdsc>; + venus-core0-supply = <&vcodec0_gdsc>; + venus-core1-supply = <&vcodec1_gdsc>; + + /* Clocks */ + clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk", + "core1_clk", "core1_bus_clk"; + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC1_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC1_AXI_CLK>; + qcom,proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "core0_clk", "core0_bus_clk", + "core1_clk", "core1_bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>; + qcom,allowed-clock-rates = <100000000 200000000 320000000 + 380000000 444000000 533000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-ddr"; + qcom,bus-range-kbps = <1000 3388000>; + }; + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&apps_smmu 0x10a0 0x8>, + <&apps_smmu 0x10b0 0x0>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x6f800000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = + <&apps_smmu 0x10a1 0x8>, + <&apps_smmu 0x10a5 0x8>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = + <&apps_smmu 0x10a3 0x8>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = + <&apps_smmu 0x10a4 0x8>, + <&apps_smmu 0x10b4 0x0>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; + + msm_vidc1: qcom,vidc1 { + compatible = "qcom,msm-vidc", "qcom,sdm670-vidc"; + status = "ok"; + sku-index = <1>; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + venus-supply = <&venus_gdsc>; + venus-core0-supply = <&vcodec0_gdsc>; + + /* Clocks */ + clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk"; + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>; + qcom,proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "core0_clk", "core0_bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>; + qcom,allowed-clock-rates = <100000000 200000000 320000000 + 364700000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-ddr"; + qcom,bus-range-kbps = <1000 2128000>; + }; + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&apps_smmu 0x10a0 0x8>, + <&apps_smmu 0x10b0 0x0>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x6f800000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = + <&apps_smmu 0x10a1 0x8>, + <&apps_smmu 0x10a5 0x8>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = + <&apps_smmu 0x10a3 0x8>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = + <&apps_smmu 0x10a4 0x8>, + <&apps_smmu 0x10b4 0x0>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d7120d0a37f4add9a80943054cdf8a21751c5bf7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-wcd.dtsi @@ -0,0 +1,183 @@ +/* Copyright (c) 2017-2018, 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. + */ + +&slim_aud { + tavil_codec { + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctrl"; + qcom,num-gpios = <5>; + gpio-controller; + #gpio-cells = <2>; + + us_euro_sw_wcd_active: us_euro_sw_wcd_active { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-high; + }; + }; + + us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-low; + }; + }; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + + spkr_2_wcd_en_active: spkr_2_sd_n_active { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + output-high; + }; + }; + + spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + input-enable; + }; + }; + + hph_en0_wcd_active: hph_en0_wcd_active { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-high; + }; + }; + + hph_en0_wcd_sleep: hph_en0_wcd_sleep { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-low; + }; + }; + + hph_en1_wcd_active: hph_en1_wcd_active { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-high; + }; + }; + + hph_en1_wcd_sleep: hph_en1_wcd_sleep { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-low; + }; + }; + }; + + wsa_spkr_wcd_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_wcd_en_active>; + pinctrl-1 = <&spkr_1_wcd_en_sleep>; + }; + + wsa_spkr_wcd_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_wcd_en_active>; + pinctrl-1 = <&spkr_2_wcd_en_sleep>; + }; + + tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&us_euro_sw_wcd_active>; + pinctrl-1 = <&us_euro_sw_wcd_sleep>; + }; + + tavil_hph_en0: msm_cdc_pinctrl_hph_en0 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en0_wcd_active>; + pinctrl-1 = <&hph_en0_wcd_sleep>; + }; + + tavil_hph_en1: msm_cdc_pinctrl_hph_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en1_wcd_active>; + pinctrl-1 = <&hph_en1_wcd_sleep>; + }; + }; + + tasha_codec { + wsa_spkr_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tasha_spkr_1_sd_n_active>; + pinctrl-1 = <&tasha_spkr_1_sd_n_sleep>; + }; + + wsa_spkr_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tasha_spkr_2_sd_n_active>; + pinctrl-1 = <&tasha_spkr_2_sd_n_sleep>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5dfe24437edf0389b54ca16e5881a5b522c1800d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670-wsa881x.dtsi @@ -0,0 +1,77 @@ +/* Copyright (c) 2017-2018, 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. + */ + +&slim_aud { + tavil_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; + }; + + tasha_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd1>; + }; + + wsa881x_212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd2>; + }; + + wsa881x_213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd1>; + }; + + wsa881x_214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dts b/arch/arm64/boot/dts/qcom/sdm670.dts new file mode 100644 index 0000000000000000000000000000000000000000..1d5e5e0c3f22e52675f5a4ad212003bc83223f2f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sdm670.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM670 SoC"; + compatible = "qcom,sdm670"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9bc083f606ec186a9705fed406af13a314cc0ed0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -0,0 +1,3025 @@ +/* Copyright (c) 2017-2018, 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 "skeleton64.dtsi" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) + +/ { + model = "Qualcomm Technologies, Inc. SDM670"; + compatible = "qcom,sdm670"; + qcom,msm-id = <336 0x0>; + interrupt-parent = <&pdc>; + + aliases { + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + serial0 = &qupv3_se12_2uart; + spi0 = &qupv3_se8_spi; + i2c0 = &qupv3_se10_i2c; + i2c1 = &qupv3_se3_i2c; + hsuart0 = &qupv3_se6_4uart; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 core_ctl_disable_cpumask=6-7"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x10000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_0>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + L3_0: l3-cache { + compatible = "arm,arch-cache"; + cache-size = <0x100000>; + cache-level = <3>; + }; + }; + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x3000>; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x10000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_100>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_100: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x3000>; + }; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x200>; + enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x10000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_200>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_200: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_200: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_200: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_200: l1-tlb { + qcom,dump-size = <0x3000>; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x300>; + enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x10000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_300>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_300: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_300: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_300: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_300: l1-tlb { + qcom,dump-size = <0x3000>; + }; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x400>; + enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x10000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_400>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_400: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_400: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_400: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_400: l1-tlb { + qcom,dump-size = <0x3000>; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x500>; + enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x10000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_500>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_500: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_500: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_500: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_500: l1-tlb { + qcom,dump-size = <0x3000>; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x600>; + enable-method = "psci"; + efficiency = <1740>; + cache-size = <0x20000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_600>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + L2_600: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x40000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_600: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x24000>; + }; + L1_D_600: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + L1_TLB_600: l1-tlb { + qcom,dump-size = <0x3c000>; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x700>; + enable-method = "psci"; + efficiency = <1740>; + cache-size = <0x20000>; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_700>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + L2_700: l2-cache { + compatible = "arm,arch-cache"; + cache-size = <0x40000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_700: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x24000>; + }; + L1_D_700: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + L1_TLB_700: l1-tlb { + qcom,dump-size = <0x3c000>; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + + core4 { + cpu = <&CPU4>; + }; + + core5 { + cpu = <&CPU5>; + }; + }; + cluster1 { + core0 { + cpu = <&CPU6>; + }; + + core1 { + cpu = <&CPU7>; + }; + }; + }; + }; + + energy_costs: energy-costs { + compatible = "sched-energy"; + + CPU_COST_0: core-cost0 { + busy-cost-data = < + 300000 14 + 576000 25 + 748800 31 + 998400 46 + 1209600 57 + 1324800 84 + 1516800 96 + 1612800 114 + 1708800 139 + >; + idle-cost-data = < + 12 10 8 6 + >; + }; + CPU_COST_1: core-cost1 { + busy-cost-data = < + 300000 256 + 652800 307 + 825600 332 + 979200 382 + 1132800 408 + 1363200 448 + 1536000 586 + 1747200 641 + 1843200 659 + 1996800 696 + 2054400 876 + 2169600 900 + 2208000 924 + 2361600 948 + 2400000 1170 + 2457600 1200 + 2515200 1300 + 2611200 1400 + >; + idle-cost-data = < + 100 80 60 40 + >; + }; + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 300000 5 + 576000 7 + 748800 8 + 998400 9 + 1209600 10 + 1324800 13 + 1516800 15 + 1612800 16 + 1708800 19 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 300000 25 + 652800 30 + 825600 33 + 979200 38 + 1132800 40 + 1363200 44 + 1536000 58 + 1747200 64 + 1843200 65 + 1996800 69 + 2054400 87 + 2169600 90 + 2208000 92 + 2361600 94 + 2400000 117 + 2457600 120 + 2515200 130 + 2611200 140 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + soc: soc { }; + + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + }; + }; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_region: hyp_region@85700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x85700000 0 0x600000>; + }; + + xbl_region: xbl_region@85e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x85e00000 0 0x100000>; + }; + + removed_region: removed_region@85fc0000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x85fc0000 0 0x2f40000>; + }; + + pil_camera_mem: camera_region@8ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8ab00000 0 0x500000>; + }; + + pil_modem_mem: modem_region@8b000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8b000000 0 0x7e00000>; + }; + + pil_video_mem: pil_video_region@92e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x92e00000 0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@93300000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x93300000 0 0x100000>; + }; + + pil_cdsp_mem: cdsp_regions@93400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x93400000 0 0x800000>; + }; + + pil_mba_mem: pil_mba_region@0x93c00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x93c00000 0 0x200000>; + }; + + pil_adsp_mem: pil_adsp_region@93e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x93e00000 0 0x1e00000>; + }; + + pil_ipa_fw_mem: ips_fw_region@0x95c00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x95c00000 0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@0x95c10000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x95c10000 0 0x5000>; + }; + + pil_gpu_mem: gpu_region@0x95c15000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x95c15000 0 0x2000>; + }; + + qseecom_mem: qseecom_region@0x9e400000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0 0x9e400000 0 0x1400000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0xc00000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + }; + + sp_mem: sp_region { /* SPSS-HLOS ION shared mem */ + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; /* 32-bit */ + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + + secure_display_memory: secure_display_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x5c00000>; + }; + + cont_splash_memory: cont_splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x02400000>; + label = "cont_splash_region"; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + reusable; + size = <0 0x2400000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x2000000>; + linux,cma-default; + }; + }; +}; + +#include "sdm670-ion.dtsi" + +#include "sdm670-smp2p.dtsi" + +#include "msm-rdbg.dtsi" + +#include "sdm670-qupv3.dtsi" + +#include "sdm670-coresight.dtsi" + +#include "sdm670-vidc.dtsi" + +#include "sdm670-sde-pll.dtsi" + +#include "sdm670-sde.dtsi" + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + interrupt-parent = <&intc>; + }; + + pdc: interrupt-controller@b220000{ + compatible = "qcom,pdc-sdm670"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-boot-time; + label = "modem"; + }; + }; + + qcom,sps { + compatible = "qcom,msm_sps_4k"; + qcom,pipe-attr-ee; + }; + + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,request-bw-before-clk; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x706 0x1>, + <&apps_smmu 0x716 0x1>; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,request-bw-before-clk; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x704 0x1>, + <&apps_smmu 0x714 0x1>; + }; + + qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clock-frequency = <25000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&tlmm 122 0>; + }; + + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 0x2200000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + qcom,appsbl-qseecom-support; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 200000 400000>, + <125 512 300000 800000>, + <125 512 400000 1000000>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_tzlog: tz-log@146bf720 { + compatible = "qcom,tz-log"; + reg = <0x146bf720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_rng: qrng@793000{ + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 800>; /* 100 KHz */ + clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + + thermal_zones: thermal-zones {}; + + tsens0: tsens@c222000 { + compatible = "qcom,tsens24xx"; + reg = <0xc222000 0x4>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 506 0>, <0 508 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: tsens@c223000 { + compatible = "qcom,tsens24xx"; + reg = <0xc223000 0x4>, + <0xc265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 507 0>, <0 509 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + timer@0x17c90000{ + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c90000 0x1000>; + clock-frequency = <19200000>; + + frame@0x17ca0000 { + frame-number = <0>; + interrupts = <0 7 0x4>, + <0 6 0x4>; + reg = <0x17ca0000 0x1000>, + <0x17cb0000 0x1000>; + }; + + frame@17cc0000 { + frame-number = <1>; + interrupts = <0 8 0x4>; + reg = <0x17cc0000 0x1000>; + status = "disabled"; + }; + + frame@17cd0000 { + frame-number = <2>; + interrupts = <0 9 0x4>; + reg = <0x17cd0000 0x1000>; + status = "disabled"; + }; + + frame@17ce0000 { + frame-number = <3>; + interrupts = <0 10 0x4>; + reg = <0x17ce0000 0x1000>; + status = "disabled"; + }; + + frame@17cf0000 { + frame-number = <4>; + interrupts = <0 11 0x4>; + reg = <0x17cf0000 0x1000>; + status = "disabled"; + }; + + frame@17d00000 { + frame-number = <5>; + interrupts = <0 12 0x4>; + reg = <0x17d00000 0x1000>; + status = "disabled"; + }; + + frame@17d10000 { + frame-number = <6>; + interrupts = <0 13 0x4>; + reg = <0x17d10000 0x1000>; + status = "disabled"; + }; + }; + + restart@10ac000 { + compatible = "qcom,pshold"; + reg = <0xC264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sdm670"; + #clock-cells = <1>; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + }; + + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-sdm670", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm660l_s3_level>; + vdd_cx_ao-supply = <&pm660l_s3_level_ao>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_videocc: qcom,videocc@ab00000 { + compatible = "qcom,video_cc-sdm670", "syscon"; + reg = <0xab00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm660l_s3_level>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_camcc: qcom,camcc@ad00000 { + compatible = "qcom,cam_cc-sdm670", "syscon"; + reg = <0xad00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm660l_s3_level>; + vdd_mx-supply = <&pm660l_s1_level>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_dispcc: qcom,dispcc@af00000 { + compatible = "qcom,dispcc-sdm670", "syscon"; + reg = <0xaf00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm660l_s3_level>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gpucc: qcom,gpucc@5090000 { + compatible = "qcom,gpucc-sdm670", "syscon"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm660l_s3_level>; + vdd_mx-supply = <&pm660l_s1_level>; + qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gfx: qcom,gfxcc@5090000 { + compatible = "qcom,gfxcc-sdm670"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_gfx-supply = <&pm660l_s2_level>; + qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cpucc_debug: syscon@17970018 { + compatible = "syscon"; + reg = <0x17970018 0x4>; + }; + + clock_debug: qcom,cc-debug { + compatible = "qcom,debugcc-sdm845"; + qcom,cc-count = <5>; + qcom,gcc = <&clock_gcc>; + qcom,videocc = <&clock_videocc>; + qcom,camcc = <&clock_camcc>; + qcom,dispcc = <&clock_dispcc>; + qcom,gpucc = <&clock_gpucc>; + qcom,cpucc = <&cpucc_debug>; + clock-names = "xo_clk_src"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + #clock-cells = <1>; + }; + + clock_cpucc: qcom,cpucc@0x17d41000 { + compatible = "qcom,clk-cpu-osm-sdm670"; + reg = <0x17d41000 0x1400>, + <0x17d43000 0x1400>, + <0x17d45800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base"; + vdd_l3_mx_ao-supply = <&pm660l_s1_level_ao>; + vdd_pwrcl_mx_ao-supply = <&pm660l_s1_level_ao>; + + qcom,mx-turbo-freq = <1440000000 1708000000 3300000001>; + l3-devs = <&l3_cpu0 &l3_cpu6 &l3_cdsp>; + + clock-names = "xo_ao"; + clocks = <&clock_rpmh RPMH_CXO_CLK_A>; + #clock-cells = <1>; + }; + + clock_aop: qcom,aopclk { + compatible = "qcom,aop-qmp-clk-v1"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + }; + + slim_aud: slim@62dc0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x62dc0000 0x2c000>, + <0x62d84000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0>, <0 164 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x780000>; + qcom,ea-pc = <0x290>; + status = "disabled"; + qcom,iommu-s1-bypass; + + iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1826 0x0>, + <&apps_smmu 0x182d 0x0>, + <&apps_smmu 0x182e 0x1>, + <&apps_smmu 0x1830 0x1>; + }; + + }; + + slim_qca: slim@62e40000 { + cell-index = <3>; + compatible = "qcom,slim-ngd"; + reg = <0x62e40000 0x2c000>, + <0x62e04000 0x20000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 291 0>, <0 292 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + status = "ok"; + qcom,iommu-s1-bypass; + + iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1833 0x0>; + }; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + wdog: qcom,wdt@17980000{ + compatible = "qcom,msm-watchdog"; + reg = <0x17980000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 0 0>, <0 1 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,mpm2-sleep-counter@c221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x0c221000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,msm-imem@146bf000 { + compatible = "qcom,msm-imem"; + reg = <0x146bf000 0x1000>; + ranges = <0x0 0x146bf000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 0x20>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 0xc8>; + }; + }; + + gpi_dma0: qcom,gpi-dma@0x800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, + <0 252 0>, <0 253 0>, <0 254 0>, <0 255 0>, + <0 256 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x0016 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; + }; + + gpi_dma1: qcom,gpi-dma@0xa00000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0xa00000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 279 0>, <0 280 0>, <0 281 0>, <0 282 0>, + <0 283 0>, <0 284 0>, <0 293 0>, <0 294 0>, + <0 295 0>, <0 296 0>, <0 297 0>, <0 298 0>, + <0 299 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + iommus = <&apps_smmu 0x06d6 0x0>; + status = "ok"; + }; + + cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,l1_i_cache0 { + qcom,dump-node = <&L1_I_0>; + qcom,dump-id = <0x60>; + }; + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x61>; + }; + qcom,l1_i_cache200 { + qcom,dump-node = <&L1_I_200>; + qcom,dump-id = <0x62>; + }; + qcom,l1_i_cache300 { + qcom,dump-node = <&L1_I_300>; + qcom,dump-id = <0x63>; + }; + qcom,l1_i_cache400 { + qcom,dump-node = <&L1_I_400>; + qcom,dump-id = <0x64>; + }; + qcom,l1_i_cache500 { + qcom,dump-node = <&L1_I_500>; + qcom,dump-id = <0x65>; + }; + qcom,l1_i_cache600 { + qcom,dump-node = <&L1_I_600>; + qcom,dump-id = <0x66>; + }; + qcom,l1_i_cache700 { + qcom,dump-node = <&L1_I_700>; + qcom,dump-id = <0x67>; + }; + qcom,l1_d_cache0 { + qcom,dump-node = <&L1_D_0>; + qcom,dump-id = <0x80>; + }; + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x81>; + }; + qcom,l1_d_cache200 { + qcom,dump-node = <&L1_D_200>; + qcom,dump-id = <0x82>; + }; + qcom,l1_d_cache300 { + qcom,dump-node = <&L1_D_300>; + qcom,dump-id = <0x83>; + }; + qcom,l1_d_cache400 { + qcom,dump-node = <&L1_D_400>; + qcom,dump-id = <0x84>; + }; + qcom,l1_d_cache500 { + qcom,dump-node = <&L1_D_500>; + qcom,dump-id = <0x85>; + }; + qcom,l1_d_cache600 { + qcom,dump-node = <&L1_D_600>; + qcom,dump-id = <0x86>; + }; + qcom,l1_d_cache700 { + qcom,dump-node = <&L1_D_700>; + qcom,dump-id = <0x87>; + }; + qcom,llcc1_d_cache { + qcom,dump-node = <&LLCC_1>; + qcom,dump-id = <0x140>; + }; + qcom,llcc2_d_cache { + qcom,dump-node = <&LLCC_2>; + qcom,dump-id = <0x141>; + }; + qcom,l1_tlb_dump0 { + qcom,dump-node = <&L1_TLB_0>; + qcom,dump-id = <0x20>; + }; + qcom,l1_tlb_dump100 { + qcom,dump-node = <&L1_TLB_100>; + qcom,dump-id = <0x21>; + }; + qcom,l1_tlb_dump200 { + qcom,dump-node = <&L1_TLB_200>; + qcom,dump-id = <0x22>; + }; + qcom,l1_tlb_dump300 { + qcom,dump-node = <&L1_TLB_300>; + qcom,dump-id = <0x23>; + }; + qcom,l1_tlb_dump400 { + qcom,dump-node = <&L1_TLB_400>; + qcom,dump-id = <0x24>; + }; + qcom,l1_tlb_dump500 { + qcom,dump-node = <&L1_TLB_500>; + qcom,dump-id = <0x25>; + }; + qcom,l1_tlb_dump600 { + qcom,dump-node = <&L1_TLB_600>; + qcom,dump-id = <0x26>; + }; + qcom,l1_tlb_dump700 { + qcom,dump-node = <&L1_TLB_700>; + qcom,dump-id = <0x27>; + }; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xe4>; + }; + + tmc_etf { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf0>; + }; + + tmc_etfswao { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xf1>; + }; + + tmc_etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + tmc_etf_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x101>; + }; + + etfswao_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + + power_regs { + qcom,dump-size = <0x100000>; + qcom,dump-id = <0xed>; + }; + }; + + kryo3xx-erp { + compatible = "arm,arm64-kryo3xx-cpu-erp"; + interrupts = <1 6 4>, + <1 7 4>, + <0 34 4>, + <0 35 4>; + + interrupt-names = "l1-l2-faultirq", + "l1-l2-errirq", + "l3-scu-errirq", + "l3-scu-faultirq"; + }; + + qcom,ipc-spinlock@1f40000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1f40000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,smem@86000000 { + compatible = "qcom,smem"; + reg = <0x86000000 0x200000>, + <0x17911008 0x4>, + <0x778000 0x7000>, + <0x1fd4000 0x8>; + reg-names = "smem", "irq-reg-base", "aux-mem1", + "smem_targ_info_reg"; + qcom,mpu-enabled; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + label = "aop"; + reg = <0xc300000 0x100000>, + <0x1799000c 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x1>; + interrupts = <0 389 1>; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + qcom,glink-smem-native-xprt-modem@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x1000>; + interrupts = ; + label = "mpss"; + }; + + qcom,glink-smem-native-xprt-adsp@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x1000000>; + interrupts = ; + label = "lpass"; + qcom,qos-config = <&glink_qos_adsp>; + qcom,ramp-time = <0xaf>; + }; + + glink_qos_adsp: qcom,glink-qos-config-adsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x3c 0x0>, + <0x3c 0x0>, + <0x3c 0x0>, + <0x3c 0x0>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + + glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp { + compatible = "qcom,glink-spi-xprt"; + label = "wdsp"; + qcom,remote-fifo-config = <&glink_fifo_wdsp>; + qcom,qos-config = <&glink_qos_wdsp>; + qcom,ramp-time = <0x10>, + <0x20>, + <0x30>, + <0x40>; + }; + + glink_fifo_wdsp: qcom,glink-fifo-config-wdsp { + compatible = "qcom,glink-fifo-config"; + qcom,out-read-idx-reg = <0x12000>; + qcom,out-write-idx-reg = <0x12004>; + qcom,in-read-idx-reg = <0x1200C>; + qcom,in-write-idx-reg = <0x12010>; + }; + + glink_qos_wdsp: qcom,glink-qos-config-wdsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x80 0x0>, + <0x70 0x1>, + <0x60 0x2>, + <0x50 0x3>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + + qcom,glink-smem-native-xprt-cdsp@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x10>; + interrupts = ; + label = "cdsp"; + }; + + glink_mpss: qcom,glink-ssr-modem { + compatible = "qcom,glink_ssr"; + label = "modem"; + qcom,edge = "mpss"; + qcom,notify-edges = <&glink_lpass>, <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_lpass: qcom,glink-ssr-adsp { + compatible = "qcom,glink_ssr"; + label = "adsp"; + qcom,edge = "lpass"; + qcom,notify-edges = <&glink_mpss>, <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_cdsp: qcom,glink-ssr-cdsp { + compatible = "qcom,glink_ssr"; + label = "cdsp"; + qcom,edge = "cdsp"; + qcom,notify-edges = <&glink_mpss>, <&glink_lpass>; + qcom,xprt = "smem"; + }; + + qcom,ipc_router { + compatible = "qcom,ipc_router"; + qcom,node-id = <1>; + }; + + qcom,ipc_router_modem_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "mpss"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,ipc_router_q6_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "lpass"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,ipc_router_cdsp_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "cdsp"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-loopback_cntl { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl"; + }; + + qcom,glinkpkt-loopback_data { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,chd_sliver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x17e00058 0x17e10058 0x17e20058 + 0x17e30058 0x17e40058 0x17e50058>; + qcom,config-arr = <0x17e00060 0x17e10060 0x17e20060 + 0x17e30060 0x17e40060 0x17e50060>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x17e60058 0x17e70058>; + qcom,config-arr = <0x17e60060 0x17e70060>; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect-v2"; + qcom,threshold-arr = <0x1799041c 0x17990420>; + qcom,config-reg = <0x17990434>; + }; + + qcom,msm-gladiator-v3@17900000 { + compatible = "qcom,msm-gladiator-v3"; + reg = <0x17900000 0xd080>; + reg-names = "gladiator_base"; + interrupts = <0 17 0>; + }; + + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x88e0000 0x2000>; + reg-names = "eud_base"; + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "cfg_ahb_clk"; + }; + + qcom,llcc@1100000 { + compatible = "qcom,llcc-core", "syscon", "simple-mfd"; + reg = <0x1100000 0x250000>; + reg-names = "llcc_base"; + qcom,llcc-banks-off = <0x0 0x80000 >; + qcom,llcc-broadcast-off = <0x200000>; + + llcc: qcom,sdm670-llcc { + compatible = "qcom,sdm670-llcc"; + #cache-cells = <1>; + max-slices = <32>; + qcom,dump-size = <0x80000>; + }; + + qcom,llcc-perfmon { + compatible = "qcom,llcc-perfmon"; + }; + + qcom,llcc-erp { + compatible = "qcom,llcc-erp"; + interrupt-names = "ecc_irq"; + interrupts = ; + }; + + qcom,llcc-amon { + compatible = "qcom,llcc-amon"; + }; + + LLCC_1: llcc_1_dcache { + qcom,dump-size = <0xd8000>; + }; + + LLCC_2: llcc_2_dcache { + qcom,dump-size = <0xd8000>; + }; + }; + + cmd_db: qcom,cmd-db@c3f000c { + compatible = "qcom,cmd-db"; + reg = <0xc3f000c 0x8>; + }; + + apps_rsc: mailbox@179e0000 { + compatible = "qcom,tcs-drv"; + label = "apps_rsc"; + reg = <0x179e0000 0x100>, <0x179e0d00 0x3000>; + interrupts = <0 5 0>; + #mbox-cells = <1>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + }; + + disp_rsc: mailbox@af20000 { + compatible = "qcom,tcs-drv"; + label = "display_rsc"; + reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>; + interrupts = <0 129 0>; + #mbox-cells = <1>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + }; + + system_pm { + compatible = "qcom,system-pm"; + mboxes = <&apps_rsc 0>; + }; + + dcc: dcc_v2@10a2000 { + compatible = "qcom,dcc_v2"; + reg = <0x10a2000 0x1000>, + <0x10ae000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + + dcc-ram-offset = <0x6000>; + }; + + spmi_bus: qcom,spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0x1100>, + <0xc600000 0x2000000>, + <0xe600000 0x100000>, + <0xe700000 0xa0000>, + <0xc40a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + ufs_ice: ufsice@1d90000 { + compatible = "qcom,ice"; + reg = <0x1d90000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_phy_gdsc>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + reg = <0x1d87000 0xe00>; /* PHY regs */ + reg-names = "phy_mem"; + #phy-cells = <0>; + + lanes-per-direction = <1>; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK>; + + status = "disabled"; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x3000>; + interrupts = <0 265 0>; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; + + lanes-per-direction = <1>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + + 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_PHY_AXI_HW_CTL_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + + non-removable; + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 7643136 0>, <1 757 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"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x3f 0xC0>; + qcom,pm-qos-cpu-group-latency-us = <70 70>; + qcom,pm-qos-default-cpu = <0>; + + resets = <&clock_gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + + status = "disabled"; + }; + + qcom,lpass@62400000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x62400000 0x00100>; + interrupts = <0 162 1>; + + vdd_cx-supply = <&pm660l_l9_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + qcom,signal-aop; + memory-region = <&pil_adsp_mem>; + + /* GPIO inputs from lpass */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>; + + /* GPIO output to lpass */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; + status = "ok"; + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-loaduC; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + ipa_hw: qcom,ipa@01e00000 { + compatible = "qcom,ipa"; + reg = <0x1e00000 0x34000>, + <0x1e04000 0x2c000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = + <0 311 0>, + <0 432 0>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <13>; /* IPA core version = IPAv3.5.1 */ + qcom,ipa-hw-mode = <1>; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,use-64-bit-dma-mask; + qcom,arm-smmu; + qcom,bandwidth-vote-for-ipa; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <4>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <90 512 0 0>, + <90 585 0 0>, + <1 676 0 0>, + <143 777 0 0>, + /* SVS2 */ + <90 512 80000 600000>, + <90 585 80000 350000>, + <1 676 40000 40000>, /*gcc_config_noc_clk_src */ + <143 777 0 75>, /* IB defined for IPA2X_clk in MHz*/ + /* SVS */ + <90 512 80000 640000>, + <90 585 80000 640000>, + <1 676 80000 80000>, + <143 777 0 150>, /* IB defined for IPA2X_clk in MHz*/ + /* NOMINAL */ + <90 512 206000 960000>, + <90 585 206000 960000>, + <1 676 206000 160000>, + <143 777 0 300>, /* IB defined for IPA2X_clk in MHz*/ + /* TURBO */ + <90 512 206000 3600000>, + <90 585 206000 3600000>, + <1 676 206000 300000>, + <143 777 0 355>; /* IB defined for IPA clk in MHz*/ + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + + /* IPA RAM mmap */ + qcom,ipa-ram-mmap = < + 0x280 /* ofst_start; */ + 0x0 /* nat_ofst; */ + 0x0 /* nat_size; */ + 0x288 /* v4_flt_hash_ofst; */ + 0x78 /* v4_flt_hash_size; */ + 0x4000 /* v4_flt_hash_size_ddr; */ + 0x308 /* v4_flt_nhash_ofst; */ + 0x78 /* v4_flt_nhash_size; */ + 0x4000 /* v4_flt_nhash_size_ddr; */ + 0x388 /* v6_flt_hash_ofst; */ + 0x78 /* v6_flt_hash_size; */ + 0x4000 /* v6_flt_hash_size_ddr; */ + 0x408 /* v6_flt_nhash_ofst; */ + 0x78 /* v6_flt_nhash_size; */ + 0x4000 /* v6_flt_nhash_size_ddr; */ + 0xf /* v4_rt_num_index; */ + 0x0 /* v4_modem_rt_index_lo; */ + 0x7 /* v4_modem_rt_index_hi; */ + 0x8 /* v4_apps_rt_index_lo; */ + 0xe /* v4_apps_rt_index_hi; */ + 0x488 /* v4_rt_hash_ofst; */ + 0x78 /* v4_rt_hash_size; */ + 0x4000 /* v4_rt_hash_size_ddr; */ + 0x508 /* v4_rt_nhash_ofst; */ + 0x78 /* v4_rt_nhash_size; */ + 0x4000 /* v4_rt_nhash_size_ddr; */ + 0xf /* v6_rt_num_index; */ + 0x0 /* v6_modem_rt_index_lo; */ + 0x7 /* v6_modem_rt_index_hi; */ + 0x8 /* v6_apps_rt_index_lo; */ + 0xe /* v6_apps_rt_index_hi; */ + 0x588 /* v6_rt_hash_ofst; */ + 0x78 /* v6_rt_hash_size; */ + 0x4000 /* v6_rt_hash_size_ddr; */ + 0x608 /* v6_rt_nhash_ofst; */ + 0x78 /* v6_rt_nhash_size; */ + 0x4000 /* v6_rt_nhash_size_ddr; */ + 0x688 /* modem_hdr_ofst; */ + 0x140 /* modem_hdr_size; */ + 0x7c8 /* apps_hdr_ofst; */ + 0x0 /* apps_hdr_size; */ + 0x800 /* apps_hdr_size_ddr; */ + 0x7d0 /* modem_hdr_proc_ctx_ofst; */ + 0x200 /* modem_hdr_proc_ctx_size; */ + 0x9d0 /* apps_hdr_proc_ctx_ofst; */ + 0x200 /* apps_hdr_proc_ctx_size; */ + 0x0 /* apps_hdr_proc_ctx_size_ddr; */ + 0x0 /* modem_comp_decomp_ofst; diff */ + 0x0 /* modem_comp_decomp_size; diff */ + 0xbd8 /* modem_ofst; */ + 0x1024 /* modem_size; */ + 0x2000 /* apps_v4_flt_hash_ofst; */ + 0x0 /* apps_v4_flt_hash_size; */ + 0x2000 /* apps_v4_flt_nhash_ofst; */ + 0x0 /* apps_v4_flt_nhash_size; */ + 0x2000 /* apps_v6_flt_hash_ofst; */ + 0x0 /* apps_v6_flt_hash_size; */ + 0x2000 /* apps_v6_flt_nhash_ofst; */ + 0x0 /* apps_v6_flt_nhash_size; */ + 0x80 /* uc_info_ofst; */ + 0x200 /* uc_info_size; */ + 0x2000 /* end_ofst; */ + 0x2000 /* apps_v4_rt_hash_ofst; */ + 0x0 /* apps_v4_rt_hash_size; */ + 0x2000 /* apps_v4_rt_nhash_ofst; */ + 0x0 /* apps_v4_rt_nhash_size; */ + 0x2000 /* apps_v6_rt_hash_ofst; */ + 0x0 /* apps_v6_rt_hash_size; */ + 0x2000 /* apps_v6_rt_nhash_ofst; */ + 0x0 /* apps_v6_rt_nhash_size; */ + 0x1c00 /* uc_event_ring_ofst; */ + 0x400 /* uc_event_ring_size; */ + >; + + /* smp2p gpio information */ + qcom,smp2pgpio_map_ipa_1_out { + compatible = "qcom,smp2pgpio-map-ipa-1-out"; + gpios = <&smp2pgpio_ipa_1_out 0 0>; + }; + + qcom,smp2pgpio_map_ipa_1_in { + compatible = "qcom,smp2pgpio-map-ipa-1-in"; + gpios = <&smp2pgpio_ipa_1_in 0 0>; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x720 0x0>; + qcom,iova-mapping = <0x20000000 0x40000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x721 0x0>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x722 0x0>; + qcom,iova-mapping = <0x40000000 0x20000000>; + }; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-q6v55-mss"; + reg = <0x4080000 0x100>, + <0x1f63000 0x008>, + <0x1f65000 0x008>, + <0x1f64000 0x008>, + <0x4180000 0x020>, + <0xc2b0000 0x004>, + <0xb2e0100 0x004>, + <0x4180044 0x004>; + reg-names = "qdsp6_base", "halt_q6", "halt_modem", + "halt_nc", "rmb_base", "restart_reg", + "pdc_sync", "alt_reset"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_MSS_CFG_AHB_CLK>, + <&clock_gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>, + <&clock_gcc GCC_BOOT_ROM_AHB_CLK>, + <&clock_gcc GCC_MSS_GPLL0_DIV_CLK_SRC>, + <&clock_gcc GCC_MSS_SNOC_AXI_CLK>, + <&clock_gcc GCC_MSS_MFAB_AXIS_CLK>, + <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "xo", "iface_clk", "bus_clk", + "mem_clk", "gpll0_mss_clk", "snoc_axi_clk", + "mnoc_axi_clk", "prng_clk"; + qcom,proxy-clock-names = "xo", "prng_clk"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk", + "gpll0_mss_clk", "snoc_axi_clk", + "mnoc_axi_clk"; + + interrupts = <0 266 1>; + vdd_cx-supply = <&pm660l_s3_level>; + vdd_cx-voltage = ; + vdd_mx-supply = <&pm660l_s1_level>; + vdd_mx-uV = ; + vdd_mss-supply = <&pm660_s5_level>; + vdd_mss-uV = ; + qcom,firmware-name = "modem"; + qcom,pil-self-auth; + qcom,sysmon-id = <0>; + qcom,minidump-id = <3>; + qcom,ssctl-instance-id = <0x12>; + qcom,override-acc; + qcom,signal-aop; + qcom,qdsp6v65-1-0; + qcom,mss_pdc_offset = <9>; + status = "ok"; + memory-region = <&pil_modem_mem>; + qcom,mem-protect-id = <0xF>; + + /* GPIO inputs from mss */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>; + qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>; + + /* GPIO output to mss */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "mss-pil"; + qcom,mba-mem@0 { + compatible = "qcom,pil-mba-mem"; + memory-region = <&pil_mba_mem>; + }; + }; + + qcom,venus@aae0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xaae0000 0x4000>; + + vdd-supply = <&venus_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; + clock-names = "core_clk", "iface_clk", "bus_clk"; + qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk"; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + status = "ok"; + }; + + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + interrupts = <0 578 1>; + + vdd_cx-supply = <&pm660l_s3_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + qcom,signal-aop; + memory-region = <&pil_cdsp_mem>; + + /* GPIO inputs from turing */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_5_in 0 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_5_in 2 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_5_in 1 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_5_in 3 0>; + + /* GPIO output to turing*/ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; + status = "ok"; + }; + + sdcc1_ice: sdcc1ice@7c8000 { + compatible = "qcom,ice"; + reg = <0x7c8000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ice_core_clk_src", "ice_core_clk", + "bus_clk", "iface_clk"; + clocks = <&clock_gcc GCC_SDCC1_ICE_CORE_CLK_SRC>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_AHB_CLK>; + qcom,op-freq-hz = <300000000>, <0>, <0>, <0>; + qcom,msm-bus,name = "sdcc_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <150 512 0 0>, /* No vote */ + <150 512 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "sdcc"; + }; + + sdhc_1: sdhci@7c4000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x7C4000 0x1000>, <0x7C5000 0x1000>; + reg-names = "hc_mem", "cmdq_mem"; + + interrupts = <0 641 0>, <0 644 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + sdhc-msm-crypto = <&sdcc1_ice>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-aggr-clk-rates = <50000000 50000000 50000000 50000000 + 100000000 200000000 200000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <150 512 0 0>, <1 782 0 0>, + /* 400 KB/s*/ + <150 512 1046 1600>, + <1 782 1600 1600>, + /* 20 MB/s */ + <150 512 52286 80000>, + <1 782 80000 80000>, + /* 25 MB/s */ + <150 512 65360 100000>, + <1 782 100000 100000>, + /* 50 MB/s */ + <150 512 130718 200000>, + <1 782 100000 100000>, + /* 100 MB/s */ + <150 512 130718 200000>, + <1 782 130000 130000>, + /* 200 MB/s */ + <150 512 261438 400000>, + <1 782 300000 300000>, + /* 400 MB/s */ + <150 512 261438 400000>, + <1 782 300000 300000>, + /* Max. bandwidth */ + <150 512 1338562 4096000>, + <1 782 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <70 70>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-cmdq-latency-us = <70 70>, <70 70>; + qcom,pm-qos-legacy-latency-us = <70 70>, <70 70>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk", + "bus_aggr_clk"; + + qcom,ice-clk-rates = <300000000 75000000>; + + qcom,ddr-config = <0xC3040873>; + + qcom,nonremovable; + nvmem-cells = <&minor_rev>; + nvmem-cell-names = "minor_rev"; + + status = "disabled"; + }; + + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 204 0>, <0 222 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 201500000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 201500000>; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 1600>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 80000>, + <1 608 80000 80000>, + /* 25 MB/s */ + <81 512 65360 100000>, + <1 608 100000 100000>, + /* 50 MB/s */ + <81 512 130718 200000>, + <1 608 100000 100000>, + /* 100 MB/s */ + <81 512 261438 200000>, + <1 608 130000 130000>, + /* 200 MB/s */ + <81 512 261438 400000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <70 70>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <70 70>, <70 70>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + status = "disabled"; + }; + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1421 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1422 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1423 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1424 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1425 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1426 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1429 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x142A 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1803 0x0>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1804 0x0>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1805 0x0>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1806 0x0>; + dma-coherent; + }; + }; + + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-core-supply = <&pm660_l9>; + qca,bt-vdd-pa-supply = <&pm660_l6>; + qca,bt-vdd-ldo-supply = <&pm660_l19>; + + 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-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 */ + }; + + qcom,icnss@18800000 { + compatible = "qcom,icnss"; + reg = <0x18800000 0x800000>, + <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x0040 0x1>; + interrupts = <0 414 0 /* CE0 */ >, + <0 415 0 /* CE1 */ >, + <0 416 0 /* CE2 */ >, + <0 417 0 /* CE3 */ >, + <0 418 0 /* CE4 */ >, + <0 419 0 /* CE5 */ >, + <0 420 0 /* CE6 */ >, + <0 421 0 /* CE7 */ >, + <0 422 0 /* CE8 */ >, + <0 423 0 /* CE9 */ >, + <0 424 0 /* CE10 */ >, + <0 425 0 /* CE11 */ >; + vdd-0.8-cx-mx-supply = <&pm660_l5>; + vdd-1.8-xo-supply = <&pm660_l9>; + vdd-1.3-rfa-supply = <&pm660_l6>; + vdd-3.3-ch0-supply = <&pm660_l19>; + qcom,vdd-3.3-ch0-config = <3000000 3312000>; + qcom,wlan-msa-memory = <0x100000>; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; + qcom,smmu-s1-bypass; + }; + + cpubw: qcom,cpubw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */ + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + bwmon: qcom,cpu-bwmon { + compatible = "qcom,bimc-bwmon4"; + reg = <0x1436400 0x300>, <0x1436300 0x200>; + reg-names = "base", "global_base"; + interrupts = <0 581 4>; + qcom,mport = <0>; + qcom,count-unit = <0x10000>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpubw>; + }; + + memlat_cpu0: qcom,memlat-cpu0 { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */ + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + memlat_cpu6: qcom,memlat-cpu6 { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = + < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */ + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <139 627>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = + < 1 >; + }; + + devfreq_memlat_0: qcom,cpu0-memlat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&memlat_cpu0>; + qcom,cachemiss-ev = <0x2a>; + qcom,core-dev-table = + < 748800 MHZ_TO_MBPS( 300, 4) >, + < 998400 MHZ_TO_MBPS( 451, 4) >, + < 1209600 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1708000 MHZ_TO_MBPS(1017, 4) >; + }; + + devfreq_memlat_6: qcom,cpu6-memlat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&memlat_cpu6>; + qcom,cachemiss-ev = <0x2a>; + qcom,core-dev-table = + < 825600 MHZ_TO_MBPS( 300, 4) >, + < 1132800 MHZ_TO_MBPS( 547, 4) >, + < 1363200 MHZ_TO_MBPS(1017, 4) >, + < 1996800 MHZ_TO_MBPS(1555, 4) >, + < 2457600 MHZ_TO_MBPS(1804, 4) >; + }; + + l3_cpu0: qcom,l3-cpu0 { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; + governor = "performance"; + }; + + l3_cpu6: qcom,l3-cpu6 { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; + governor = "performance"; + }; + + devfreq_l3lat_0: qcom,cpu0-l3lat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&l3_cpu0>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 576000 300000000 >, + < 998400 556800000 >, + < 1209660 844800000 >, + < 1516800 940800000 >, + < 1612800 1382400000 >, + < 1708000 1440000000 >; + }; + + devfreq_l3lat_6: qcom,cpu6-l3lat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&l3_cpu6>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 1132800 556800000 >, + < 1363200 806400000 >, + < 1747200 940800000 >, + < 1996800 1190400000 >, + < 2457600 1440000000 >; + }; + + mincpubw: qcom,mincpubw { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */ + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + devfreq-cpufreq { + mincpubw-cpufreq { + target-dev = <&mincpubw>; + cpu-to-dev-map-0 = + < 748800 MHZ_TO_MBPS( 300, 4) >, + < 1209660 MHZ_TO_MBPS( 451, 4) >, + < 1612800 MHZ_TO_MBPS( 547, 4) >, + < 1708000 MHZ_TO_MBPS( 768, 4) >; + cpu-to-dev-map-6 = + < 1132800 MHZ_TO_MBPS( 300, 4) >, + < 1363200 MHZ_TO_MBPS( 547, 4) >, + < 1747200 MHZ_TO_MBPS( 768, 4) >, + < 1996800 MHZ_TO_MBPS(1017, 4) >, + < 2457600 MHZ_TO_MBPS(1804, 4) >; + }; + }; + + mincpu0bw: qcom,mincpu0bw { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */ + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + mincpu6bw: qcom,mincpu6bw { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */ + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + devfreq_compute0: qcom,devfreq-compute0 { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&mincpu0bw>; + qcom,core-dev-table = + < 748800 MHZ_TO_MBPS( 300, 4) >, + < 1209660 MHZ_TO_MBPS( 451, 4) >, + < 1612800 MHZ_TO_MBPS( 547, 4) >, + < 1708000 MHZ_TO_MBPS( 768, 4) >; + }; + + devfreq_compute6: qcom,devfreq-compute6 { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&mincpu6bw>; + qcom,core-dev-table = + < 1132800 MHZ_TO_MBPS( 300, 4) >, + < 1363200 MHZ_TO_MBPS( 547, 4) >, + < 1747200 MHZ_TO_MBPS( 768, 4) >, + < 1996800 MHZ_TO_MBPS(1017, 4) >, + < 2457600 MHZ_TO_MBPS(1804, 4) >; + }; + + l3_cdsp: qcom,l3-cdsp { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; + governor = "powersave"; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 5 4>; + }; + + gpu_gx_domain_addr: syscon@0x5091508 { + compatible = "syscon"; + reg = <0x5091508 0x4>; + }; + + gpu_gx_sw_reset: syscon@0x5091008 { + compatible = "syscon"; + reg = <0x5091008 0x4>; + }; + + qfprom: qfprom@0x780000 { + compatible = "qcom,qfprom"; + reg = <0x00780000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + minor_rev: minor_rev@0x78014c { + reg = <0x14c 0x4>; + bits = <0x1c 0x2>; + }; + }; + +}; + +#include "pm660.dtsi" +#include "pm660l.dtsi" +#include "sdm670-regulator.dtsi" +#include "sdm670-pinctrl.dtsi" +#include "msm-arm-smmu-sdm670.dtsi" +#include "msm-gdsc-sdm845.dtsi" +#include "sdm670-pm.dtsi" + +&usb30_prim_gdsc { + status = "ok"; +}; + +&ufs_phy_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_tbu1_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_tbu2_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc { + status = "ok"; +}; + +&bps_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&ife_0_gdsc { + status = "ok"; +}; + +&ife_1_gdsc { + status = "ok"; +}; + +&ipe_0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&ipe_1_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&titan_top_gdsc { + status = "ok"; +}; + +&mdss_core_gdsc { + status = "ok"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; +}; + +&gpu_cx_gdsc { + status = "ok"; +}; + +&gpu_gx_gdsc { + clock-names = "core_root_clk"; + clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK_SRC>; + qcom,force-enable-root-clk; + parent-supply = <&pm660l_s2_level>; + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; + qcom,reset-aon-logic; + status = "ok"; +}; + +&vcodec0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&vcodec1_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&venus_gdsc { + status = "ok"; +}; + +&mdss_dsi0 { + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&mdss_dsi1 { + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&sde_dp { + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +#include "sdm670-audio.dtsi" +#include "sdm670-usb.dtsi" +#include "sdm670-gpu.dtsi" +#include "sdm670-camera.dtsi" +#include "sdm670-thermal.dtsi" +#include "sdm670-bus.dtsi" + +&pm660_div_clk { + status = "ok"; +}; + +&qupv3_se10_i2c { + nx30p6093: nx30p6093@36 { + status = "disabled"; + compatible = "nxp,nx30p6093"; + reg = <0x36>; + interrupt-parent = <&tlmm>; + interrupts = <5 IRQ_TYPE_NONE>; + nxp,long-wakeup-sec = <28800>; /* 8 hours */ + nxp,short-wakeup-ms = <180000>; /* 3 mins */ + pinctrl-names = "default"; + pinctrl-0 = <&nx30p6093_intr_default>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm830.dtsi b/arch/arm64/boot/dts/qcom/sdm830.dtsi deleted file mode 100644 index 81ae913b245d5a56bf5741374d4696cf6642ad75..0000000000000000000000000000000000000000 --- a/arch/arm64/boot/dts/qcom/sdm830.dtsi +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2016-2017, 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. - */ - -/* - * As a general rule, only version-specific property overrides should be placed - * inside this file. Common device definitions should be placed inside the - * sdm845.dtsi file. - */ - - #include "sdm845.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. SDM830"; - compatible = "qcom,sdm830"; - qcom,msm-id = <328 0x0>; - -}; - -&soc { - qcom,llcc@1300000 { - status = "disabled"; - }; - - qcom,spss@1880000 { - status = "disabled"; - }; - - qcom,glink-mailbox-xprt-spss@1885008 { - status = "disabled"; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a78672dd19e26edbe56ead6a1df1ef00bd5d2ed0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <1 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts index d5646bf416141435d1c85c3b078abf8bb3cb2f5c..faf09c467427c0acfa1f0f7f6a88ad91c06775b4 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-cdp.dtsi" / { @@ -21,3 +22,37 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,board-id = <1 1>; }; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a776d426f306adce2f29d6f91794e5abfd3a2248 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <8 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts index d641276cb8d44c210ae9ce0346932b97436b3cc9..2ae93452210355d8e1a2bb1a5e51d74b2db63958 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-mtp.dtsi" / { @@ -21,3 +22,37 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,board-id = <8 1>; }; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c6622d424424f777607250eaa88732abdae0ff88 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts @@ -0,0 +1,64 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <11 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts index 6171c7b626a8b307cb209a9d0eb93e9e62ba0fe0..20f80c90dcc1a33dd0cfeff02f6fdbc33cd3e626 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-qrd.dtsi" / { @@ -21,3 +22,35 @@ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; qcom,board-id = <11 1>; }; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi similarity index 88% rename from arch/arm64/boot/dts/qcom/sdm845-usb.dtsi rename to arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index aac63ee7ac5bd8b73cce6e010959d14c126cc6e9..f6fa948a3530804f1892f758fdcbc6c459292cda 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -21,18 +21,22 @@ reg = <0x0a600000 0xf8c00>, <0x088ee000 0x400>; reg-names = "core_base", "ahb2phy_base"; + iommus = <&apps_smmu 0x740 0x0>; + qcom,smmu-s1-bypass; #address-cells = <1>; #size-cells = <1>; ranges; - interrupts = <0 489 0>, <0 130 0>, <0 486 0>; - interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq"; + interrupts = <0 489 0>, <0 130 0>, <0 486 0>, <0 488 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; USB3_GDSC-supply = <&usb30_prim_gdsc>; qcom,usb-dbm = <&dbm_1p5>; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,num-gsi-evt-buffs = <0x3>; - extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>; + qcom,use-pdc-interrupts; + extcon = <0>, <0>, <&eud>, <0>, <0>; clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>, <&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, @@ -59,15 +63,14 @@ , , , + MSM_BUS_SLAVE_EBI_CH0 240000 700000>, , - ; + ; dwc3@a600000 { compatible = "snps,dwc3"; reg = <0x0a600000 0xcd00>; - interrupt-parent = <&intc>; interrupts = <0 133 0>; usb-phy = <&qusb_phy0>, <&usb_qmp_dp_phy>; tx-fifo-resize; @@ -75,12 +78,13 @@ snps,disable-clk-gating; snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <0>; }; qcom,usbbam@a704000 { compatible = "qcom,usb-bam-msm"; reg = <0xa704000 0x17000>; - interrupt-parent = <&intc>; interrupts = <0 132 0>; qcom,bam-type = <0>; @@ -113,13 +117,29 @@ /* Primary USB port related QUSB2 PHY */ qusb_phy0: qusb@88e2000 { compatible = "qcom,qusb2phy-v2"; - reg = <0x088e2000 0x400>; - reg-names = "qusb_phy_base"; - + reg = <0x088e2000 0x400>, + <0x007801e8 0x4>, + <0x088e7014 0x4>; + reg-names = "qusb_phy_base", "efuse_addr", + "refgen_north_bg_reg_addr"; + + qcom,efuse-bit-pos = <25>; + qcom,efuse-num-bits = <3>; vdd-supply = <&pm8998_l1>; vdda18-supply = <&pm8998_l12>; vdda33-supply = <&pm8998_l24>; qcom,vdd-voltage-level = <0 880000 880000>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x228 /* QUSB2PHY_SQ_CTRL1 */ + 0x22c>; /* QUSB2PHY_SQ_CTRL2 */ + qcom,qusb-phy-init-seq = /* */ <0x23 0x210 /* PWR_CTRL1 */ @@ -133,7 +153,7 @@ 0x21 0x214 /* PWR_CTRL2 */ 0x00 0x220 /* IMP_CTRL1 */ 0x58 0x224 /* IMP_CTRL2 */ - 0x32 0x240 /* TUNE1 */ + 0x30 0x240 /* TUNE1 */ 0x29 0x244 /* TUNE2 */ 0xca 0x248 /* TUNE3 */ 0x04 0x24c /* TUNE4 */ @@ -206,6 +226,8 @@ 0x14fc 0x80 0x00 /* RXA_RX_OFFSET_ADAPTOR_CNTRL2 */ 0x1504 0x03 0x00 /* RXA_SIGDET_CNTRL */ 0x150c 0x16 0x00 /* RXA_SIGDET_DEGLITCH_CNTRL */ + 0x1564 0x05 0x00 /* RXA_RX_MODE_00 */ + 0x14c0 0x03 0x00 /* RXA_VGA_CAL_CNTRL2 */ 0x1830 0x0b 0x00 /* RXB_UCDR_FASTLOCK_FO_GAIN */ 0x18d4 0x0f 0x00 /* RXB_RX_EQU_ADAPTOR_CNTRL2 */ 0x18d8 0x4e 0x00 /* RXB_RX_EQU_ADAPTOR_CNTRL3 */ @@ -214,16 +236,18 @@ 0x18fc 0x80 0x00 /* RXB_RX_OFFSET_ADAPTOR_CNTRL2 */ 0x1904 0x03 0x00 /* RXB_SIGDET_CNTRL */ 0x190c 0x16 0x00 /* RXB_SIGDET_DEGLITCH_CNTRL */ + 0x1964 0x05 0x00 /* RXB_RX_MODE_00 */ + 0x18c0 0x03 0x00 /* RXB_VGA_CAL_CNTRL2 */ 0x1260 0x10 0x00 /* TXA_HIGHZ_DRVR_EN */ 0x12a4 0x12 0x00 /* TXA_RCV_DETECT_LVL_2 */ 0x128c 0x16 0x00 /* TXA_LANE_MODE_1 */ 0x1248 0x09 0x00 /* TXA_RES_CODE_LANE_OFFSET_RX */ - 0x1244 0x0d 0x00 /* TXA_RES_CODE_LANE_OFFSET_TX */ + 0x1244 0x06 0x00 /* TXA_RES_CODE_LANE_OFFSET_TX */ 0x1660 0x10 0x00 /* TXB_HIGHZ_DRVR_EN */ 0x16a4 0x12 0x00 /* TXB_RCV_DETECT_LVL_2 */ 0x168c 0x16 0x00 /* TXB_LANE_MODE_1 */ 0x1648 0x09 0x00 /* TXB_RES_CODE_LANE_OFFSET_RX */ - 0x1644 0x0d 0x00 /* TXB_RES_CODE_LANE_OFFSET_TX */ + 0x1644 0x06 0x00 /* TXB_RES_CODE_LANE_OFFSET_TX */ 0x1cc8 0x83 0x00 /* PCS_FLL_CNTRL2 */ 0x1ccc 0x09 0x00 /* PCS_FLL_CNT_VAL_L */ 0x1cd0 0xa2 0x00 /* PCS_FLL_CNT_VAL_H_TOL */ @@ -254,6 +278,8 @@ 0x1c48 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_V4 */ 0x1c4c 0x15 0x00 /* PCS_TXDEEMPH_M6DB_LS */ 0x1c50 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_LS */ + 0x1e0c 0x21 0x00 /* PCS_REFGEN_REQ_CONFIG1 */ + 0x1e10 0x60 0x00 /* PCS_REFGEN_REQ_CONFIG2 */ 0x1c5c 0x02 0x00 /* PCS_RATE_SLEW_CNTRL */ 0x1ca0 0x04 0x00 /* PCS_PWRUP_RESET_DLY_TIME_AUXCLK */ 0x1c8c 0x44 0x00 /* PCS_TSYNC_RSYNC_TIME */ @@ -264,6 +290,7 @@ 0x1cb8 0x75 0x00 /* PCS_RXEQTRAINING_WAIT_TIME */ 0x1cb0 0x86 0x00 /* PCS_LFPS_TX_ECSTART_EQTLOCK */ 0x1cbc 0x13 0x00 /* PCS_RXEQTRAINING_RUN_TIME */ + 0x1cac 0x04 0x00 /* PCS_LFPS_DET_HIGH_COUNT_VAL */ 0xffffffff 0xffffffff 0x00>; qcom,qmp-phy-reg-offset = @@ -305,7 +332,7 @@ usb_audio_qmi_dev { compatible = "qcom,usb-audio-qmi-dev"; - iommus = <&apps_smmu 0x182c>; + iommus = <&apps_smmu 0x182c 0x0>; qcom,usb-audio-stream-id = <0xc>; qcom,usb-audio-intr-num = <2>; }; @@ -320,15 +347,19 @@ reg = <0x0a800000 0xf8c00>, <0x088ee000 0x400>; reg-names = "core_base", "ahb2phy_base"; + iommus = <&apps_smmu 0x760 0x0>; + qcom,smmu-s1-bypass; #address-cells = <1>; #size-cells = <1>; ranges; - interrupts = <0 491 0>, <0 135 0>, <0 487 0>; - interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq"; + interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; USB3_GDSC-supply = <&usb30_sec_gdsc>; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,use-pdc-interrupts; clocks = <&clock_gcc GCC_USB30_SEC_MASTER_CLK>, <&clock_gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, @@ -355,13 +386,12 @@ , , , - ; + MSM_BUS_SLAVE_EBI_CH0 240000 700000>, + ; - dwc3@a600000 { + dwc3@a800000 { compatible = "snps,dwc3"; reg = <0x0a800000 0xcd00>; - interrupt-parent = <&intc>; interrupts = <0 138 0>; usb-phy = <&qusb_phy1>, <&usb_qmp_phy>; tx-fifo-resize; @@ -369,19 +399,34 @@ snps,disable-clk-gating; snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <1>; }; }; /* Secondary USB port related QUSB2 PHY */ qusb_phy1: qusb@88e3000 { compatible = "qcom,qusb2phy-v2"; - reg = <0x088e3000 0x400>; - reg-names = "qusb_phy_base"; + reg = <0x088e3000 0x400>, + <0x088e7014 0x4>; + reg-names = "qusb_phy_base", + "refgen_north_bg_reg_addr"; vdd-supply = <&pm8998_l1>; vdda18-supply = <&pm8998_l12>; vdda33-supply = <&pm8998_l24>; qcom,vdd-voltage-level = <0 880000 880000>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x228 /* QUSB2PHY_SQ_CTRL1 */ + 0x22c>; /* QUSB2PHY_SQ_CTRL2 */ + qcom,qusb-phy-init-seq = /* */ <0x23 0x210 /* PWR_CTRL1 */ @@ -395,7 +440,7 @@ 0x21 0x214 /* PWR_CTRL2 */ 0x00 0x220 /* IMP_CTRL1 */ 0x58 0x224 /* IMP_CTRL2 */ - 0x32 0x240 /* TUNE1 */ + 0x20 0x240 /* TUNE1 */ 0x29 0x244 /* TUNE2 */ 0xca 0x248 /* TUNE3 */ 0x04 0x24c /* TUNE4 */ @@ -482,8 +527,8 @@ 0x260 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */ 0x2a4 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */ 0x28c 0xc6 0x00 /* QSERDES_TX_LANE_MODE_1 */ - 0x248 0x09 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */ - 0x244 0x0d 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */ + 0x248 0x06 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */ + 0x244 0x06 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */ 0x8c8 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */ 0x8cc 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */ 0x8d0 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */ diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9d485b5dbba083ab1532d4e9786842d1e96056ff --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2017, 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 "sdm845-wcd.dtsi" +#include "msm-wsa881x.dtsi" +#include + +&snd_934x { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>; + qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,tavil-mclk-clk-freq = <9600000>; + + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; + + qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2-gpio = <&tlmm 51 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en2_active>; + pinctrl-1 = <&wcd_usbc_analog_en2_idle>; + + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&soc { + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; + + wcd9xxx_intc: wcd9xxx-irq { + status = "ok"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 54 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + status = "ok"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 64 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; + + qocm,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + }; + + qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi_xprt_wdsp 2>; + qcom,img-filename = "cpe_9340"; + }; +}; + +&slim_aud { + wcd934x_cdc: tavil_codec { + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; + + cdc-vdd-buck-supply = <&pm8998_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pm8998_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pm8998_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pm8998_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pm8998_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <0>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index 9d59a16d068bf0781c7545269555d96ae37ccbfb..a5c6d84ccdbe49ab5a42af59b6711c5fe90b5d56 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -12,12 +12,9 @@ */ #include "msm-audio-lpass.dtsi" -#include "sdm845-wcd.dtsi" -#include "msm-wsa881x.dtsi" -#include &msm_audio_ion { - iommus = <&apps_smmu 0x1821>; + iommus = <&apps_smmu 0x1821 0x0>; qcom,smmu-sid-mask = /bits/ 64 <0xf>; }; @@ -31,9 +28,11 @@ qcom,clk-mult = <10>; }; - sound-tavil { + snd_934x: sound-tavil { compatible = "qcom,sdm845-asoc-snd-tavil"; qcom,model = "sdm845-tavil-snd-card"; + qcom,ext-disp-audio-rx; + qcom,wcn-btfm; qcom,mi2s-audio-intf; qcom,auxpcm-audio-intf; qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; @@ -47,36 +46,6 @@ "lpaif_tert_mode_muxsel", "lpaif_quat_mode_muxsel"; - qcom,audio-routing = - "AIF4 VI", "MCLK", - "RX_BIAS", "MCLK", - "MADINPUT", "MCLK", - "hifi amp", "LINEOUT1", - "hifi amp", "LINEOUT2", - "AMIC2", "MIC BIAS2", - "MIC BIAS2", "Headset Mic", - "AMIC5", "MIC BIAS3", - "MIC BIAS3", "Handset Mic", - "DMIC0", "MIC BIAS1", - "MIC BIAS1", "Digital Mic0", - "DMIC1", "MIC BIAS1", - "MIC BIAS1", "Digital Mic1", - "DMIC2", "MIC BIAS3", - "MIC BIAS3", "Digital Mic2", - "DMIC3", "MIC BIAS3", - "MIC BIAS3", "Digital Mic3", - "DMIC4", "MIC BIAS4", - "MIC BIAS4", "Digital Mic4", - "DMIC5", "MIC BIAS4", - "MIC BIAS4", "Digital Mic5", - "SpkrLeft IN", "SPK1 OUT", - "SpkrRight IN", "SPK2 OUT"; - - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <1>; - qcom,hph-en0-gpio = <&tavil_hph_en0>; - qcom,hph-en1-gpio = <&tavil_hph_en1>; - qcom,tavil-mclk-clk-freq = <9600000>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, @@ -128,45 +97,6 @@ "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913"; - asoc-codec = <&stub_codec>; - asoc-codec-names = "msm-stub-codec.1"; - qcom,wsa-max-devs = <2>; - qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, - <&wsa881x_0213>, <&wsa881x_0214>; - qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", - "SpkrLeft", "SpkrRight"; - }; - - wcd9xxx_intc: wcd9xxx-irq { - status = "ok"; - compatible = "qcom,wcd9xxx-irq"; - interrupt-controller; - #interrupt-cells = <1>; - interrupt-parent = <&tlmm>; - qcom,gpio-connect = <&tlmm 54 0>; - pinctrl-names = "default"; - pinctrl-0 = <&wcd_intr_default>; - }; - - clock_audio_lnbb: audio_ext_clk_lnbb { - status = "ok"; - compatible = "qcom,audio-ref-clk"; - clock-names = "osr_clk"; - clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; - qcom,node_has_rpm_clock; - #clock-cells = <1>; - }; - - wcd_rst_gpio: msm_cdc_pinctrl@64 { - compatible = "qcom,msm-cdc-pinctrl"; - qcom,cdc-rst-n-gpio = <&tlmm 64 0>; - pinctrl-names = "aud_active", "aud_sleep"; - pinctrl-0 = <&cdc_reset_active>; - pinctrl-1 = <&cdc_reset_sleep>; - }; - - qocm,wcd-dsp-glink { - compatible = "qcom,wcd-dsp-glink"; }; }; @@ -175,58 +105,4 @@ compatible = "qcom,msm-dai-slim"; elemental-addr = [ff ff ff fe 17 02]; }; - - wcd934x_cdc: tavil_codec { - compatible = "qcom,tavil-slim-pgd"; - elemental-addr = [00 01 50 02 17 02]; - - interrupt-parent = <&wcd9xxx_intc>; - interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - 17 18 19 20 21 22 23 24 25 26 27 28 29 - 30 31>; - - qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; - - clock-names = "wcd_clk"; - clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; - - cdc-vdd-buck-supply = <&pm8998_s4>; - qcom,cdc-vdd-buck-voltage = <1800000 1800000>; - qcom,cdc-vdd-buck-current = <650000>; - - cdc-buck-sido-supply = <&pm8998_s4>; - qcom,cdc-buck-sido-voltage = <1800000 1800000>; - qcom,cdc-buck-sido-current = <250000>; - - cdc-vdd-tx-h-supply = <&pm8998_s4>; - qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; - qcom,cdc-vdd-tx-h-current = <25000>; - - cdc-vdd-rx-h-supply = <&pm8998_s4>; - qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; - qcom,cdc-vdd-rx-h-current = <25000>; - - cdc-vddpx-1-supply = <&pm8998_s4>; - qcom,cdc-vddpx-1-voltage = <1800000 1800000>; - qcom,cdc-vddpx-1-current = <10000>; - - qcom,cdc-static-supplies = "cdc-vdd-buck", - "cdc-buck-sido", - "cdc-vdd-tx-h", - "cdc-vdd-rx-h", - "cdc-vddpx-1"; - - qcom,cdc-micbias1-mv = <1800>; - qcom,cdc-micbias2-mv = <1800>; - qcom,cdc-micbias3-mv = <1800>; - qcom,cdc-micbias4-mv = <1800>; - - qcom,cdc-mclk-clk-rate = <9600000>; - qcom,cdc-slim-ifd = "tavil-slim-ifd"; - qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; - qcom,cdc-dmic-sample-rate = <4800000>; - qcom,cdc-mad-dmic-rate = <600000>; - - qcom,wdsp-cmpnt-dev-name = "tavil_codec"; - }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi index 1702e8040e3ecb391fedc228240525d76859b731..3ce56269be2b3302739a54a596882a598edb072d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi @@ -12,6 +12,7 @@ #include #include +#include &soc { ad_hoc_bus: ad-hoc-bus { @@ -25,12 +26,14 @@ <0x1380000 0x40000>, <0x1740000 0x40000>, <0x1620000 0x40000>, + <0x1620000 0x40000>, <0x1620000 0x40000>; reg-names = "aggre1_noc-base", "aggre2_noc-base", "config_noc-base", "dc_noc-base", "gladiator_noc-base", "mc_virt-base", "mem_noc-base", - "mmss_noc-base", "system_noc-base", "ipa_virt-base"; + "mmss_noc-base", "system_noc-base", "ipa_virt-base", + "camnoc_virt-base"; mbox-names = "apps_rsc", "disp_rsc"; mboxes = <&apps_rsc 0 &disp_rsc 0>; @@ -353,7 +356,8 @@ label = "fab-aggre1_noc"; qcom,fab-dev; qcom,base-name = "aggre1_noc-base"; - qcom,bypass-qos-prg; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; qcom,bus-type = <1>; clocks = <>; }; @@ -363,11 +367,21 @@ label = "fab-aggre2_noc"; qcom,fab-dev; qcom,base-name = "aggre2_noc-base"; - qcom,bypass-qos-prg; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; qcom,bus-type = <1>; clocks = <>; }; + fab_camnoc_virt: fab-camnoc_virt { + cell-id = ; + label = "fab-camnoc_virt"; + qcom,fab-dev; + qcom,base-name = "camnoc_virt-base"; + qcom,bypass-qos-prg; + clocks = <>; + }; + fab_config_noc: fab-config_noc { cell-id = ; label = "fab-config_noc"; @@ -421,7 +435,8 @@ label = "fab-mem_noc"; qcom,fab-dev; qcom,base-name = "mem_noc-base"; - qcom,bypass-qos-prg; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; qcom,bus-type = <1>; clocks = <>; }; @@ -431,7 +446,8 @@ label = "fab-mmss_noc"; qcom,fab-dev; qcom,base-name = "mmss_noc-base"; - qcom,bypass-qos-prg; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; qcom,bus-type = <1>; clocks = <>; }; @@ -441,7 +457,8 @@ label = "fab-system_noc"; qcom,fab-dev; qcom,base-name = "system_noc-base"; - qcom,bypass-qos-prg; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; qcom,bus-type = <1>; clocks = <>; }; @@ -460,6 +477,8 @@ label = "fab-mem_noc_display"; qcom,fab-dev; qcom,base-name = "mem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; @@ -513,6 +532,8 @@ qcom,qport = <1>; qcom,connections = <&slv_qns_a1noc_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <1>; }; mas_xm_sdc4: mas-xm-sdc4 { @@ -523,6 +544,8 @@ qcom,qport = <2>; qcom,connections = <&slv_qns_a1noc_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <1>; }; mas_xm_ufs_card: mas-xm-ufs-card { @@ -533,6 +556,8 @@ qcom,qport = <3>; qcom,connections = <&slv_qns_a1noc_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; }; mas_xm_ufs_mem: mas-xm-ufs-mem { @@ -543,6 +568,20 @@ qcom,qport = <4>; qcom,connections = <&slv_qns_a1noc_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_pcie_0: mas-xm-pcie-0 { + cell-id = ; + label = "mas-xm-pcie-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_pcie_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; }; mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg { @@ -581,6 +620,8 @@ qcom,qport = <0>; qcom,connections = <&slv_qns_a2noc_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <1>; }; mas_qxm_crypto: mas-qxm-crypto { @@ -592,6 +633,8 @@ qcom,connections = <&slv_qns_a2noc_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; qcom,bcms = <&bcm_ce0>; + qcom,ap-owned; + qcom,prio = <2>; }; mas_qxm_ipa: mas-qxm-ipa { @@ -602,6 +645,10 @@ qcom,qport = <2>; qcom,connections = <&slv_qns_a2noc_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; }; mas_xm_pcie3_1: mas-xm-pcie3-1 { @@ -612,16 +659,8 @@ qcom,qport = <6>; qcom,connections = <&slv_qns_pcie_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; - }; - - mas_xm_pcie_0: mas-xm-pcie-0 { - cell-id = ; - label = "mas-xm-pcie-0"; - qcom,buswidth = <8>; - qcom,agg-ports = <1>; - qcom,qport = <5>; - qcom,connections = <&slv_qns_pcie_snoc>; - qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; }; mas_xm_qdss_etr: mas-xm-qdss-etr { @@ -632,6 +671,8 @@ qcom,qport = <7>; qcom,connections = <&slv_qns_a2noc_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; }; mas_xm_usb3_0: mas-xm-usb3-0 { @@ -642,6 +683,14 @@ qcom,qport = <10>; qcom,connections = <&slv_qns_a2noc_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-usb3-prim-axi-no-rate"; + }; }; mas_xm_usb3_1: mas-xm-usb3-1 { @@ -652,6 +701,44 @@ qcom,qport = <11>; qcom,connections = <&slv_qns_a2noc_snoc>; qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_SEC_AXI_CLK>; + clock-names = + "clk-usb3-sec-axi-no-rate"; + }; + }; + + mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf0-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_hf1_uncomp: mas-qxm-camnoc-hf1-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf1-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_sf_uncomp: mas-qxm-camnoc-sf-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-sf-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; }; mas_qhm_spdm: mas-qhm-spdm { @@ -664,38 +751,6 @@ qcom,bcms = <&bcm_cn0>; }; - mas_qhm_tic: mas-qhm-tic { - cell-id = ; - label = "mas-qhm-tic"; - qcom,buswidth = <4>; - qcom,agg-ports = <1>; - qcom,connections = <&slv_qhs_tlmm_south - &slv_qhs_spss_cfg &slv_qhs_camera_cfg - &slv_qhs_sdc4 &slv_qhs_sdc2 - &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg - &slv_qhs_snoc_cfg &slv_qhs_glm - &slv_qhs_pdm &slv_qhs_a2_noc_cfg - &slv_qhs_qdss_cfg &slv_qhs_display_cfg - &slv_qhs_tcsr &slv_qhs_dcc_cfg - &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc - &slv_qhs_phy_refgen_south - &slv_qhs_pcie_gen3_cfg - &slv_qhs_pcie0_cfg &slv_qhs_gpuss_cfg - &slv_qhs_venus_cfg &slv_qhs_tsif - &slv_qhs_compute_dsp_cfg &slv_qhs_aop - &slv_qhs_qupv3_north &slv_qhs_usb3_0 - &slv_srvc_cnoc &slv_qhs_ufs_card_cfg - &slv_qhs_usb3_1 &slv_qhs_ipa - &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg - &slv_qhs_aoss &slv_qhs_prng - &slv_qhs_vsense_ctrl_cfg &slv_qhs_qupv3_south - &slv_qhs_spdm &slv_qhs_crypto0_cfg - &slv_qhs_pimem_cfg &slv_qhs_tlmm_north - &slv_qhs_clk_ctl &slv_qhs_imem_cfg>; - qcom,bus-dev = <&fab_config_noc>; - qcom,bcms = <&bcm_cn0>; - }; - mas_qnm_snoc: mas-qnm-snoc { cell-id = ; label = "mas-qnm-snoc"; @@ -727,38 +782,6 @@ qcom,bcms = <&bcm_cn0>; }; - mas_xm_qdss_dap: mas-xm-qdss-dap { - cell-id = ; - label = "mas-xm-qdss-dap"; - qcom,buswidth = <8>; - qcom,agg-ports = <1>; - qcom,connections = <&slv_qhs_tlmm_south - &slv_qhs_spss_cfg &slv_qhs_camera_cfg - &slv_qhs_sdc4 &slv_qhs_sdc2 - &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg - &slv_qhs_snoc_cfg &slv_qhs_glm - &slv_qhs_pdm &slv_qhs_a2_noc_cfg - &slv_qhs_qdss_cfg &slv_qhs_display_cfg - &slv_qhs_tcsr &slv_qhs_dcc_cfg - &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc - &slv_qhs_phy_refgen_south - &slv_qhs_pcie_gen3_cfg - &slv_qhs_pcie0_cfg &slv_qhs_gpuss_cfg - &slv_qhs_venus_cfg &slv_qhs_tsif - &slv_qhs_compute_dsp_cfg &slv_qhs_aop - &slv_qhs_qupv3_north &slv_qhs_usb3_0 - &slv_srvc_cnoc &slv_qhs_ufs_card_cfg - &slv_qhs_usb3_1 &slv_qhs_ipa - &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg - &slv_qhs_aoss &slv_qhs_prng - &slv_qhs_vsense_ctrl_cfg &slv_qhs_qupv3_south - &slv_qhs_spdm &slv_qhs_crypto0_cfg - &slv_qhs_pimem_cfg &slv_qhs_tlmm_north - &slv_qhs_clk_ctl &slv_qhs_imem_cfg>; - qcom,bus-dev = <&fab_config_noc>; - qcom,bcms = <&bcm_cn0>; - }; - mas_qhm_cnoc: mas-qhm-cnoc { cell-id = ; label = "mas-qhm-cnoc"; @@ -787,12 +810,12 @@ qcom,bus-dev = <&fab_gladiator_noc>; }; - mas_ipa_core: mas-ipa-core { + mas_ipa_core_master: mas-ipa-core-master { cell-id = ; - label = "mas-ipa-core"; - qcom,buswidth = <1>; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; qcom,agg-ports = <1>; - qcom,connections = <&slv_ipa_core>; + qcom,connections = <&slv_ipa_core_slave>; qcom,bus-dev = <&fab_ipa_virt>; }; @@ -815,6 +838,8 @@ &slv_qns_memnoc_snoc>; qcom,bus-dev = <&fab_mem_noc>; qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <7>; }; mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg { @@ -836,6 +861,8 @@ qcom,connections = <&slv_qns_llcc>; qcom,bus-dev = <&fab_mem_noc>; qcom,bcms = <&bcm_sh5>; + qcom,ap-owned; + qcom,prio = <0>; }; mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { @@ -846,6 +873,10 @@ qcom,qport = <4 5>; qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>; qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { @@ -857,6 +888,10 @@ qcom,connections = <&slv_qns_apps_io &slv_qns_llcc &slv_qns_memnoc_snoc>; qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qnm_snoc_gc: mas-qnm-snoc-gc { @@ -867,6 +902,9 @@ qcom,qport = <8>; qcom,connections = <&slv_qns_llcc>; qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; }; mas_qnm_snoc_sf: mas-qnm-snoc-sf { @@ -877,6 +915,9 @@ qcom,qport = <9>; qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>; qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; }; mas_qxm_gpu: mas-qxm-gpu { @@ -888,7 +929,8 @@ qcom,connections = <&slv_qns_apps_io &slv_qns_llcc &slv_qns_memnoc_snoc>; qcom,bus-dev = <&fab_mem_noc>; - qcom,bcms = <&bcm_sh4>; + qcom,ap-owned; + qcom,prio = <0>; }; mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { @@ -900,15 +942,34 @@ qcom,bus-dev = <&fab_mmss_noc>; }; - mas_qxm_camnoc_hf: mas-qxm-camnoc-hf { - cell-id = ; - label = "mas-qxm-camnoc-hf"; + mas_qxm_camnoc_hf0: mas-qxm-camnoc-hf0 { + cell-id = ; + label = "mas-qxm-camnoc-hf0"; qcom,buswidth = <32>; - qcom,agg-ports = <2>; - qcom,qport = <1 2>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 { + cell-id = ; + label = "mas-qxm-camnoc-hf1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <2>; qcom,connections = <&slv_qns_mem_noc_hf>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { @@ -920,6 +981,10 @@ qcom,connections = <&slv_qns2_mem_noc>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_mdp0: mas-qxm-mdp0 { @@ -931,6 +996,10 @@ qcom,connections = <&slv_qns_mem_noc_hf>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_mdp1: mas-qxm-mdp1 { @@ -942,6 +1011,10 @@ qcom,connections = <&slv_qns_mem_noc_hf>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_rot: mas-qxm-rot { @@ -953,6 +1026,10 @@ qcom,connections = <&slv_qns2_mem_noc>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus0: mas-qxm-venus0 { @@ -964,6 +1041,10 @@ qcom,connections = <&slv_qns2_mem_noc>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus1: mas-qxm-venus1 { @@ -975,6 +1056,10 @@ qcom,connections = <&slv_qns2_mem_noc>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus_arm9: mas-qxm-venus-arm9 { @@ -986,6 +1071,10 @@ qcom,connections = <&slv_qns2_mem_noc>; qcom,bus-dev = <&fab_mmss_noc>; qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { @@ -1071,6 +1160,30 @@ qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>; qcom,bus-dev = <&fab_system_noc>; qcom,bcms = <&bcm_sn4>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_gic: mas-xm-gic { + cell-id = ; + label = "mas-xm-gic"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn12>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_alc: mas-alc { + cell-id = ; + label = "mas-alc"; + qcom,buswidth = <1>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_alc>; }; mas_llcc_mc_display: mas-llcc-mc_display { @@ -1157,6 +1270,15 @@ qcom,bcms = <&bcm_sn9>; }; + slv_qns_pcie_a1noc_snoc:slv-qns-pcie-a1noc-snoc { + cell-id = ; + label = "slv-qns-pcie-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_pcie_anoc>; + }; + slv_qns_a2noc_snoc:slv-qns-a2noc-snoc { cell-id = ; label = "slv-qns-a2noc-snoc"; @@ -1184,6 +1306,14 @@ qcom,bcms = <&bcm_sn11>; }; + slv_qns_camnoc_uncomp:slv-qns-camnoc-uncomp { + cell-id = ; + label = "slv-qns-camnoc-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_camnoc_virt>; + }; + slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg { cell-id = ; label = "slv-qhs-a1-noc-cfg"; @@ -1620,10 +1750,10 @@ qcom,bus-dev = <&fab_gladiator_noc>; }; - slv_ipa_core:slv-ipa-core { - cell-id = ; - label = "slv-ipa-core"; - qcom,buswidth = <1>; + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; qcom,agg-ports = <1>; qcom,bus-dev = <&fab_ipa_virt>; qcom,bcms = <&bcm_ip0>; @@ -1635,7 +1765,7 @@ qcom,buswidth = <4>; qcom,agg-ports = <4>; qcom,bus-dev = <&fab_mc_virt>; - qcom,bcms = <&bcm_mc0>; + qcom,bcms = <&bcm_mc0>, <&bcm_acv>; }; slv_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg { diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi index c0189a4cfff9cee4609cd7009c367642df7b8a67..f31b3a5ca767dfcb007d65ade110cc7d34200967 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi @@ -16,19 +16,39 @@ cell-index = <0>; reg = <0x00 0x00>; compatible = "qcom,camera-flash"; - qcom,flash-source = <&pmi8998_flash0 &pmi8998_flash1>; - qcom,torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - qcom,switch-source = <&pmi8998_switch0>; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; status = "ok"; }; - led_flash_front: qcom,camera-flash@1 { + led_flash_rear_aux: qcom,camera-flash@1 { cell-index = <1>; reg = <0x01 0x00>; compatible = "qcom,camera-flash"; - qcom,flash-source = <&pmi8998_flash2>; - qcom,torch-source = <&pmi8998_torch2>; - qcom,switch-source = <&pmi8998_switch1>; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch1>; + status = "ok"; + }; + + led_flash_iris: qcom,camera-flash@3 { + cell-index = <3>; + reg = <0x03 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch2>; status = "ok"; }; @@ -73,42 +93,67 @@ }; }; -&cci { +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <8>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_res_mgr_active>; + pinctrl-1 = <&cam_res_mgr_suspend>; + }; + actuator_rear: qcom,actuator@0 { cell-index = <0>; reg = <0x0>; compatible = "qcom,actuator"; - qcom,cci-master = <0>; + cci-master = <0>; cam_vaf-supply = <&actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <0>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; }; - actuator_front: qcom,actuator@1 { + actuator_rear_aux: qcom,actuator@1 { cell-index = <1>; reg = <0x1>; compatible = "qcom,actuator"; - qcom,cci-master = <1>; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; cam_vaf-supply = <&actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <0>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; }; ois_rear: qcom,ois@0 { cell-index = <0>; reg = <0x0>; compatible = "qcom,ois"; - qcom,cci-master = <0>; + cci-master = <0>; cam_vaf-supply = <&actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <0>; - status = "disabled"; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "ok"; }; eeprom_rear: qcom,eeprom@0 { @@ -118,11 +163,15 @@ cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_rear_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>; @@ -130,24 +179,22 @@ &cam_sensor_rear_suspend>; gpios = <&tlmm 13 0>, <&tlmm 80 0>, - <&tlmm 79 0>, - <&tlmm 27 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-vaf = <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", + <&tlmm 79 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", - "CAM_VANA0", - "CAM_VAF"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + "CAM_VANA0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; eeprom_rear_aux: qcom,eeprom@1 { @@ -157,11 +204,15 @@ cam_vdig-supply = <&camera_ldo>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-min-voltage = <1050000 0 3312000>; - qcom,cam-vreg-max-voltage = <1050000 0 3600000>; - qcom,cam-vreg-op-mode = <105000 0 80000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0 2800000>; + rgltr-max-voltage = <1050000 0 3600000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_rear2_active>; @@ -170,20 +221,21 @@ gpios = <&tlmm 15 0>, <&tlmm 9 0>, <&tlmm 8 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", "CAM_RESET1", "CAM_VANA1"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; eeprom_front: qcom,eeprom@2 { @@ -193,11 +245,15 @@ cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; @@ -205,46 +261,47 @@ &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, - <&tlmm 8 0>, - <&tlmm 27 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-vaf = <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", + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", - "CAM_VANA2", - "CAM_VAF"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + "CAM_VANA2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; qcom,cam-sensor@0 { cell-index = <0>; compatible = "qcom,cam-sensor"; reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <180>; - qcom,led-flash-src = <&led_flash_rear>; - qcom,actuator-src = <&actuator_rear>; - qcom,ois-src = <&ois_rear>; - qcom,eeprom-src = <&eeprom_rear>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_rear_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>; @@ -253,38 +310,44 @@ gpios = <&tlmm 13 0>, <&tlmm 80 0>, <&tlmm 79 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", "CAM_VANA"; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + sensor-mode = <0>; + cci-master = <0>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; qcom,cam-sensor@1 { cell-index = <1>; compatible = "qcom,cam-sensor"; reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <180>; - qcom,eeprom-src = <&eeprom_rear_aux>; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; cam_vdig-supply = <&camera_ldo>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-min-voltage = <1050000 0 3312000>; - qcom,cam-vreg-max-voltage = <1050000 0 3600000>; - qcom,cam-vreg-op-mode = <105000 0 80000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0>; + rgltr-max-voltage = <1050000 0 3600000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_rear2_active>; @@ -293,40 +356,44 @@ gpios = <&tlmm 15 0>, <&tlmm 9 0>, <&tlmm 8 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", "CAM_RESET1", "CAM_VANA1"; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; qcom,cam-sensor@2 { cell-index = <2>; compatible = "qcom,cam-sensor"; reg = <0x02>; - qcom,csiphy-sd-index = <2>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <0>; - qcom,eeprom-src = <&eeprom_front>; - qcom,actuator-src = <&actuator_front>; - qcom,led-flash-src = <&led_flash_front>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; @@ -335,18 +402,63 @@ gpios = <&tlmm 14 0>, <&tlmm 28 0>, <&tlmm 8 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", "CAM_VANA1"; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + led-flash-src = <&led_flash_iris>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_iris_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 9 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_VANA1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi index c0189a4cfff9cee4609cd7009c367642df7b8a67..d708a121c4b105efd2947ad51e8643f2a7683368 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,19 +16,39 @@ cell-index = <0>; reg = <0x00 0x00>; compatible = "qcom,camera-flash"; - qcom,flash-source = <&pmi8998_flash0 &pmi8998_flash1>; - qcom,torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - qcom,switch-source = <&pmi8998_switch0>; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; status = "ok"; }; - led_flash_front: qcom,camera-flash@1 { + led_flash_rear_aux: qcom,camera-flash@1 { cell-index = <1>; reg = <0x01 0x00>; compatible = "qcom,camera-flash"; - qcom,flash-source = <&pmi8998_flash2>; - qcom,torch-source = <&pmi8998_torch2>; - qcom,switch-source = <&pmi8998_switch1>; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch1>; + status = "ok"; + }; + + led_flash_iris: qcom,camera-flash@3 { + cell-index = <3>; + reg = <0x03 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch2>; status = "ok"; }; @@ -71,44 +91,79 @@ pinctrl-0 = <&camera_dvdd_en_default>; vin-supply = <&pm8998_s3>; }; + + camera_vana_ldo: gpio-regulator@4 { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "camera_vana_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vana>; + vin-supply = <&pmi8998_bob>; + }; }; -&cci { +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + actuator_rear: qcom,actuator@0 { cell-index = <0>; reg = <0x0>; compatible = "qcom,actuator"; - qcom,cci-master = <0>; + cci-master = <0>; cam_vaf-supply = <&actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <0>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; }; - actuator_front: qcom,actuator@1 { + actuator_rear_aux: qcom,actuator@1 { cell-index = <1>; reg = <0x1>; compatible = "qcom,actuator"; - qcom,cci-master = <1>; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; cam_vaf-supply = <&actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <0>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; }; ois_rear: qcom,ois@0 { cell-index = <0>; reg = <0x0>; compatible = "qcom,ois"; - qcom,cci-master = <0>; + cci-master = <0>; cam_vaf-supply = <&actuator_regulator>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <0>; - status = "disabled"; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "ok"; }; eeprom_rear: qcom,eeprom@0 { @@ -118,11 +173,15 @@ cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_rear_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>; @@ -130,24 +189,22 @@ &cam_sensor_rear_suspend>; gpios = <&tlmm 13 0>, <&tlmm 80 0>, - <&tlmm 79 0>, - <&tlmm 27 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-vaf = <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", + <&tlmm 79 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", - "CAM_VANA0", - "CAM_VAF"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + "CAM_VANA0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; eeprom_rear_aux: qcom,eeprom@1 { @@ -157,11 +214,15 @@ cam_vdig-supply = <&camera_ldo>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-min-voltage = <1050000 0 3312000>; - qcom,cam-vreg-max-voltage = <1050000 0 3600000>; - qcom,cam-vreg-op-mode = <105000 0 80000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0 2800000>; + rgltr-max-voltage = <1050000 0 3600000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active &cam_sensor_rear2_active>; @@ -170,20 +231,21 @@ gpios = <&tlmm 15 0>, <&tlmm 9 0>, <&tlmm 8 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", "CAM_RESET1", "CAM_VANA1"; - qcom,sensor-position = <0>; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; eeprom_front: qcom,eeprom@2 { @@ -193,11 +255,15 @@ cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_front_active>; @@ -205,46 +271,47 @@ &cam_sensor_front_suspend>; gpios = <&tlmm 14 0>, <&tlmm 28 0>, - <&tlmm 8 0>, - <&tlmm 27 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-vaf = <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", + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", "CAM_RESET2", - "CAM_VANA2", - "CAM_VAF"; - qcom,sensor-position = <1>; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + "CAM_VANA2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; qcom,cam-sensor@0 { cell-index = <0>; compatible = "qcom,cam-sensor"; reg = <0x0>; - qcom,csiphy-sd-index = <0>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <180>; - qcom,led-flash-src = <&led_flash_rear>; - qcom,actuator-src = <&actuator_rear>; - qcom,ois-src = <&ois_rear>; - qcom,eeprom-src = <&eeprom_rear>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; cam_vio-supply = <&pm8998_lvs1>; cam_vana-supply = <&pmi8998_bob>; cam_vdig-supply = <&camera_rear_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>; @@ -253,100 +320,146 @@ gpios = <&tlmm 13 0>, <&tlmm 80 0>, <&tlmm 79 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", "CAM_VANA"; - qcom,sensor-mode = <0>; - qcom,cci-master = <0>; + sensor-mode = <0>; + cci-master = <0>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; qcom,cam-sensor@1 { cell-index = <1>; compatible = "qcom,cam-sensor"; reg = <0x1>; - qcom,csiphy-sd-index = <1>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <180>; - qcom,eeprom-src = <&eeprom_rear_aux>; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; cam_vdig-supply = <&camera_ldo>; cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; - qcom,cam-vreg-min-voltage = <1050000 0 3312000>; - qcom,cam-vreg-max-voltage = <1050000 0 3600000>; - qcom,cam-vreg-op-mode = <105000 0 80000>; - qcom,gpio-no-mux = <0>; + cam_vana-supply = <&camera_vana_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 2850000 0>; + rgltr-max-voltage = <1050000 0 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + 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>, - <&tlmm 8 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1", - "CAM_VANA1"; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; qcom,cam-sensor@2 { cell-index = <2>; compatible = "qcom,cam-sensor"; reg = <0x02>; - qcom,csiphy-sd-index = <2>; - qcom,sensor-position-roll = <90>; - qcom,sensor-position-pitch = <0>; - qcom,sensor-position-yaw = <0>; - qcom,eeprom-src = <&eeprom_front>; - qcom,actuator-src = <&actuator_front>; - qcom,led-flash-src = <&led_flash_front>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; + cam_vana-supply = <&camera_vana_ldo>; cam_vdig-supply = <&camera_ldo>; - qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; - qcom,cam-vreg-min-voltage = <0 3312000 1050000>; - qcom,cam-vreg-max-voltage = <0 3600000 1050000>; - qcom,cam-vreg-op-mode = <0 80000 105000>; - qcom,gpio-no-mux = <0>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 2850000 1050000 0>; + rgltr-max-voltage = <0 2850000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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>, - <&tlmm 8 0>; - qcom,gpio-reset = <1>; - qcom,gpio-vana = <2>; - qcom,gpio-req-tbl-num = <0 1 2>; - qcom,gpio-req-tbl-flags = <1 0 0>; - qcom,gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET2", - "CAM_VANA1"; - qcom,sensor-mode = <0>; - qcom,cci-master = <1>; + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; status = "ok"; clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; clock-names = "cam_clk"; - qcom,clock-rates = <24000000>; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + led-flash-src = <&led_flash_iris>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 2850000 1050000 0>; + rgltr-max-voltage = <0 2850000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_iris_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 9 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8ad5f3ce159a86e1b688115d3bd7ca135f985d18 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qvr.dtsi @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2017, 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 { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch1>; + status = "ok"; + }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + vin-supply = <&pmi8998_bob>; + }; + + camera_rear_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm8998_gpios 12 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm8998_s3>; + }; + + camera_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm8998_gpios 9 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm8998_s3>; + }; +}; + +&cam_cci { + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_aux: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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 80 0>, + <&tlmm 79 0>, + <&tlmm 27 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vaf = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA0", + "CAM_VAF"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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>, + <&tlmm 8 0>, + <&tlmm 27 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vaf = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1", + "CAM_VAF"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0>; + rgltr-max-voltage = <1050000 0 3600000 0>; + rgltr-load-current = <105000 0 80000 0>; + 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>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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 80 0>, + <&tlmm 79 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + 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>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0>; + rgltr-max-voltage = <1050000 0 3600000 0>; + rgltr-load-current = <105000 0 80000 0>; + 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>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index cd9c8a8df0dee6592cdb1a69c8a90f8ac7d0363a..35a777405be2ccba0782703df181f19a88e18fa9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -17,17 +17,18 @@ status = "ok"; }; - qcom,csiphy@ac65000 { + cam_csiphy0: qcom,csiphy@ac65000 { cell-index = <0>; compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; reg = <0x0ac65000 0x1000>; reg-names = "csiphy"; + reg-cam-base = <0x65000>; interrupts = <0 477 0>; interrupt-names = "csiphy"; gdscr-supply = <&titan_top_gdsc>; - qcom,cam-vreg-name = "gdscr"; - qcom,csi-vdd-voltage = <1200000>; - qcom,mipi-csi-vdd-supply = <&pm8998_l26>; + regulator-names = "gdscr"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, <&clock_camcc CAM_CC_SOC_AHB_CLK>, <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, @@ -35,9 +36,7 @@ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, <&clock_camcc CAM_CC_CSIPHY0_CLK>, <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>, - <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, - <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>; + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; clock-names = "camnoc_axi_clk", "soc_ahb_clk", "slow_ahb_src_clk", @@ -45,25 +44,26 @@ "cphy_rx_clk_src", "csiphy0_clk", "csi0phytimer_clk_src", - "csi0phytimer_clk", - "ife_0_csid_clk", - "ife_0_csid_clk_src"; - qcom,clock-rates = - <0 0 80000000 0 320000000 0 269333333 0 0 384000000>; + "csi0phytimer_clk"; + clock-cntl-level = "svs", "turbo"; + clock-rates = + <0 0 0 0 320000000 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; status = "ok"; }; - qcom,csiphy@ac66000{ + cam_csiphy1: qcom,csiphy@ac66000{ cell-index = <1>; compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; reg = <0xac66000 0x1000>; reg-names = "csiphy"; + reg-cam-base = <0x66000>; interrupts = <0 478 0>; interrupt-names = "csiphy"; gdscr-supply = <&titan_top_gdsc>; - qcom,cam-vreg-name = "gdscr"; - qcom,csi-vdd-voltage = <1200000>; - qcom,mipi-csi-vdd-supply = <&pm8998_l26>; + regulator-names = "gdscr"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, <&clock_camcc CAM_CC_SOC_AHB_CLK>, <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, @@ -71,9 +71,7 @@ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, <&clock_camcc CAM_CC_CSIPHY1_CLK>, <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>, - <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, - <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>; + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; clock-names = "camnoc_axi_clk", "soc_ahb_clk", "slow_ahb_src_clk", @@ -81,26 +79,27 @@ "cphy_rx_clk_src", "csiphy1_clk", "csi1phytimer_clk_src", - "csi1phytimer_clk", - "ife_1_csid_clk", - "ife_1_csid_clk_src"; - qcom,clock-rates = - <0 0 80000000 0 320000000 0 269333333 0 0 384000000>; + "csi1phytimer_clk"; + clock-cntl-level = "svs", "turbo"; + clock-rates = + <0 0 0 0 320000000 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; status = "ok"; }; - qcom,csiphy@ac67000 { + cam_csiphy2: qcom,csiphy@ac67000 { cell-index = <2>; compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; reg = <0xac67000 0x1000>; reg-names = "csiphy"; + reg-cam-base = <0x67000>; interrupts = <0 479 0>; interrupt-names = "csiphy"; gdscr-supply = <&titan_top_gdsc>; - qcom,cam-vreg-name = "gdscr"; - qcom,csi-vdd-voltage = <1200000>; - qcom,mipi-csi-vdd-supply = <&pm8998_l26>; + regulator-names = "gdscr"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, <&clock_camcc CAM_CC_SOC_AHB_CLK>, <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, @@ -108,9 +107,7 @@ <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, <&clock_camcc CAM_CC_CSIPHY2_CLK>, <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>, - <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, - <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>; + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; clock-names = "camnoc_axi_clk", "soc_ahb_clk", "slow_ahb_src_clk", @@ -118,26 +115,27 @@ "cphy_rx_clk_src", "csiphy2_clk", "csi2phytimer_clk_src", - "csi2phytimer_clk", - "ife_lite_csid_clk", - "ife_lite_csid_clk_src"; - qcom,clock-rates = - <0 0 80000000 0 320000000 0 269333333 0 0 384000000>; + "csi2phytimer_clk"; + clock-cntl-level = "svs", "turbo"; + clock-rates = + <0 0 0 0 320000000 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; status = "ok"; }; - cci: qcom,cci@ac4a000 { + cam_cci: qcom,cci@ac4a000 { cell-index = <0>; compatible = "qcom,cci"; - reg = <0xac4a000 0x4000>; #address-cells = <1>; #size-cells = <0>; + reg = <0xac4a000 0x4000>; reg-names = "cci"; - interrupts = <0 460 0>; + reg-cam-base = <0x4a000>; interrupt-names = "cci"; + interrupts = <0 460 0>; status = "ok"; gdscr-supply = <&titan_top_gdsc>; - qcom,cam-vreg-name = "gdscr"; + regulator-names = "gdscr"; clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, <&clock_camcc CAM_CC_SOC_AHB_CLK>, <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, @@ -150,79 +148,918 @@ "cpas_ahb_clk", "cci_clk", "cci_clk_src"; - qcom,clock-rates = <0 0 80000000 0 0 37500000>; - pinctrl-names = "cci_default", "cci_suspend"; + src-clock-name = "cci_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 0 0 0 0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cci0_active &cci1_active>; pinctrl-1 = <&cci0_suspend &cci1_suspend>; gpios = <&tlmm 17 0>, <&tlmm 18 0>, <&tlmm 19 0>, <&tlmm 20 0>; - qcom,gpio-tbl-num = <0 1 2 3>; - qcom,gpio-tbl-flags = <1 1 1 1>; - qcom,gpio-tbl-label = "CCI_I2C_DATA0", + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", "CCI_I2C_CLK0", "CCI_I2C_DATA1", "CCI_I2C_CLK1"; i2c_freq_100Khz: qcom,i2c_standard_mode { - qcom,hw-thigh = <201>; - qcom,hw-tlow = <174>; - qcom,hw-tsu-sto = <204>; - qcom,hw-tsu-sta = <231>; - qcom,hw-thd-dat = <22>; - qcom,hw-thd-sta = <162>; - qcom,hw-tbuf = <227>; - qcom,hw-scl-stretch-en = <0>; - qcom,hw-trdhld = <6>; - qcom,hw-tsp = <3>; - qcom,cci-clk-src = <37500000>; + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; status = "ok"; }; i2c_freq_400Khz: qcom,i2c_fast_mode { - qcom,hw-thigh = <38>; - qcom,hw-tlow = <56>; - qcom,hw-tsu-sto = <40>; - qcom,hw-tsu-sta = <40>; - qcom,hw-thd-dat = <22>; - qcom,hw-thd-sta = <35>; - qcom,hw-tbuf = <62>; - qcom,hw-scl-stretch-en = <0>; - qcom,hw-trdhld = <6>; - qcom,hw-tsp = <3>; - qcom,cci-clk-src = <37500000>; + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; status = "ok"; }; i2c_freq_custom: qcom,i2c_custom_mode { - qcom,hw-thigh = <38>; - qcom,hw-tlow = <56>; - qcom,hw-tsu-sto = <40>; - qcom,hw-tsu-sta = <40>; - qcom,hw-thd-dat = <22>; - qcom,hw-thd-sta = <35>; - qcom,hw-tbuf = <62>; - qcom,hw-scl-stretch-en = <1>; - qcom,hw-trdhld = <6>; - qcom,hw-tsp = <3>; - qcom,cci-clk-src = <37500000>; + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; status = "ok"; }; i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { - qcom,hw-thigh = <16>; - qcom,hw-tlow = <22>; - qcom,hw-tsu-sto = <17>; - qcom,hw-tsu-sta = <18>; - qcom,hw-thd-dat = <16>; - qcom,hw-thd-sta = <15>; - qcom,hw-tbuf = <24>; - qcom,hw-scl-stretch-en = <0>; - qcom,hw-trdhld = <3>; - qcom,hw-tsp = <3>; - qcom,cci-clk-src = <37500000>; + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; status = "ok"; }; }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x808 0x0>, + <&apps_smmu 0x810 0x8>, + <&apps_smmu 0xc08 0x0>, + <&apps_smmu 0xc10 0x8>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1060 0x8>, + <&apps_smmu 0x1068 0x8>; + label = "jpeg"; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1078 0x2>, + <&apps_smmu 0x1020 0x8>, + <&apps_smmu 0x1040 0x8>, + <&apps_smmu 0x1030 0x0>, + <&apps_smmu 0x1050 0x0>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0xd800000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.3 GB */ + iova-region-name = "io"; + iova-region-start = <0xd900000>; + iova-region-len = <0xd2700000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1000 0x0>; + label = "cpas-cdm0"; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + msm_cam_smmu_fd { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1070 0x0>; + label = "fd"; + fd_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170100>; /* Titan v170 v1.0.0 */ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 19200000 0 0>, + <0 0 0 60000000 0 0>, + <0 0 0 66660000 0 0>, + <0 0 0 73840000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "fd", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "gcc_camera_ahb", + "gcc_camera_axi", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = <0 464 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = <0 465 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 480000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = <0 466 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = <0 467 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 480000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <2>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = <0 468 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <2>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = <0 469 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0>, + <0 0 0 0 0 0 480000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,ipe1", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <2>; + num-bps = <1>; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_fast_ahb", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_clk", + "icp_clk_src"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <0 0 200000000 0 0 0 0 400000000>, + <0 0 200000000 0 0 0 0 600000000>; + clock-cntl-level = "svs", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x7F 0x1FF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = + <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_ipe1: qcom,ipe1 { + cell-index = <1>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe1-vdd"; + ipe1-vdd-supply = <&ipe_1_gdsc>; + clock-names = "ipe_1_ahb_clk", + "ipe_1_areg_clk", + "ipe_1_axi_clk", + "ipe_1_clk", + "ipe_1_clk_src"; + src-clock-name = "ipe_1_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_1_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_1_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = <0 0 0 0 200000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 600000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + status = "ok"; + }; + + cam_fd: qcom,fd@ac5a000 { + cell-index = <0>; + compatible = "qcom,fd41"; + reg-names = "fd_core", "fd_wrapper"; + reg = <0xac5a000 0x1000>, + <0xac5b000 0x400>; + reg-cam-base = <0x5a000 0x5b000>; + interrupt-names = "fd"; + interrupts = <0 462 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "fd_core_clk_src", + "fd_core_clk", + "fd_core_uar_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_FD_CORE_CLK_SRC>, + <&clock_camcc CAM_CC_FD_CORE_CLK>, + <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; + src-clock-name = "fd_core_clk_src"; + clock-cntl-level = "svs", "svs_l1", "turbo"; + clock-rates = + <0 0 0 0 0 400000000 0 0>, + <0 0 0 0 0 538000000 0 0>, + <0 0 0 0 0 600000000 0 0>; + status = "ok"; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..68f2e51fea20cb8486531dc54de1336d9b4f7148 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2017, 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 "sdm845-audio-overlay.dtsi" + +&soc { + sound-tavil { + qcom,us-euro-gpios = <&tavil_us_euro_sw>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7991aad97e9a475b091a5ee2165aa4f53f05519e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp.dts index 22e3aea0710d5d2e9c867fceee9ac8e208a1b045..0a6aa5eb44f54f9da800466a9c9561f52c2ab96b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-cdp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi index 68824d78c09e337147cf160205bcbc99a53fe83a..5a88dc2405920be27eb401a9c59b14cf09ed30ba 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi @@ -11,9 +11,11 @@ */ #include +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" #include "sdm845-camera-sensor-cdp.dtsi" -/ { +&vendor { bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; qca,bt-vdd-io-supply = <&pm8998_s3>; @@ -37,10 +39,6 @@ }; &soc { - sound-tavil { - qcom,us-euro-gpios = <&tavil_us_euro_sw>; - }; - gpio_keys { compatible = "gpio-keys"; label = "gpio-keys"; @@ -93,6 +91,10 @@ }; }; +&mdss_mdp { + #cooling-cells = <2>; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3"; @@ -108,6 +110,7 @@ vdd-hba-supply = <&ufs_phy_gdsc>; vdd-hba-fixed-regulator; vcc-supply = <&pm8998_l20>; + vcc-voltage-level = <2950000 2960000>; vccq2-supply = <&pm8998_s4>; vcc-max-microamp = <600000>; vccq2-max-microamp = <600000>; @@ -118,31 +121,6 @@ status = "ok"; }; -&ufsphy_card { - compatible = "qcom,ufs-phy-qmp-v3"; - - vdda-phy-supply = <&pm8998_l1>; /* 0.88v */ - vdda-pll-supply = <&pm8998_l26>; /* 1.2v */ - vdda-phy-max-microamp = <62900>; - vdda-pll-max-microamp = <18300>; - - status = "ok"; -}; - -&ufshc_card { - vdd-hba-supply = <&ufs_card_gdsc>; - vdd-hba-fixed-regulator; - vcc-supply = <&pm8998_l21>; - vccq2-supply = <&pm8998_s4>; - vcc-max-microamp = <300000>; - vccq2-max-microamp = <300000>; - - qcom,vddp-ref-clk-supply = <&pm8998_l2>; - qcom,vddp-ref-clk-max-microamp = <100>; - - status = "ok"; -}; - &sdhc_2 { vdd-supply = <&pm8998_l21>; qcom,vdd-voltage-level = <2950000 2960000>; @@ -153,12 +131,10 @@ qcom,vdd-io-current-level = <200 22000>; pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; - pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; - qcom,clk-rates = <400000 20000000 25000000 - 50000000 100000000 200000000>; - qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>; status = "ok"; }; @@ -173,7 +149,7 @@ qcom,batteryless-platform; }; -/ { +&vendor { extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; id-gpio = <&pmi8998_gpios 9 GPIO_ACTIVE_HIGH>; @@ -196,13 +172,6 @@ pinctrl-names = "default"; pinctrl-0 = <&usb2_vbus_boost_default>; }; - -aliases { - serial0 = &qupv3_se9_2uart; - spi0 = &qupv3_se8_spi; - i2c0 = &qupv3_se10_i2c; - i2c1 = &qupv3_se3_i2c; - }; }; &qupv3_se9_2uart { @@ -219,12 +188,109 @@ aliases { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; - qcom,mdss-dsi-panel-mode-gpio-state = "dual_port"; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; }; -&dsi_dual_nt35597_truly_video_display { +&dsi_sharp_1080_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { qcom,dsi-display-active; }; @@ -233,18 +299,48 @@ aliases { qcom,led-strings-list = [01 02]; }; +&pmi8998_haptics { + qcom,vmax-mv = <2400>; + qcom,lra-auto-mode; + status = "okay"; +}; + &qupv3_se8_spi { status = "ok"; }; &qupv3_se3_i2c { status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 63 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 62 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; }; &qupv3_se10_i2c { status = "ok"; }; +&qupv3_se6_4uart { + status = "ok"; +}; + &usb1 { status = "okay"; extcon = <&extcon_usb1>; @@ -291,7 +387,6 @@ aliases { qcom,scale-function = <4>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@4d { @@ -303,7 +398,6 @@ aliases { qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@4f { @@ -315,7 +409,6 @@ aliases { qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@51 { @@ -327,7 +420,6 @@ aliases { qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; }; @@ -341,30 +433,118 @@ aliases { qcom,hw-settle-time = <0>; qcom,btm-channel-number = <0x60>; }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x80>; + qcom,thermal-node; + }; }; &thermal_zones { xo-therm-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x4c>; + thermal-sensors = <&pm8998_adc_tm 0x4c>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; msm-therm-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x4d>; + thermal-sensors = <&pm8998_adc_tm 0x4d>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; pa-therm1-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x4f>; + thermal-sensors = <&pm8998_adc_tm 0x4f>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; quiet-therm-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x51>; + thermal-sensors = <&pm8998_adc_tm 0x51>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; }; + +&wil6210 { + status = "ok"; +}; + +&ext_5v_boost { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi index 1d471f510530cd1f5c61f398db089e7c9fa7ac3c..a094f65a04028200246871d216e38fbe0d655527 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, 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 @@ -12,6 +12,33 @@ &soc { + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@6b0e000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0e000 0x1000>; + reg-names = "csr-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + qcom,blk-size = <1>; + }; + replicator_qdss: replicator@6046000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b909>; @@ -103,6 +130,7 @@ reg-names = "tmc-base"; coresight-name = "coresight-tmc-etf-swao"; + coresight-csr = <&csr>; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; @@ -156,6 +184,15 @@ }; port@1 { + reg = <6>; + funnel_swao_in_sensor_etm0: endpoint { + slave-mode; + remote-endpoint= + <&sensor_etm0_out_funnel_swao>; + }; + }; + + port@2 { reg = <7>; funnel_swao_in_tpda_swao: endpoint { slave-mode; @@ -245,6 +282,8 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,msr-fix-req; + port { tpdm_swao1_out_tpda_swao: endpoint { remote-endpoint = <&tpda_swao_in_tpdm_swao1>; @@ -265,10 +304,14 @@ coresight-name = "coresight-tmc-etr"; coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + interrupts = ; + interrupt-names = "byte-cntr-irq"; + port { tmc_etr_in_replicator: endpoint { slave-mode; @@ -286,6 +329,7 @@ coresight-name = "coresight-tmc-etf"; coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; arm,default-sink; clocks = <&clock_aop QDSS_CLK>; @@ -390,20 +434,10 @@ "ddr-ch23-ctrl"; coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; - clocks = <&clock_gcc RPMH_QDSS_CLK>, - <&clock_gcc RPMH_QDSS_A_CLK>; - clock-names = "core_clk", "core_a_clk"; - }; - - csr: csr@6001000 { - compatible = "qcom,coresight-csr"; - reg = <0x6001000 0x1000>; - reg-names = "csr-base"; - - coresight-name = "coresight-csr"; - - qcom,blk-size = <1>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; }; funnel_in0: funnel@0x6041000 { @@ -483,6 +517,16 @@ }; port@1 { + reg = <0>; + funnel_in2_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in2>; + }; + + }; + + port@2 { reg = <1>; funnel_in2_in_replicator_swao: endpoint { slave-mode; @@ -492,7 +536,7 @@ }; - port@2 { + port@3 { reg = <2>; funnel_in2_in_funnel_modem: endpoint { slave-mode; @@ -502,7 +546,7 @@ }; - port@3 { + port@4 { reg = <5>; funnel_in2_in_funnel_apss_merg: endpoint { slave-mode; @@ -511,6 +555,60 @@ }; }; + port@5 { + reg = <6>; + funnel_in2_in_funnel_gfx: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gfx_out_funnel_in2>; + }; + }; + }; + }; + + funnel_gfx: funnel@0x6943000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6943000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_gfx>; + }; + }; + + port@1 { + reg = <0>; + funnel_in2_in_gfx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_out_funnel_in2>; + }; + }; + + port@2 { + reg = <1>; + funnel_in2_in_gfx_cx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_cx_out_funnel_in2>; + }; + }; }; }; @@ -530,11 +628,13 @@ <2 32>, <3 32>, <5 32>, + <6 32>, <10 32>, <11 32>, <13 32>; qcom,cmb-elem-size = <3 64>, <7 64>, + <9 64>, <13 64>; clocks = <&clock_aop QDSS_CLK>; @@ -589,6 +689,15 @@ }; port@5 { + reg = <6>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + port@6 { reg = <7>; tpda_in_tpdm_vsense: endpoint { slave-mode; @@ -597,7 +706,16 @@ }; }; - port@6 { + port@7 { + reg = <9>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@8 { reg = <10>; tpda_in_tpdm_qm: endpoint { slave-mode; @@ -606,7 +724,7 @@ }; }; - port@7 { + port@9 { reg = <11>; tpda_in_tpdm_north: endpoint { slave-mode; @@ -615,7 +733,7 @@ }; }; - port@8 { + port@10 { reg = <13>; tpda_in_tpdm_pimem: endpoint { slave-mode; @@ -751,15 +869,56 @@ }; }; + funnel_lpass_1: funnel_1@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867010 0x10>, + <0x6845000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-lpass-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_lpass_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_lpass_1_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_lpass_1>; + }; + }; + }; + }; + tpdm_lpass: tpdm@6844000 { - compatible = "qcom,coresight-tpdm"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; reg = <0x6844000 0x1000>; reg-names = "tpdm-base"; coresight-name = "coresight-tpdm-lpass"; clocks = <&clock_aop QDSS_CLK>; - clock-names = "core_clk"; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; port { tpdm_lpass_out_funnel_lpass: endpoint { @@ -779,6 +938,8 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,msr-fix-req; + port { tpdm_center_out_tpda: endpoint { remote-endpoint = <&tpda_in_tpdm_center>; @@ -797,6 +958,8 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,msr-fix-req; + port { tpdm_north_out_tpda: endpoint { remote-endpoint = <&tpda_in_tpdm_north>; @@ -885,7 +1048,7 @@ coresight-name = "coresight-tpda-llm-silver"; qcom,tpda-atid = <72>; - qcom,cmb-elem-size = <0 64>; + qcom,cmb-elem-size = <0 32>; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; @@ -940,7 +1103,7 @@ coresight-name = "coresight-tpda-llm-gold"; qcom,tpda-atid = <73>; - qcom,cmb-elem-size = <0 64>; + qcom,cmb-elem-size = <0 32>; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; @@ -1032,6 +1195,8 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,msr-fix-req; + port { tpdm_mm_out_funnel_dl_mm: endpoint { remote-endpoint = <&funnel_dl_mm_in_tpdm_mm>; @@ -1039,6 +1204,100 @@ }; }; + funnel_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + funnel_turing_1: funnel_1@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867000 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-turing-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing_1>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + funnel_ddr_0: funnel@69e2000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; @@ -1085,6 +1344,8 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,msr-fix-req; + port { tpdm_ddr_out_funnel_ddr_0: endpoint { remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; @@ -1110,6 +1371,24 @@ }; }; + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + tpdm_vsense: tpdm@6840000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b968>; @@ -1226,7 +1505,6 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; - qcom,msr-fix-req; port{ tpdm_spss_out_tpda_spss: endpoint { @@ -1267,6 +1545,15 @@ <&tpda_spss_out_funnel_spss>; }; }; + + port@2 { + reg = <1>; + funnel_spss_in_spss_etm0: endpoint { + slave-mode; + remote-endpoint = + <&spss_etm0_out_funnel_spss>; + }; + }; }; }; @@ -1302,9 +1589,123 @@ <&tpda_out_funnel_qatb>; }; }; + + port@2 { + reg = <6>; + funnel_qatb_in_funnel_lpass_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_1_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <7>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; }; }; + cti0_ddr0: cti@69e1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e1000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@69e4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@69e5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + cti0: cti@6010000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; @@ -1341,6 +1742,10 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + + qcom,cti-gpio-trigout = <4>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; }; cti3: cti@6013000 { @@ -1617,6 +2022,48 @@ clock-names = "apb_pclk"; }; + cti0_swao:cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06B0C000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + dummy_eud: dummy_sink { compatible = "qcom,coresight-dummy"; @@ -1632,6 +2079,62 @@ }; }; + sensor_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-sensor-etm0"; + qcom,inst-id = <8>; + + port { + sensor_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_sensor_etm0>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_modem_etm0>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_lpass_1: endpoint { + remote-endpoint = + <&funnel_lpass_1_in_audio_etm0>; + }; + }; + }; + + spss_etm0 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-spss-etm0"; + + qcom,dummy-source; + port { + spss_etm0_out_funnel_spss: endpoint { + remote-endpoint = + <&funnel_spss_in_spss_etm0>; + }; + }; + }; + funnel_apss_merg: funnel@7810000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index bfbaabb07991753f9311bd1efd37714f75e6cd10..000f5d39f1fc5ccb46891a20ab31802fdd6db9c7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -12,6 +12,13 @@ &soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a630_zap"; + memory-region = <&pil_gpu_mem>; + }; + msm_bus: qcom,kgsl-busmon{ label = "kgsl-busmon"; compatible = "qcom,kgsl-busmon"; @@ -21,46 +28,40 @@ compatible = "qcom,devbw"; governor = "bw_vbif"; qcom,src-dst-ports = <26 512>; - /* - * active-only flag is used while registering the bus - * governor.It helps release the bus vote when the CPU - * subsystem is inactiv3 - */ - qcom,active-only; qcom,bw-tbl = < 0 /* off */ >, - < 762 /* 100 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2288 /* 300 MHz */ >, - < 3143 /* 412 MHz */ >, - < 4173 /* 547 MHz */ >, - < 5195 /* 681 MHz */ >, - < 5859 /* 768 MHz */ >, - < 7759 /* 1017 MHz */ >, - < 9887 /* 1296 MHz */ >, - < 11863 /* 1555 MHz */ >, - < 13763 /* 1804 MHz */ >; + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; }; msm_gpu: qcom,kgsl-3d0@5000000 { label = "kgsl-3d0"; compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; status = "ok"; - reg = <0x5000000 0x40000>; - reg-names = "kgsl_3d0_reg_memory"; + reg = <0x5000000 0x40000>, <0x5061000 0x800>; + reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_cx_dbgc_memory"; interrupts = <0 300 0>; interrupt-names = "kgsl_3d0_irq"; qcom,id = <0>; qcom,chipid = <0x06030000>; - qcom,initial-pwrlevel = <2>; + qcom,initial-pwrlevel = <5>; qcom,gpu-quirk-hfi-use-reg; - qcom,gpu-quirk-two-pass-use-wfi; + qcom,gpu-quirk-secvid-set-once; - qcom,idle-timeout = <100000000>; //msecs + qcom,idle-timeout = <80>; //msecs qcom,no-nap; qcom,highest-bank-bit = <15>; @@ -76,14 +77,16 @@ qcom,tsens-name = "tsens_tz_sensor12"; #cooling-cells = <2>; + qcom,pm-qos-active-latency = <460>; + clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>, - <&clock_gcc GCC_GPU_CFG_AHB_CLK>, <&clock_gpucc GPU_CC_CXO_CLK>, <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, - <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>; - clock-names = "core_clk", "iface_clk", "rbbmtimer_clk", - "mem_clk", "mem_iface_clk"; + clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk"; qcom,isense-clk-on-level = <1>; @@ -91,23 +94,24 @@ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; qcom,msm-bus,num-cases = <13>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <26 512 0 0>, - <26 512 0 800000>, // 1 bus=100 - <26 512 0 1200000>, // 2 bus=150 - <26 512 0 1600000>, // 3 bus=200 - <26 512 0 2400000>, // 4 bus=300 - <26 512 0 3296000>, // 5 bus=412 - <26 512 0 4376000>, // 6 bus=547 - <26 512 0 5448000>, // 7 bus=681 - <26 512 0 6144000>, // 8 bus=768 - <26 512 0 8136000>, // 9 bus=1017 - <26 512 0 10368000>, // 10 bus=1296 - <26 512 0 12440000>, // 11 bus=1555 - <26 512 0 14432000>; // 12 bus=1804 + <26 512 0 400000>, // 1 bus=100 + <26 512 0 600000>, // 2 bus=150 + <26 512 0 800000>, // 3 bus=200 + <26 512 0 1200000>, // 4 bus=300 + <26 512 0 1648000>, // 5 bus=412 + <26 512 0 2188000>, // 6 bus=547 + <26 512 0 2724000>, // 7 bus=681 + <26 512 0 3072000>, // 8 bus=768 + <26 512 0 4068000>, // 9 bus=1017 + <26 512 0 5184000>, // 10 bus=1296 + <26 512 0 6220000>, // 11 bus=1555 + <26 512 0 7216000>; // 12 bus=1804 /* GDSC regulator names */ regulator-names = "vddcx", "vdd"; @@ -119,6 +123,38 @@ cache-slice-names = "gpu", "gpuhtw"; cache-slices = <&llcc 12>, <&llcc 11>; + qcom,gpu-coresights { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-coresight"; + + status = "disabled"; + + qcom,gpu-coresight@0 { + reg = <0>; + coresight-name = "coresight-gfx"; + coresight-atid = <50>; + port { + gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_gfx>; + }; + }; + }; + + qcom,gpu-coresight@1 { + reg = <1>; + coresight-name = "coresight-gfx-cx"; + coresight-atid = <51>; + port { + gfx_cx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_gfx_cx>; + }; + }; + }; + }; + /* GPU Mempools */ qcom,gpu-mempools { #address-cells = <1>; @@ -162,7 +198,7 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <548000000>; + qcom,gpu-freq = <600000000>; qcom,bus-freq = <12>; qcom,bus-min = <11>; qcom,bus-max = <12>; @@ -171,23 +207,57 @@ qcom,gpu-pwrlevel@1 { reg = <1>; - qcom,gpu-freq = <425000000>; - qcom,bus-freq = <7>; - qcom,bus-min = <6>; - qcom,bus-max = <8>; + qcom,gpu-freq = <548000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; }; qcom,gpu-pwrlevel@2 { reg = <2>; + qcom,gpu-freq = <487000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <425000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <338000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + + qcom,gpu-pwrlevel@5 { + reg = <5>; qcom,gpu-freq = <280000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <210000000>; qcom,bus-freq = <4>; qcom,bus-min = <3>; qcom,bus-max = <5>; }; - qcom,gpu-pwrlevel@3 { - reg = <3>; - qcom,gpu-freq = <27000000>; + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; qcom,bus-max = <0>; @@ -200,7 +270,8 @@ compatible = "qcom,kgsl-smmu-v2"; reg = <0x05040000 0x10000>; - qcom,protect = <0x40000 0x10000>; + /* CB5(ATOS) & CB5/6/7 are protected by HYP */ + qcom,protect = <0x40000 0xc000>; qcom,micro-mmu-control = <0x6000>; clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>, @@ -210,7 +281,8 @@ clock-names = "iface_clk", "mem_clk", "mem_iface_clk"; qcom,secure_align_mask = <0xfff>; - qcom,global_pt; + qcom,retention; + qcom,hyp_secure_alloc; gfx3d_user: gfx3d_user { compatible = "qcom,smmu-kgsl-cb"; @@ -221,7 +293,7 @@ gfx3d_secure: gfx3d_secure { compatible = "qcom,smmu-kgsl-cb"; - iommus = <&kgsl_smmu 2>; + iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>; }; }; @@ -229,7 +301,7 @@ label = "kgsl-gmu"; compatible = "qcom,gpu-gmu"; - reg = <0x506a000 0x26000>, <0xb200000 0x300000>; + reg = <0x506a000 0x30000>, <0xb200000 0x300000>; reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_reg"; interrupts = <0 304 0>, <0 305 0>; @@ -248,13 +320,12 @@ clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>, - <&clock_gcc GCC_GPU_CFG_AHB_CLK>, <&clock_gpucc GPU_CC_CXO_CLK>, <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; - clock-names = "gmu_clk", "ahb_clk", "cxo_clk", - "axi_clk", "memnoc_clk"; + clock-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk"; qcom,gmu-pwrlevels { #address-cells = <1>; @@ -262,19 +333,20 @@ compatible = "qcom,gmu-pwrlevels"; + /* GMU power levels must go from lowest to highest */ qcom,gmu-pwrlevel@0 { reg = <0>; - qcom,gmu-freq = <400000000>; + qcom,gmu-freq = <0>; }; qcom,gmu-pwrlevel@1 { reg = <1>; - qcom,gmu-freq = <19200000>; + qcom,gmu-freq = <200000000>; }; qcom,gmu-pwrlevel@2 { reg = <2>; - qcom,gmu-freq = <0>; + qcom,gmu-freq = <400000000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-hdk-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-hdk-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..492f07ba10aca4061a9589f37e66eb0167a700f8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-hdk-audio-overlay.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, 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 "sdm845-audio-overlay.dtsi" + +&snd_934x { + qcom,model = "sdm845-tavil-hdk-snd-card"; + + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT"; + + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1c7269ab2b33fd0cd479413f7c04b072c6b2476c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi @@ -0,0 +1,445 @@ +/* Copyright (c) 2016-2018, 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. + */ + +/ { + /delete-node/regulator-pm8998-s4; +}; + +&dsi_sharp_4k_dsc_video_display { + /delete-property/ vddio-supply; +}; + +&dsi_sharp_4k_dsc_cmd_display { + /delete-property/ vddio-supply; +}; + +&dsi_sharp_1080_cmd_display { + /delete-property/ vddio-supply; +}; + +&dsi_dual_sharp_1080_120hz_cmd_display { + /delete-property/ vddio-supply; +}; + +&dsi_dual_nt35597_truly_video_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&dsi_dual_nt35597_truly_cmd_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&dsi_nt35597_truly_dsc_video_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&dsi_dual_nt35597_video_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&dsi_dual_nt35597_cmd_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&dsi_dual_nt36850_truly_cmd_display { + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; + +&sde_dp { + status = "disabled"; + /delete-property/ vdda-1p2-supply; + /delete-property/ vdda-0p9-supply; + /delete-property/ qcom,dp-usbpd-detection; +}; + +&mdss_dp_pll { + status = "disabled"; +}; + +&bluetooth { + /delete-property/ qca,bt-vdd-io-supply; + /delete-property/ qca,bt-vdd-xtal-supply; + /delete-property/ qca,bt-vdd-core-supply; + /delete-property/ qca,bt-vdd-pa-supply; + /delete-property/ qca,bt-vdd-ldo-supply; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-supply; + /delete-property/ vdda-pll-supply; +}; + +&ufshc_mem { + /delete-property/ vcc-supply; + /delete-property/ vccq2-supply; + /delete-property/ qcom,vddp-ref-clk-supply; +}; + +&sdhc_2 { + /delete-property/ vdd-supply; + /delete-property/ vdd-io-supply; +}; + +&vendor { + extcon_usb1 { + /delete-property/ id-gpio; + /delete-property/ vbus-gpio; + /delete-property/ pinctrl-names; + /delete-property/ pinctrl-0; + }; + + usb1_vbus_vreg { + /delete-property/ gpio; + /delete-property/ pinctrl-names; + /delete-property/ pinctrl-0; + }; +}; + +&qupv3_se3_i2c { + nq@28 { + /delete-property/ qcom,nq-clkreq; + /* delete "nfc_clk_default" -- PMIC GPIO */ + pinctrl-0 = <&nfc_int_active &nfc_enable_active>; + }; +}; + +&pcie0 { + /delete-property/ vreg-1.8-supply; + /delete-property/ vreg-0.9-supply; + /delete-property/ vreg-cx-supply; +}; + +&pcie1 { + /delete-property/ vreg-1.8-supply; + /delete-property/ vreg-0.9-supply; + /delete-property/ vreg-cx-supply; +}; + +&cam_csiphy0 { + /delete-property/ mipi-csi-vdd-supply; +}; + +&cam_csiphy1 { + /delete-property/ mipi-csi-vdd-supply; +}; + +&cam_csiphy2 { + /delete-property/ mipi-csi-vdd-supply; +}; + +&led_flash_rear { + /delete-property/ flash-source; + /delete-property/ torch-source; + /delete-property/ switch-source; +}; + +&led_flash_rear_aux { + /delete-property/ flash-source; + /delete-property/ torch-source; + /delete-property/ switch-source; +}; + +&led_flash_front { + /delete-property/ flash-source; + /delete-property/ torch-source; + /delete-property/ switch-source; +}; + +&led_flash_iris { + /delete-property/ flash-source; + /delete-property/ torch-source; + /delete-property/ switch-source; +}; + +&actuator_regulator { + /delete-property/ vin-supply; +}; + + +&eeprom_rear { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; +}; + +&eeprom_rear_aux { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; +}; + +&eeprom_front { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; +}; + +&cam_cci { + qcom,cam-sensor@0 { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; + }; + + qcom,cam-sensor@1 { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; + }; + + qcom,cam-sensor@2 { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; + }; + + qcom,cam-sensor@3 { + /delete-property/ cam_vio-supply; + /delete-property/ cam_vana-supply; + }; + +}; + +&clock_gcc { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_cx_ao-supply; +}; + +&clock_videocc { + /delete-property/ vdd_cx-supply; +}; + +&clock_camcc { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_mx-supply; +}; + +&clock_dispcc { + /delete-property/ vdd_cx-supply; +}; + +&clock_gpucc { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_mx-supply; +}; + +&clock_gfx { + /delete-property/ vdd_gfx-supply; +}; + +&clock_cpucc { + /delete-property/ vdd_l3_mx_ao-supply; + /delete-property/ vdd_pwrcl_mx_ao-supply; +}; + +&pil_modem { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_mx-supply; +}; + +&gpu_gx_gdsc { + /delete-property/ parent-supply; +}; + +&soc { + /delete-node/ gpio_keys; + + qcom,mss@4080000 { + /delete-property/ vdd_mss-supply; + }; + + qcom,lpass@17300000 { + /delete-property/ vdd_cx-supply; + }; + + qcom,ssc@5c00000 { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_mx-supply; + }; + + qcom,spss@1880000 { + /delete-property/ vdd_cx-supply; + /delete-property/ vdd_mx-supply; + }; + + qcom,turing@8300000 { + /delete-property/ vdd_cx-supply; + }; + + qcom,qbt1000 { + /delete-property/ qcom,finger-detect-gpio; + }; + + qcom,icnss@18800000 { + /delete-property/ vdd-0.8-cx-mx-supply; + /delete-property/ vdd-1.8-xo-supply; + /delete-property/ vdd-1.3-rfa-supply; + /delete-property/ vdd-3.3-ch0-supply; + }; + + qcom,mdss_dsi_ctrl0@ae94000 { + vdda-1p2-supply = <&pm660_l1>; + }; + + qcom,mdss_dsi_ctrl1@ae96000 { + vdda-1p2-supply = <&pm660_l1>; + }; + + qcom,mdss_dsi_phy0@ae94400 { + vdda-0p9-supply = <&pm660l_l1>; + }; + + qcom,mdss_dsi_phy0@ae96400 { + vdda-0p9-supply = <&pm660l_l1>; + }; + + gpio-regulator@1 { + /delete-property/ gpio; + /delete-property/ vin-supply; + /delete-property/ pinctrl-names; + /delete-property/ pinctrl-0; + }; + + gpio-regulator@2 { + /delete-property/ gpio; + /delete-property/ vin-supply; + /delete-property/ pinctrl-names; + /delete-property/ pinctrl-0; + }; + + gpio-regulator@4 { + /delete-property/ gpio; + /delete-property/ vin-supply; + /delete-property/ pinctrl-names; + /delete-property/ pinctrl-0; + }; + + /delete-node/ qcom,spmi-debug@6b22000; + +}; + +&wil6210 { + /delete-property/ vdd-supply; + /delete-property/ vddio-supply; +}; + +&usb0 { + /delete-property/ extcon; +}; + +&qusb_phy0 { + /delete-property/ vdd-supply; + /delete-property/ vdda18-supply; + /delete-property/ vdda33-supply; +}; + +&usb_qmp_dp_phy { + /delete-property/ vdd-supply; + /delete-property/ core-supply; +}; + +&qusb_phy1 { + /delete-property/ vdd-supply; + /delete-property/ vdda18-supply; + /delete-property/ vdda33-supply; +}; + +&usb_qmp_phy { + /delete-property/ vdd-supply; + /delete-property/ core-supply; +}; + +&soc { + /* Delete all regulators */ + /delete-node/ rpmh-regulator-ebilvl; + /delete-node/ rpmh-regulator-smpa2; + /delete-node/ rpmh-regulator-smpa3; + /delete-node/ rpmh-regulator-smpa5; + /delete-node/ rpmh-regulator-mxlvl; + /delete-node/ rpmh-regulator-smpa7; + /delete-node/ rpmh-regulator-cxlvl; + /delete-node/ rpmh-regulator-ldoa1; + /delete-node/ rpmh-regulator-ldoa2; + /delete-node/ rpmh-regulator-ldoa3; + /delete-node/ rpmh-regulator-lmxlvl; + /delete-node/ rpmh-regulator-ldoa5; + /delete-node/ rpmh-regulator-ldoa6; + /delete-node/ rpmh-regulator-ldoa7; + /delete-node/ rpmh-regulator-ldoa8; + /delete-node/ rpmh-regulator-ldoa9; + /delete-node/ rpmh-regulator-ldoa10; + /delete-node/ rpmh-regulator-ldoa11; + /delete-node/ rpmh-regulator-ldoa12; + /delete-node/ rpmh-regulator-ldoa13; + /delete-node/ rpmh-regulator-ldoa14; + /delete-node/ rpmh-regulator-ldoa15; + /delete-node/ rpmh-regulator-ldoa16; + /delete-node/ rpmh-regulator-ldoa17; + /delete-node/ rpmh-regulator-ldoa18; + /delete-node/ rpmh-regulator-ldoa19; + /delete-node/ rpmh-regulator-ldoa20; + /delete-node/ rpmh-regulator-ldoa21; + /delete-node/ rpmh-regulator-ldoa22; + /delete-node/ rpmh-regulator-ldoa23; + /delete-node/ rpmh-regulator-ldoa24; + /delete-node/ rpmh-regulator-ldoa25; + /delete-node/ rpmh-regulator-ldoa26; + /delete-node/ rpmh-regulator-lcxlvl; + /delete-node/ rpmh-regulator-ldoa28; + /delete-node/ rpmh-regulator-vsa1; + /delete-node/ rpmh-regulator-vsa2; + /delete-node/ rpmh-regulator-bobb1; + /delete-node/ rpmh-regulator-gfxlvl; + /delete-node/ rpmh-regulator-msslvl; + /delete-node/ rpmh-regulator-smpc3; +}; + +&spmi_bus { + /delete-node/ qcom,pm8998@0; + /delete-node/ qcom,pm8998@1; + /delete-node/ qcom,pm8005@4; + /delete-node/ qcom,pm8005@5; +}; + +/delete-node/ &pmi8998_lsid0; +/delete-node/ &pmi8998_lsid1; +/delete-node/ &ext_5v_boost; + +#include "pm660.dtsi" +#include "pm660l.dtsi" +#include "sdm670-regulator.dtsi" +#include "sdm670-pmic-overlay.dtsi" + +&soc { + /delete-node/ thermal-zones; +}; + +&lmh_dcvs1 { + /delete-property/ isens_vref-supply; + /delete-property/ isens-vref-settings; +}; + +&pm660l_wled { + qcom,led-strings-list = [01 02]; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..54bd52012fcc4e1695656f892d80c0dec099552c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio-overlay.dtsi @@ -0,0 +1,53 @@ +/* Copyright (c) 2017, 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 "sdm670-audio-overlay.dtsi" + +&pm660l_3 { + /delete-node/analog-codec; +}; + +&soc { + /delete-node/msm-sdw-codec@62ec1000; + /delete-node/cdc_pdm_pinctrl; + /delete-node/wsa_spkr_en1_pinctrl; + /delete-node/wsa_spkr_en2_pinctrl; + /delete-node/sdw_clk_data_pinctrl; +}; + +&qupv3_se8_spi { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; + qcom,gpio-connect = <&tlmm 54 0>; +}; + +&wdsp_mgr { + status = "okay"; +}; + +&wdsp_glink { + status = "okay"; +}; + +&wcd934x_cdc { + status = "okay"; +}; + +&clock_audio_lnbb { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi similarity index 71% rename from arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi rename to arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi index 4b3fa93ac1666451ba3d5c6fa32af321eb106996..88892d799af3942f5792140d10a41e55631a06c0 100644 --- a/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi @@ -10,14 +10,24 @@ * GNU General Public License for more details. */ + +&msm_audio_ion { + iommus = <&apps_smmu 0x1821 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + &soc { - tlmm: pinctrl@03400000 { - compatible = "qcom,sdm830-pinctrl"; - reg = <0x03400000 0xc00000>; - interrupts = <0 208 0>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; + /delete-node/sound; +}; + +&tavil_snd { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..9d61324b1e90984734fd142a41bb02cf3b301cf0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-interposer-sdm670-cdp.dtsi" +#include "sdm845-interposer-sdm670-audio-overlay.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 Interposer SDM670 CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x0>; + qcom,board-id = <1 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..597773e23236d9e8ab6d7d0580225331d496ddca --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2017, 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 "sdm845-interposer-sdm670.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-interposer-sdm670-cdp.dtsi" +#include "sdm670-audio.dtsi" +#include "sdm845-interposer-sdm670-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM sdm845 v1 Interposer SDM670 CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,board-id = <1 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9313a75a9673502db8b262519721f53523227d38 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi @@ -0,0 +1,43 @@ +/* Copyright (c) 2017, 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 "sdm845-cdp.dtsi" +#include "sdm845-interposer-pm660.dtsi" + +&soc { + /delete-node/ ssusb@a800000; + /delete-node/ qusb@88e3000; + /delete-node/ ssphy@88eb000; +}; + +&usb0 { + extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */; +}; + +&qusb_phy0 { + vdd-supply = <&pm660l_l1>; + vdda18-supply = <&pm660_l10>; + vdda33-supply = <&pm660l_l7>; +}; + +&usb_qmp_dp_phy { + vdd-supply = <&pm660l_l1>; /* 0.88v */ + core-supply = <&pm660_l1>; /* 1.2v */ +}; + +&pcie0 { + status = "disabled"; +}; + +&eud { + vdda33-supply = <&pm660l_l7>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1690174670e91dde7a81f417ddc410e7dc24c4d2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-interposer-sdm670-mtp.dtsi" +#include "sdm845-interposer-sdm670-audio-overlay.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 Interposer SDM670 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x0>; + qcom,board-id = <8 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..52869da35f538ecb1a7c8563dc8378528c1d6fa3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2017, 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 "sdm845-interposer-sdm670.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-interposer-sdm670-mtp.dtsi" +#include "sdm670-audio.dtsi" +#include "sdm845-interposer-sdm670-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM sdm845 v1 Interposer SDM670 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,board-id = <8 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e7ff910332712a0a24de6cb48222d1f5cc2f4143 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi @@ -0,0 +1,48 @@ +/* Copyright (c) 2017, 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 "sdm845-mtp.dtsi" +#include "sdm845-interposer-pm660.dtsi" + +&qupv3_se10_i2c { + /delete-node/ qcom,smb1355@8; + /delete-node/ qcom,smb1355@c; +}; + +&soc { + /delete-node/ ssusb@a800000; + /delete-node/ qusb@88e3000; + /delete-node/ ssphy@88eb000; +}; + +&usb0 { + extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */; +}; + +&qusb_phy0 { + vdd-supply = <&pm660l_l1>; + vdda18-supply = <&pm660_l10>; + vdda33-supply = <&pm660l_l7>; +}; + +&usb_qmp_dp_phy { + vdd-supply = <&pm660l_l1>; /* 0.88v */ + core-supply = <&pm660_l1>; /* 1.2v */ +}; + +&pcie0 { + status = "disabled"; +}; + +&eud { + vdda33-supply = <&pm660l_l7>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dts new file mode 100644 index 0000000000000000000000000000000000000000..c5e4ae1ff5d18651d0c8b2499d7f37b8c38d82d9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sdm845-interposer-sdm670.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 Interposer SDM670"; + compatible = "qcom,sdm845"; + qcom,msm-id = <321 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9341507487fbb0881720349aa216c79738d7ff40 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2017, 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 "sdm845.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 Interposer SDM670"; + compatible = "qcom,sdm845"; + qcom,msm-id = <321 0x0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi index 25798199b6499a882b9a67e9e1dc2dff37b39295..7d8318497c507a31c79574d5ee08fb262b5e4d24 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, 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 @@ -33,12 +33,18 @@ qcom,ion-heap-type = "DMA"; }; - qcom,ion-heap@13 { /* SPSS HEAP */ - reg = <13>; - memory-region = <&sp_mem>; + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; qcom,ion-heap-type = "DMA"; }; + qcom,ion-heap@13 { /* SECURE SPSS HEAP */ + reg = <13>; + memory-region = <&secure_sp_mem>; + qcom,ion-heap-type = "HYP_CMA"; + }; + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ reg = <10>; memory-region = <&secure_display_memory>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..2d1d9b637c9f805db1a6be40263498b93c4e958d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index f7af60c9aa36815896c95aadcf24b818cf07ab28..e74b342e521b3da67ee7629f3219a653ab3d8e50 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-mtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi index 43911890095ba17da6ac5bc44e9d759c6e2c818f..fc4b674f3b63c504b1c627c5d0344e083623ba0b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -11,9 +11,12 @@ */ #include +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" #include "sdm845-camera-sensor-mtp.dtsi" +#include "smb1355.dtsi" -/ { +&vendor { bluetooth: bt_wcn3990 { compatible = "qca,wcn3990"; qca,bt-vdd-io-supply = <&pm8998_s3>; @@ -88,12 +91,101 @@ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; - qcom,mdss-dsi-panel-mode-gpio-state = "dual_port"; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; }; -&dsi_dual_nt35597_truly_video_display { +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { qcom,dsi-display-active; }; @@ -102,6 +194,16 @@ qcom,led-strings-list = [01 02]; }; +&pmi8998_haptics { + qcom,vmax-mv = <2400>; + qcom,lra-auto-mode; + status = "okay"; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3"; @@ -117,6 +219,7 @@ vdd-hba-supply = <&ufs_phy_gdsc>; vdd-hba-fixed-regulator; vcc-supply = <&pm8998_l20>; + vcc-voltage-level = <2950000 2960000>; vccq2-supply = <&pm8998_s4>; vcc-max-microamp = <600000>; vccq2-max-microamp = <600000>; @@ -127,31 +230,6 @@ status = "ok"; }; -&ufsphy_card { - compatible = "qcom,ufs-phy-qmp-v3"; - - vdda-phy-supply = <&pm8998_l1>; /* 0.88v */ - vdda-pll-supply = <&pm8998_l26>; /* 1.2v */ - vdda-phy-max-microamp = <62900>; - vdda-pll-max-microamp = <18300>; - - status = "ok"; -}; - -&ufshc_card { - vdd-hba-supply = <&ufs_card_gdsc>; - vdd-hba-fixed-regulator; - vcc-supply = <&pm8998_l21>; - vccq2-supply = <&pm8998_s4>; - vcc-max-microamp = <300000>; - vccq2-max-microamp = <300000>; - - qcom,vddp-ref-clk-supply = <&pm8998_l2>; - qcom,vddp-ref-clk-max-microamp = <100>; - - status = "ok"; -}; - &sdhc_2 { vdd-supply = <&pm8998_l21>; qcom,vdd-voltage-level = <2950000 2960000>; @@ -161,13 +239,20 @@ qcom,vdd-io-voltage-level = <1808000 2960000>; qcom,vdd-io-current-level = <200 22000>; - pinctrl-names = "active", "sleep"; - pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; - pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; - - qcom,clk-rates = <400000 20000000 25000000 - 50000000 100000000 200000000>; - qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + pinctrl-names = "active", "sleep", "ds_400KHz", + "ds_50MHz", "ds_100MHz", "ds_200MHz"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + pinctrl-2 = <&sdc2_clk_ds_400KHz + &sdc2_cmd_ds_400KHz &sdc2_data_ds_400KHz>; + pinctrl-3 = <&sdc2_clk_ds_50MHz + &sdc2_cmd_ds_50MHz &sdc2_data_ds_50MHz>; + pinctrl-4 = <&sdc2_clk_ds_100MHz + &sdc2_cmd_ds_100MHz &sdc2_data_ds_100MHz>; + pinctrl-5 = <&sdc2_clk_ds_200MHz + &sdc2_cmd_ds_200MHz &sdc2_data_ds_200MHz>; + + cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>; status = "ok"; }; @@ -178,7 +263,13 @@ pinctrl-1 = <&flash_led3_front_dis>; }; -/{ +&pmi8998_switch2 { + pinctrl-names = "led_enable", "led_disable"; + pinctrl-0 = <&flash_led3_iris_en>; + pinctrl-1 = <&flash_led3_iris_dis>; +}; + +&vendor { mtp_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; #include "fg-gen3-batterydata-itech-3000mah.dtsi" @@ -199,13 +290,14 @@ qcom,battery-data = <&mtp_batterydata>; }; -/ { -aliases { - serial0 = &qupv3_se9_2uart; - spi0 = &qupv3_se8_spi; - i2c0 = &qupv3_se10_i2c; - i2c1 = &qupv3_se3_i2c; - }; +&smb1355_charger_0 { + status = "ok"; + qcom,disable-ctm; +}; + +&smb1355_charger_1 { + status = "ok"; + qcom,disable-ctm; }; &qupv3_se9_2uart { @@ -218,12 +310,36 @@ aliases { &qupv3_se3_i2c { status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 63 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 62 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; }; &qupv3_se10_i2c { status = "ok"; }; +&qupv3_se6_4uart { + status = "ok"; +}; + &usb1 { status = "okay"; extcon = <&extcon_usb1>; @@ -233,6 +349,10 @@ aliases { status = "okay"; }; +&ext_5v_boost { + status = "ok"; +}; + &usb_qmp_phy { status = "okay"; }; @@ -269,7 +389,6 @@ aliases { qcom,scale-function = <4>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@4d { @@ -281,7 +400,6 @@ aliases { qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@4f { @@ -293,7 +411,6 @@ aliases { qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@51 { @@ -305,7 +422,6 @@ aliases { qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; }; @@ -319,30 +435,114 @@ aliases { qcom,hw-settle-time = <0>; qcom,btm-channel-number = <0x60>; }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x80>; + qcom,thermal-node; + }; }; &thermal_zones { xo-therm-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x4c>; + thermal-sensors = <&pm8998_adc_tm 0x4c>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; msm-therm-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x4d>; + thermal-sensors = <&pm8998_adc_tm 0x4d>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; pa-therm1-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x4f>; + thermal-sensors = <&pm8998_adc_tm 0x4f>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; quiet-therm-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_vadc 0x51>; + thermal-sensors = <&pm8998_adc_tm 0x51>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; }; }; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..af7feb5c24f1940cfe64b6d0c8135c3f80ec1329 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2017-2018, 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 + +&soc { + pcie0: qcom,pcie@0x1c00000 { + compatible = "qcom,pci-msm"; + cell-index = <0>; + + reg = <0x1c00000 0x2000>, + <0x1c06000 0x1000>, + <0x60000000 0xf1d>, + <0x60000f20 0xa8>, + <0x60100000 0x100000>, + <0x60200000 0x100000>, + <0x60300000 0xd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x60200000 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x60300000 0x0 0xd00000>; + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + 36 37>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &pdc 0 141 0 + 0 0 0 1 &pdc 0 149 0 + 0 0 0 2 &pdc 0 150 0 + 0 0 0 3 &pdc 0 151 0 + 0 0 0 4 &pdc 0 152 0 + 0 0 0 5 &pdc 0 140 0 + 0 0 0 6 &pdc 0 672 0 + 0 0 0 7 &pdc 0 673 0 + 0 0 0 8 &pdc 0 674 0 + 0 0 0 9 &pdc 0 675 0 + 0 0 0 10 &pdc 0 676 0 + 0 0 0 11 &pdc 0 677 0 + 0 0 0 12 &pdc 0 678 0 + 0 0 0 13 &pdc 0 679 0 + 0 0 0 14 &pdc 0 680 0 + 0 0 0 15 &pdc 0 681 0 + 0 0 0 16 &pdc 0 682 0 + 0 0 0 17 &pdc 0 683 0 + 0 0 0 18 &pdc 0 684 0 + 0 0 0 19 &pdc 0 685 0 + 0 0 0 20 &pdc 0 686 0 + 0 0 0 21 &pdc 0 687 0 + 0 0 0 22 &pdc 0 688 0 + 0 0 0 23 &pdc 0 689 0 + 0 0 0 24 &pdc 0 690 0 + 0 0 0 25 &pdc 0 691 0 + 0 0 0 26 &pdc 0 692 0 + 0 0 0 27 &pdc 0 693 0 + 0 0 0 28 &pdc 0 694 0 + 0 0 0 29 &pdc 0 695 0 + 0 0 0 30 &pdc 0 696 0 + 0 0 0 31 &pdc 0 697 0 + 0 0 0 32 &pdc 0 698 0 + 0 0 0 33 &pdc 0 699 0 + 0 0 0 34 &pdc 0 700 0 + 0 0 0 35 &pdc 0 701 0 + 0 0 0 36 &pdc 0 702 0 + 0 0 0 37 &pdc 0 703 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; + + qcom,phy-sequence = <0x804 0x01 0x0 + 0x034 0x14 0x0 + 0x138 0x30 0x0 + 0x048 0x07 0x0 + 0x15c 0x06 0x0 + 0x090 0x01 0x0 + 0x088 0x20 0x0 + 0x0f0 0x00 0x0 + 0x0f8 0x01 0x0 + 0x0f4 0xc9 0x0 + 0x11c 0xff 0x0 + 0x120 0x3f 0x0 + 0x164 0x01 0x0 + 0x154 0x00 0x0 + 0x148 0x0a 0x0 + 0x05c 0x19 0x0 + 0x038 0x90 0x0 + 0x0b0 0x82 0x0 + 0x0c0 0x02 0x0 + 0x0bc 0xea 0x0 + 0x0b8 0xab 0x0 + 0x0a0 0x00 0x0 + 0x09c 0x0d 0x0 + 0x098 0x04 0x0 + 0x13c 0x00 0x0 + 0x060 0x06 0x0 + 0x068 0x16 0x0 + 0x070 0x36 0x0 + 0x184 0x01 0x0 + 0x138 0x33 0x0 + 0x03c 0x02 0x0 + 0x040 0x06 0x0 + 0x080 0x04 0x0 + 0x0dc 0x00 0x0 + 0x0d8 0x3f 0x0 + 0x00c 0x09 0x0 + 0x010 0x01 0x0 + 0x01c 0x40 0x0 + 0x020 0x01 0x0 + 0x014 0x02 0x0 + 0x018 0x00 0x0 + 0x024 0x7e 0x0 + 0x028 0x15 0x0 + 0x244 0x02 0x0 + 0x2a4 0x12 0x0 + 0x260 0x10 0x0 + 0x28c 0x06 0x0 + 0x504 0x03 0x0 + 0x500 0x10 0x0 + 0x50c 0x14 0x0 + 0x4d4 0x0e 0x0 + 0x4d8 0x04 0x0 + 0x4dc 0x1a 0x0 + 0x434 0x4b 0x0 + 0x414 0x04 0x0 + 0x40c 0x04 0x0 + 0x4f8 0x71 0x0 + 0x564 0x59 0x0 + 0x568 0x59 0x0 + 0x4fc 0x80 0x0 + 0x51c 0x40 0x0 + 0x444 0x71 0x0 + 0x43c 0x40 0x0 + 0x854 0x04 0x0 + 0x62c 0x52 0x0 + 0x654 0x10 0x0 + 0x65c 0x1a 0x0 + 0x660 0x06 0x0 + 0x8c8 0x83 0x0 + 0x8cc 0x09 0x0 + 0x8d0 0xa2 0x0 + 0x8d4 0x40 0x0 + 0x8c4 0x02 0x0 + 0x9ac 0x00 0x0 + 0x8a0 0x01 0x0 + 0x9e0 0x00 0x0 + 0x9dc 0x20 0x0 + 0x9a8 0x00 0x0 + 0x8a4 0x01 0x0 + 0x8a8 0x73 0x0 + 0x9d8 0xbb 0x0 + 0x9b0 0x03 0x0 + 0xa0c 0x0d 0x0 + 0x86c 0x00 0x0 + 0x644 0x00 0x0 + 0x804 0x03 0x0 + 0x800 0x00 0x0 + 0x808 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 35 0>; + wake-gpio = <&tlmm 37 0>; + + gdsc-vdd-supply = <&pcie_0_gdsc>; + vreg-1.8-supply = <&pm8998_l26>; + vreg-0.9-supply = <&pm8998_l1>; + vreg-cx-supply = <&pm8998_s9_level>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,l1-supported; + qcom,l1ss-supported; + qcom,aux-clk-sync; + + qcom,ep-latency = <10>; + + qcom,phy-status-offset = <0x974>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <0>; + + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x2c0>; + + qcom,pcie-phy-ver = <0x30>; + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x1c10>; + + iommu-map = <0x0 &apps_smmu 0x1c10 0x1>, + <0x100 &apps_smmu 0x1c11 0x1>, + <0x200 &apps_smmu 0x1c12 0x1>, + <0x300 &apps_smmu 0x1c13 0x1>, + <0x400 &apps_smmu 0x1c14 0x1>, + <0x500 &apps_smmu 0x1c15 0x1>, + <0x600 &apps_smmu 0x1c16 0x1>, + <0x700 &apps_smmu 0x1c17 0x1>, + <0x800 &apps_smmu 0x1c18 0x1>, + <0x900 &apps_smmu 0x1c19 0x1>, + <0xa00 &apps_smmu 0x1c1a 0x1>, + <0xb00 &apps_smmu 0x1c1b 0x1>, + <0xc00 &apps_smmu 0x1c1c 0x1>, + <0xd00 &apps_smmu 0x1c1d 0x1>, + <0xe00 &apps_smmu 0x1c1e 0x1>, + <0xf00 &apps_smmu 0x1c1f 0x1>; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_0_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_0_AUX_CLK>, + <&clock_gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>, + <&clock_gcc GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + }; + + pcie1: qcom,pcie@0x1c08000 { + compatible = "qcom,pci-msm"; + cell-index = <1>; + + reg = <0x1c08000 0x2000>, + <0x1c0a000 0x2000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1fd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1fd00000>; + interrupt-parent = <&pcie1>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + 36 37>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 307 0 + 0 0 0 1 &intc 0 434 0 + 0 0 0 2 &intc 0 435 0 + 0 0 0 3 &intc 0 438 0 + 0 0 0 4 &intc 0 439 0 + 0 0 0 5 &intc 0 306 0 + 0 0 0 6 &intc 0 704 0 + 0 0 0 7 &intc 0 705 0 + 0 0 0 8 &intc 0 706 0 + 0 0 0 9 &intc 0 707 0 + 0 0 0 10 &intc 0 708 0 + 0 0 0 11 &intc 0 709 0 + 0 0 0 12 &intc 0 710 0 + 0 0 0 13 &intc 0 711 0 + 0 0 0 14 &intc 0 712 0 + 0 0 0 15 &intc 0 713 0 + 0 0 0 16 &intc 0 714 0 + 0 0 0 17 &intc 0 715 0 + 0 0 0 18 &intc 0 716 0 + 0 0 0 19 &intc 0 717 0 + 0 0 0 20 &intc 0 718 0 + 0 0 0 21 &intc 0 719 0 + 0 0 0 22 &intc 0 720 0 + 0 0 0 23 &intc 0 721 0 + 0 0 0 24 &intc 0 722 0 + 0 0 0 25 &intc 0 723 0 + 0 0 0 26 &intc 0 724 0 + 0 0 0 27 &intc 0 725 0 + 0 0 0 28 &intc 0 726 0 + 0 0 0 29 &intc 0 727 0 + 0 0 0 30 &intc 0 728 0 + 0 0 0 31 &intc 0 729 0 + 0 0 0 32 &intc 0 730 0 + 0 0 0 33 &intc 0 731 0 + 0 0 0 34 &intc 0 732 0 + 0 0 0 35 &intc 0 733 0 + 0 0 0 36 &intc 0 734 0 + 0 0 0 37 &intc 0 735 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; + + qcom,phy-sequence = <0x1804 0x03 0x0 + 0x00dc 0x27 0x0 + 0x0014 0x01 0x0 + 0x0020 0x31 0x0 + 0x0024 0x01 0x0 + 0x0028 0xde 0x0 + 0x002c 0x07 0x0 + 0x0034 0x4c 0x0 + 0x0038 0x06 0x0 + 0x0054 0x18 0x0 + 0x0058 0xb0 0x0 + 0x006c 0x8c 0x0 + 0x0070 0x20 0x0 + 0x0078 0x14 0x0 + 0x007c 0x34 0x0 + 0x00b4 0x06 0x0 + 0x00b8 0x06 0x0 + 0x00c0 0x16 0x0 + 0x00c4 0x16 0x0 + 0x00cc 0x36 0x0 + 0x00d0 0x36 0x0 + 0x00f0 0x05 0x0 + 0x00f8 0x42 0x0 + 0x0100 0x82 0x0 + 0x0108 0x68 0x0 + 0x011c 0x55 0x0 + 0x0120 0x55 0x0 + 0x0124 0x03 0x0 + 0x0128 0xab 0x0 + 0x012c 0xaa 0x0 + 0x0130 0x02 0x0 + 0x0150 0x3f 0x0 + 0x0158 0x3f 0x0 + 0x0178 0x10 0x0 + 0x01cc 0x04 0x0 + 0x01d0 0x30 0x0 + 0x01e0 0x04 0x0 + 0x01e8 0x73 0x0 + 0x01f0 0x1c 0x0 + 0x01fc 0x15 0x0 + 0x021c 0x04 0x0 + 0x0224 0x01 0x0 + 0x0228 0x22 0x0 + 0x022c 0x00 0x0 + 0x0098 0x05 0x0 + 0x080c 0x00 0x0 + 0x0818 0x0d 0x0 + 0x0860 0x01 0x0 + 0x0864 0x3a 0x0 + 0x087c 0x2f 0x0 + 0x08c0 0x09 0x0 + 0x08c4 0x09 0x0 + 0x08c8 0x1a 0x0 + 0x08d0 0x01 0x0 + 0x08d4 0x07 0x0 + 0x08d8 0x31 0x0 + 0x08dc 0x31 0x0 + 0x08e0 0x03 0x0 + 0x08fc 0x02 0x0 + 0x0900 0x01 0x0 + 0x0908 0x12 0x0 + 0x0914 0x25 0x0 + 0x0918 0x00 0x0 + 0x091c 0x05 0x0 + 0x0920 0x01 0x0 + 0x0924 0x26 0x0 + 0x0928 0x12 0x0 + 0x0930 0x04 0x0 + 0x0934 0x04 0x0 + 0x0938 0x09 0x0 + 0x0954 0x15 0x0 + 0x0960 0x32 0x0 + 0x0968 0x7f 0x0 + 0x096c 0x07 0x0 + 0x0978 0x04 0x0 + 0x0980 0x70 0x0 + 0x0984 0x8b 0x0 + 0x0988 0x08 0x0 + 0x098c 0x09 0x0 + 0x0990 0x03 0x0 + 0x0994 0x04 0x0 + 0x0998 0x02 0x0 + 0x099c 0x0c 0x0 + 0x09a4 0x02 0x0 + 0x09c0 0x5c 0x0 + 0x09c4 0x3e 0x0 + 0x09c8 0x3f 0x0 + 0x0a30 0x01 0x0 + 0x0a34 0xa0 0x0 + 0x0a38 0x08 0x0 + 0x0aa4 0x01 0x0 + 0x0aac 0xc3 0x0 + 0x0ab0 0x00 0x0 + 0x0ab8 0x8c 0x0 + 0x0ac0 0x7f 0x0 + 0x0ac4 0x2a 0x0 + 0x0810 0x0c 0x0 + 0x0814 0x00 0x0 + 0x0acc 0x04 0x0 + 0x093c 0x20 0x0 + 0x100c 0x00 0x0 + 0x1018 0x0d 0x0 + 0x1060 0x01 0x0 + 0x1064 0x3a 0x0 + 0x107c 0x2f 0x0 + 0x10c0 0x09 0x0 + 0x10c4 0x09 0x0 + 0x10c8 0x1a 0x0 + 0x10d0 0x01 0x0 + 0x10d4 0x07 0x0 + 0x10d8 0x31 0x0 + 0x10dc 0x31 0x0 + 0x10e0 0x03 0x0 + 0x10fc 0x02 0x0 + 0x1100 0x01 0x0 + 0x1108 0x12 0x0 + 0x1114 0x25 0x0 + 0x1118 0x00 0x0 + 0x111c 0x05 0x0 + 0x1120 0x01 0x0 + 0x1124 0x26 0x0 + 0x1128 0x12 0x0 + 0x1130 0x04 0x0 + 0x1134 0x04 0x0 + 0x1138 0x09 0x0 + 0x1154 0x15 0x0 + 0x1160 0x32 0x0 + 0x1168 0x7f 0x0 + 0x116c 0x07 0x0 + 0x1178 0x04 0x0 + 0x1180 0x70 0x0 + 0x1184 0x8b 0x0 + 0x1188 0x08 0x0 + 0x118c 0x09 0x0 + 0x1190 0x03 0x0 + 0x1194 0x04 0x0 + 0x1198 0x02 0x0 + 0x119c 0x0c 0x0 + 0x11a4 0x02 0x0 + 0x11c0 0x5c 0x0 + 0x11c4 0x3e 0x0 + 0x11c8 0x3f 0x0 + 0x1230 0x01 0x0 + 0x1234 0xa0 0x0 + 0x1238 0x08 0x0 + 0x12a4 0x01 0x0 + 0x12ac 0xc3 0x0 + 0x12b0 0x00 0x0 + 0x12b8 0x8c 0x0 + 0x12c0 0x7f 0x0 + 0x12c4 0x2a 0x0 + 0x1010 0x0c 0x0 + 0x1014 0x00 0x0 + 0x12cc 0x04 0x0 + 0x113c 0x20 0x0 + 0x195c 0x3f 0x0 + 0x1974 0x58 0x0 + 0x196c 0x9f 0x0 + 0x182c 0x19 0x0 + 0x1840 0x07 0x0 + 0x1854 0x17 0x0 + 0x1868 0x09 0x0 + 0x1800 0x00 0x0 + 0x0aa8 0x01 0x0 + 0x12a8 0x01 0x0 + 0x1808 0x01 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_clkreq_default + &pcie1_perst_default + &pcie1_wake_default>; + + perst-gpio = <&tlmm 102 0>; + wake-gpio = <&tlmm 104 0>; + + gdsc-vdd-supply = <&pcie_1_gdsc>; + vreg-1.8-supply = <&pm8998_l26>; + vreg-0.9-supply = <&pm8998_l1>; + vreg-cx-supply = <&pm8998_s9_level>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,l1-supported; + qcom,l1ss-supported; + qcom,aux-clk-sync; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x20000000>; + + qcom,phy-status-offset = <0x1aac>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <1>; + + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x2e0>; + + qcom,max-link-speed = <0x3>; + + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x1c00>; + + iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, + <0x100 &apps_smmu 0x1c01 0x1>, + <0x200 &apps_smmu 0x1c02 0x1>, + <0x300 &apps_smmu 0x1c03 0x1>, + <0x400 &apps_smmu 0x1c04 0x1>, + <0x500 &apps_smmu 0x1c05 0x1>, + <0x600 &apps_smmu 0x1c06 0x1>, + <0x700 &apps_smmu 0x1c07 0x1>, + <0x800 &apps_smmu 0x1c08 0x1>, + <0x900 &apps_smmu 0x1c09 0x1>, + <0xa00 &apps_smmu 0x1c0a 0x1>, + <0xb00 &apps_smmu 0x1c0b 0x1>, + <0xc00 &apps_smmu 0x1c0c 0x1>, + <0xd00 &apps_smmu 0x1c0d 0x1>, + <0xe00 &apps_smmu 0x1c0e 0x1>, + <0xf00 &apps_smmu 0x1c0f 0x1>; + + qcom,msm-bus,name = "pcie1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_1_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_1_AUX_CLK>, + <&clock_gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_1_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_1_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_1_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>, + <&clock_gcc GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_1_pipe_clk", "pcie_1_ref_clk_src", + "pcie_1_aux_clk", "pcie_1_cfg_ahb_clk", + "pcie_1_mstr_axi_clk", "pcie_1_slv_axi_clk", + "pcie_1_ldo", "pcie_1_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_1_BCR>, + <&clock_gcc GCC_PCIE_1_PHY_BCR>; + + reset-names = "pcie_1_core_reset", + "pcie_1_phy_reset"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..67933c3784f755c28d0b68989ab91cb0a14f078c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi @@ -0,0 +1,63 @@ +/* Copyright (c) 2017, 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. + */ + +&pmi8998_gpios { + usb2_vbus_boost { + usb2_vbus_boost_default: usb2_vbus_boost_default { + pins = "gpio2"; + function = "normal"; + output-low; + power-source = <0>; + }; + }; + + qnovo_fet_ctrl { + qnovo_fet_ctrl_default: qnovo_fet_ctrl_default { + pins = "gpio6"; + function = "func1"; + output-low; + input-disable; + bias-disable; + power-source = <0>; + qcom,drive-strength = <1>; + }; + }; + + usb2_vbus_det { + usb2_vbus_det_default: usb2_vbus_det_default { + pins = "gpio8"; + function = "normal"; + input-enable; + bias-pull-down; + power-source = <1>; /* VPH input supply */ + }; + }; + + usb2_id_det { + usb2_id_det_default: usb2_id_det_default { + pins = "gpio9"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + usb2_ext_5v_boost { + usb2_ext_5v_boost_default: usb2_ext_5v_boost_default { + pins = "gpio10"; + function = "normal"; + output-low; + power-source = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi index d6af58be80a02b4c7d8d7249fa6b4c374a21560d..78be79033660451532b1dd7c7add1317b926f404 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, 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 @@ -19,6 +19,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + interrupt-parent = <&pdc>; ufs_dev_reset_assert: ufs_dev_reset_assert { config { @@ -96,6 +97,37 @@ }; }; + flash_led3_iris { + flash_led3_iris_en: flash_led3_iris_en { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_iris_dis: flash_led3_iris_dis { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; + + wcd9xxx_intr { wcd_intr_default: wcd_intr_default{ mux { @@ -112,6 +144,19 @@ }; }; + storage_cd: storage_cd { + mux { + pins = "gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio126"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + sdc2_clk_on: sdc2_clk_on { config { pins = "sdc2_clk"; @@ -128,6 +173,38 @@ }; }; + sdc2_clk_ds_400KHz: sdc2_clk_ds_400KHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_ds_50MHz: sdc2_clk_ds_50MHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_ds_100MHz: sdc2_clk_ds_100MHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_ds_200MHz: sdc2_clk_ds_200MHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + sdc2_cmd_on: sdc2_cmd_on { config { pins = "sdc2_cmd"; @@ -144,6 +221,38 @@ }; }; + sdc2_cmd_ds_400KHz: sdc2_cmd_ds_400KHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_ds_50MHz: sdc2_cmd_ds_50MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_ds_100MHz: sdc2_cmd_ds_100MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_ds_200MHz: sdc2_cmd_ds_200MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + sdc2_data_on: sdc2_data_on { config { pins = "sdc2_data"; @@ -160,6 +269,120 @@ }; }; + sdc2_data_ds_400KHz: sdc2_data_ds_400KHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_ds_50MHz: sdc2_data_ds_50MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_ds_100MHz: sdc2_data_ds_100MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_ds_200MHz: sdc2_data_ds_200MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + pcie0 { + pcie0_clkreq_default: pcie0_clkreq_default { + mux { + pins = "gpio36"; + function = "pci_e0"; + }; + + config { + pins = "gpio36"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_perst_default: pcie0_perst_default { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie0_wake_default: pcie0_wake_default { + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + pcie1 { + pcie1_clkreq_default: pcie1_clkreq_default { + mux { + pins = "gpio103"; + function = "pci_e1"; + }; + + config { + pins = "gpio103"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie1_perst_default: pcie1_perst_default { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie1_wake_default: pcie1_wake_default { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + cdc_reset_ctrl { cdc_reset_sleep: cdc_reset_sleep { mux { @@ -244,6 +467,63 @@ }; }; + /* USB C analog configuration */ + wcd_usbc_analog_en1 { + wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle { + mux { + pins = "gpio49"; + function = "gpio"; + }; + config { + pins = "gpio49"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active { + mux { + pins = "gpio49"; + function = "gpio"; + }; + config { + pins = "gpio49"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + wcd_usbc_analog_en2 { + wcd_usbc_analog_en2_idle: wcd_usbc_ana_en2_idle { + mux { + pins = "gpio51"; + function = "gpio"; + }; + config { + pins = "gpio51"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en2_active: wcd_usbc_ana_en2_active { + mux { + pins = "gpio51"; + function = "gpio"; + }; + config { + pins = "gpio51"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + pri_aux_pcm_clk { pri_aux_pcm_clk_sleep: pri_aux_pcm_clk_sleep { mux { @@ -417,6 +697,175 @@ }; }; + sde_dp_aux_active: sde_dp_aux_active { + mux { + pins = "gpio43", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio43", "gpio51"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; + }; + + sde_dp_aux_suspend: sde_dp_aux_suspend { + mux { + pins = "gpio43", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio43", "gpio51"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + bias-disable; + drive-strength = <16>; + }; + }; + + sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_suspend { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + /* add pingrp for touchscreen */ + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend1: ts_int_suspend1 { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend1: ts_reset_suspend1 { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio122", "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio122", "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + ts_mux { + ts_active: ts_active { + mux { + pins = "gpio99", "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio99", "gpio122"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + sec_aux_pcm { sec_aux_pcm_sleep: sec_aux_pcm_sleep { mux { @@ -1128,109 +1577,193 @@ }; config { - pins = "gpio60"; + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio62"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio62"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio62"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; drive-strength = <2>; /* 2 mA */ bias-pull-down; /* PULL DOWN */ input-enable; }; }; - quat_mi2s_sd0_active: quat_mi2s_sd0_active { + quat_mi2s_sd3_active: quat_mi2s_sd3_active { mux { - pins = "gpio60"; + pins = "gpio63"; function = "qua_mi2s"; }; config { - pins = "gpio60"; + pins = "gpio63"; drive-strength = <8>; /* 8 mA */ bias-disable; /* NO PULL */ }; }; }; - quat_mi2s_sd1 { - quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + quat_tdm { + quat_tdm_sleep: quat_tdm_sleep { mux { - pins = "gpio61"; - function = "gpio"; + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; }; config { - pins = "gpio61"; + pins = "gpio58", "gpio59"; drive-strength = <2>; /* 2 mA */ bias-pull-down; /* PULL DOWN */ - input-enable; }; }; - quat_mi2s_sd1_active: quat_mi2s_sd1_active { + quat_tdm_active: quat_tdm_active { mux { - pins = "gpio61"; + pins = "gpio58", "gpio59"; function = "qua_mi2s"; }; config { - pins = "gpio61"; + pins = "gpio58", "gpio59"; drive-strength = <8>; /* 8 mA */ bias-disable; /* NO PULL */ }; }; }; - quat_mi2s_sd2 { - quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + quat_tdm_dout { + quat_tdm_dout_sleep: quat_tdm_dout_sleep { mux { - pins = "gpio62"; - function = "gpio"; + pins = "gpio61"; + function = "qua_mi2s"; }; config { - pins = "gpio62"; + pins = "gpio61"; drive-strength = <2>; /* 2 mA */ bias-pull-down; /* PULL DOWN */ - input-enable; }; }; - quat_mi2s_sd2_active: quat_mi2s_sd2_active { + quat_tdm_dout_active: quat_tdm_dout_active { mux { - pins = "gpio62"; + pins = "gpio61"; function = "qua_mi2s"; }; config { - pins = "gpio62"; - drive-strength = <8>; /* 8 mA */ + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ bias-disable; /* NO PULL */ }; }; }; - quat_mi2s_sd3 { - quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + quat_tdm_din { + quat_tdm_din_sleep: quat_tdm_din_sleep { mux { - pins = "gpio63"; - function = "gpio"; + pins = "gpio60"; + function = "qua_mi2s"; }; config { - pins = "gpio63"; + pins = "gpio60"; drive-strength = <2>; /* 2 mA */ bias-pull-down; /* PULL DOWN */ - input-enable; }; }; - quat_mi2s_sd3_active: quat_mi2s_sd3_active { + quat_tdm_din_active: quat_tdm_din_active { mux { - pins = "gpio63"; + pins = "gpio60"; function = "qua_mi2s"; }; config { - pins = "gpio63"; - drive-strength = <8>; /* 8 mA */ + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ bias-disable; /* NO PULL */ }; }; @@ -1449,6 +1982,68 @@ }; }; + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 63 NFC Read Interrupt */ + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 63 NFC Read Interrupt */ + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 12: NFC ENABLE 116:ESE Enable */ + pins = "gpio12", "gpio62", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio62", "gpio116"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 12: NFC ENABLE 116:ESE Enable */ + pins = "gpio12", "gpio62", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio62", "gpio116"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + qupv3_se3_spi_pins: qupv3_se3_spi_pins { qupv3_se3_spi_active: qupv3_se3_spi_active { mux { @@ -2441,8 +3036,9 @@ config { pins = "gpio80","gpio79"; - bias-disable; /* No PULL */ + bias-pull-down; /* PULL DOWN */ drive-strength = <2>; /* 2 MA */ + output-low; }; }; @@ -2474,15 +3070,44 @@ }; }; + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { /* RESET AVDD_LDO*/ mux { - pins = "gpio28", "gpio8"; + pins = "gpio28"; function = "gpio"; }; config { - pins = "gpio28", "gpio8"; + pins = "gpio28"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -2497,11 +3122,42 @@ config { pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_iris_active: cam_sensor_iris_active { + /* RESET AVDD_LDO*/ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_iris_suspend: cam_sensor_iris_suspend { + /* RESET */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ + output-low; }; }; + cam_sensor_mclk2_active: cam_sensor_mclk2_active { /* MCLK1 */ mux { @@ -2535,12 +3191,12 @@ cam_sensor_rear2_active: cam_sensor_rear2_active { /* RESET, STANDBY */ mux { - pins = "gpio9","gpio8"; + pins = "gpio9"; function = "gpio"; }; config { - pins = "gpio9","gpio8"; + pins = "gpio9"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ }; @@ -2549,13 +3205,201 @@ cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { /* RESET, STANDBY */ mux { - pins = "gpio9","gpio8"; + pins = "gpio9"; + function = "gpio"; + }; + config { + pins = "gpio9"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear_vana: cam_sensor_rear_vana { + /* AVDD LDO */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_res_mgr_active: cam_res_mgr_active { + /* AVDD_LDO*/ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_res_mgr_suspend: cam_res_mgr_suspend { + /* AVDD_LDO */ + mux { + pins = "gpio8"; function = "gpio"; }; + config { - pins = "gpio9","gpio8"; + pins = "gpio8"; bias-disable; /* No PULL */ drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + + trigout_a: trigout_a { + mux { + pins = "gpio90"; + function = "qdss_cti"; + }; + config { + pins = "gpio90"; + drive-strength = <2>; + bias-disable; + }; + }; + + tsif0_signals_active: tsif0_signals_active { + tsif1_clk { + pins = "gpio89"; /* TSIF0 CLK */ + function = "tsif1_clk"; + }; + tsif1_en { + pins = "gpio90"; /* TSIF0 Enable */ + function = "tsif1_en"; + }; + tsif1_data { + pins = "gpio91"; /* TSIF0 DATA */ + function = "tsif1_data"; + }; + signals_cfg { + pins = "gpio89", "gpio90", "gpio91"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif0_sync_active: tsif0_sync_active { + tsif1_sync { + pins = "gpio12"; /* TSIF0 SYNC */ + function = "tsif1_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + tsif1_signals_active: tsif1_signals_active { + tsif2_clk { + pins = "gpio93"; /* TSIF1 CLK */ + function = "tsif2_clk"; + }; + tsif2_en { + pins = "gpio94"; /* TSIF1 Enable */ + function = "tsif2_en"; + }; + tsif2_data { + pins = "gpio95"; /* TSIF1 DATA */ + function = "tsif2_data"; + }; + signals_cfg { + pins = "gpio93", "gpio94", "gpio95"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif1_sync_active: tsif1_sync_active { + tsif2_sync { + pins = "gpio96"; /* TSIF1 SYNC */ + function = "tsif2_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + ap2mdm { + ap2mdm_active: ap2mdm_active { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio21", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio23"; + drive-strength = <16>; + bias-disable; + }; + }; + ap2mdm_sleep: ap2mdm_sleep { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio21", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio23"; + drive-strength = <8>; + bias-disable; + }; + + }; + }; + + mdm2ap { + mdm2ap_active: mdm2ap_active { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio22", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio20"; + drive-strength = <8>; + bias-disable; + }; + }; + mdm2ap_sleep: mdm2ap_sleep { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio22", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio20"; + drive-strength = <8>; + bias-disable; + }; }; }; }; @@ -2619,35 +3463,13 @@ output-low; }; }; -}; - -&pmi8998_gpios { - usb2_vbus_boost { - usb2_vbus_boost_default: usb2_vbus_boost_default { - pins = "gpio2"; - function = "normal"; - output-low; - power-source = <0>; - }; - }; - - usb2_vbus_det { - usb2_vbus_det_default: usb2_vbus_det_default { - pins = "gpio8"; - function = "normal"; - input-enable; - bias-pull-down; - power-source = <1>; /* VPH input supply */ - }; - }; - usb2_id_det { - usb2_id_det_default: usb2_id_det_default { - pins = "gpio9"; + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio21"; function = "normal"; input-enable; - bias-pull-up; - power-source = <0>; + power-source = <1>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi index 70e749b9931d9fb0b331adf971bbd893a3948166..ee10cfcd604175d5657e55abdd55872e157dc5c7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi @@ -9,22 +9,18 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#include &soc { qcom,lpm-levels { compatible = "qcom,lpm-levels"; - qcom,use-psci; #address-cells = <1>; #size-cells = <0>; + qcom,pm-cluster@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; label = "L3"; - qcom,spm-device-names = "L3"; - qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5 &CPU6 - &CPU7>; qcom,psci-mode-shift = <4>; qcom,psci-mode-mask = <0xfff>; @@ -38,86 +34,84 @@ qcom,time-overhead = <99>; }; - qcom,pm-cluster-level@1 { /* D2 */ + qcom,pm-cluster-level@1 { /* LLCC off, AOSS sleep */ reg = <1>; - label = "l3-dyn-ret"; - qcom,psci-mode = <0x2>; - qcom,latency-us = <659>; - qcom,ss-power = <434>; - qcom,energy-overhead = <465725>; - qcom,time-overhead = <976>; - qcom,min-child-idx = <1>; - }; - - qcom,pm-cluster-level@2 { /* D4, D3 is not supported */ - reg = <2>; - label = "l3-pc"; - qcom,psci-mode = <0x4>; - qcom,latency-us = <4562>; - qcom,ss-power = <408>; - qcom,energy-overhead = <2421840>; - qcom,time-overhead = <5376>; - qcom,min-child-idx = <2>; - qcom,is-reset; - }; - - qcom,pm-cluster-level@3 { /* Cx off */ - reg = <3>; - label = "cx-off"; - qcom,psci-mode = <0x224>; - qcom,latency-us = <5562>; - qcom,ss-power = <308>; - qcom,energy-overhead = <2521840>; - qcom,time-overhead = <6376>; - qcom,min-child-idx = <3>; - qcom,is-reset; - qcom,notify-rpm; - }; - - qcom,pm-cluster-level@4 { /* LLCC off, AOSS sleep */ - reg = <4>; label = "llcc-off"; qcom,psci-mode = <0xC24>; qcom,latency-us = <6562>; qcom,ss-power = <108>; - qcom,energy-overhead = <2621840>; - qcom,time-overhead = <7376>; - qcom,min-child-idx = <3>; + qcom,energy-overhead = <4000000>; + qcom,time-overhead = <5000>; + qcom,min-child-idx = <2>; qcom,is-reset; qcom,notify-rpm; }; - qcom,pm-cpu { + qcom,pm-cpu@0 { #address-cells = <1>; #size-cells = <0>; qcom,psci-mode-shift = <0>; qcom,psci-mode-mask = <0xf>; + qcom,use-prediction; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; qcom,pm-cpu-level@0 { /* C1 */ reg = <0>; - qcom,spm-cpu-mode = "wfi"; + label = "wfi"; qcom,psci-cpu-mode = <0x1>; qcom,latency-us = <43>; - qcom,ss-power = <454>; - qcom,energy-overhead = <38639>; - qcom,time-overhead = <83>; + qcom,ss-power = <150>; + qcom,energy-overhead = <10000>; + qcom,time-overhead = <100>; }; - qcom,pm-cpu-level@1 { /* C2D */ + qcom,pm-cpu-level@1 { /* C3 */ reg = <1>; - qcom,psci-cpu-mode = <0x2>; - qcom,spm-cpu-mode = "ret"; - qcom,latency-us = <86>; - qcom,ss-power = <449>; - qcom,energy-overhead = <78456>; - qcom,time-overhead = <167>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <461>; + qcom,ss-power = <100>; + qcom,energy-overhead = <400000>; + qcom,time-overhead = <500>; + qcom,is-reset; + qcom,use-broadcast-timer; }; - qcom,pm-cpu-level@2 { /* C3 */ + qcom,pm-cpu-level@2 { /* C4 */ reg = <2>; - qcom,spm-cpu-mode = "pc"; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <531>; + qcom,ss-power = <73>; + qcom,energy-overhead = <500000>; + qcom,time-overhead = <600>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + + qcom,pm-cpu@1 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <43>; + qcom,ss-power = <454>; + qcom,energy-overhead = <38639>; + qcom,time-overhead = <83>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; qcom,psci-cpu-mode = <0x3>; - qcom,latency-us = <612>; + qcom,latency-us = <621>; qcom,ss-power = <436>; qcom,energy-overhead = <418225>; qcom,time-overhead = <885>; @@ -125,11 +119,11 @@ qcom,use-broadcast-timer; }; - qcom,pm-cpu-level@3 { /* C4 */ - reg = <3>; - qcom,spm-cpu-mode = "rail-pc"; + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; qcom,psci-cpu-mode = <0x4>; - qcom,latency-us = <700>; + qcom,latency-us = <1061>; qcom,ss-power = <400>; qcom,energy-overhead = <428225>; qcom,time-overhead = <1000>; @@ -145,4 +139,8 @@ reg = <0xC300000 0x1000>, <0xC3F0004 0x4>; reg-names = "phys_addr_base", "offset_addr"; }; + + qcom,rpmh-master-stats { + compatible = "qcom,rpmh-master-stats"; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..48040a3ea6d6a9ee0a7b7d138e6c736d7d790adb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi @@ -0,0 +1,47 @@ +/* Copyright (c) 2017, 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 + +#include "pmi8998.dtsi" + +&vendor { + ext_5v_boost: ext_5v_boost { + status = "disabled"; + compatible = "regulator-fixed"; + regulator-name = "ext_5v_boost"; + gpio = <&pmi8998_gpios 10 GPIO_ACTIVE_HIGH>; + enable-active-high; + + regulator-enable-ramp-delay = <1600>; + pinctrl-names = "default"; + pinctrl-0 = <&usb2_ext_5v_boost_default>; + }; +}; + +&pmi8998_charger { + smb2_vconn: qcom,smb2-vconn { + regulator-name = "smb2-vconn"; + }; + smb2_vbus: qcom,smb2-vbus { + regulator-name = "smb2-vbus"; + }; +}; + +&pmi8998_qnovo { + pinctrl-names = "default"; + pinctrl-0 = <&qnovo_fet_ctrl_default>; +}; + +&usb0 { + extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..361fa2fa9bec14888552d7461c04eb6ea4a5bc18 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, 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 "sdm845-audio-overlay.dtsi" + +&soc { + sound-tavil { + qcom,model = "sdm845-tavil-qrd-snd-card"; + + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; + + qcom,msm-mbhc-usbc-audio-supported = <1>; + + qcom,usbc-analog-en2-gpio = <&tlmm 51 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en2_active>; + pinctrl-1 = <&wcd_usbc_analog_en2_idle>; + }; +}; + +&us_euro_sw_wcd_active { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + /delete-property/ output-high; + bias-high-impedance; + }; +}; + +&us_euro_sw_wcd_sleep { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + /delete-property/ output-low; + bias-high-impedance; + }; +}; + +&wcd934x_cdc { + swr_master { + wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c8136ded91637bef535df57a506b5299a648fa81 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd.dts index 228b924fbf8cf6889e93a1736507163e8edfbb70..6cb7815781e8b46fa6a5c6302ec58699a3de8ceb 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-qrd.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi index 1d5bf3a857d7db1c2a8b2e3e9f4ffd782365a6d3..3ee0138dde12fd01f509160907b607fcdf37eede 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi @@ -10,22 +10,399 @@ * GNU General Public License for more details. */ -/{ +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" +#include "smb1355.dtsi" +#include + +&vendor { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pm8998_s3>; + qca,bt-vdd-xtal-supply = <&pm8998_s5>; + qca,bt-vdd-core-supply = <&pm8998_l7>; + qca,bt-vdd-pa-supply = <&pm8998_l17>; + qca,bt-vdd-ldo-supply = <&pm8998_l25>; + + qca,bt-vdd-io-voltage-level = <1352000 1352000>; + qca,bt-vdd-xtal-voltage-level = <2040000 2040000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + 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 */ + }; + qrd_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; - #include "fg-gen3-batterydata-itech-3000mah.dtsi" - #include "fg-gen3-batterydata-ascent-3450mah.dtsi" + #include "fg-gen3-batterydata-gt3746a6-2900mah.dtsi" + }; +}; + +&qupv3_se9_2uart { + status = "ok"; +}; + +&qupv3_se8_spi { + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 63 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 62 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; }; }; +&qupv3_se10_i2c { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + &pmi8998_fg { qcom,battery-data = <&qrd_batterydata>; + qcom,fg-bmd-en-delay-ms = <300>; }; -&soc { - sound-tavil { - qcom,wsa-max-devs = <1>; - qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; - qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; +&smb1355_charger_0 { + status = "ok"; +}; + +&smb1355_charger_1 { + status = "ok"; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&pm8998_l1>; /* 0.88v */ + vdda-pll-supply = <&pm8998_l26>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8998_l20>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8998_s4>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm8998_l2>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8998_l21>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8998_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&labibb { + status = "ok"; + qcom,qpnp-labibb-mode = "lcd"; +}; + +&pmi8998_wled { + status = "okay"; + qcom,led-strings-list = [01 02]; +}; + +&pmi8998_haptics { + qcom,vmax-mv = <1800>; + qcom,wave-play-rate-us = <4347>; + qcom,lra-auto-mode; + status = "okay"; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + qcom,dsi-display-active; +}; + +&wil6210 { + status = "ok"; +}; + +&ext_5v_boost { + status = "ok"; +}; + +&pm8998_vadc { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@85 { + label = "vcoin"; + reg = <0x85>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8998_adc_tm { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,btm-channel-number = <0x60>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x80>; + qcom,thermal-node; + }; +}; + +&thermal_zones { + xo-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x4c>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + msm-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x4d>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm1-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x4f>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x51>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi index dd0d08e00630b7a278b3c79e2283997caa46d210..5fce5ff93806e4c5a23c16f260ce9d5c48221be2 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,13 +14,25 @@ &soc { /* QUPv3 South instances */ + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x003 0x0>; + }; + }; /* * HS UART instances. HS UART usecases can be supported on these * instances only. */ qupv3_se6_4uart: qcom,qup_uart@0x898000 { - compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart"; + compatible = "qcom,msm-geni-serial-hs"; reg = <0x898000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -30,13 +42,15 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se6_4uart_active>; pinctrl-1 = <&qupv3_se6_4uart_sleep>; - interrupts = ; + interrupts-extended = <&pdc GIC_SPI 607 0>, + <&tlmm 48 0>; status = "disabled"; - qcom,bus-mas = ; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; }; qupv3_se7_4uart: qcom,qup_uart@0x89c000 { - compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart"; + compatible = "qcom,msm-geni-serial-hs"; reg = <0x89c000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -46,9 +60,11 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se7_4uart_active>; pinctrl-1 = <&qupv3_se7_4uart_sleep>; - interrupts = ; + interrupts-extended = <&pdc GIC_SPI 608 0>, + <&tlmm 96 0>; status = "disabled"; - qcom,bus-mas = ; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; }; /* I2C */ @@ -62,9 +78,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se0_i2c_active>; pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -78,9 +98,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se1_i2c_active>; pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -94,9 +118,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se2_i2c_active>; pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -110,9 +138,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 3 3 64 0>, + <&gpi_dma0 1 3 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se3_i2c_active>; pinctrl-1 = <&qupv3_se3_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -126,9 +158,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 4 3 64 0>, + <&gpi_dma0 1 4 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se4_i2c_active>; pinctrl-1 = <&qupv3_se4_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -142,9 +178,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 5 3 64 0>, + <&gpi_dma0 1 5 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se5_i2c_active>; pinctrl-1 = <&qupv3_se5_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -158,9 +198,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 6 3 64 0>, + <&gpi_dma0 1 6 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se6_i2c_active>; pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -174,9 +218,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 7 3 64 0>, + <&gpi_dma0 1 7 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se7_i2c_active>; pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; @@ -196,6 +244,10 @@ pinctrl-1 = <&qupv3_se0_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -214,6 +266,10 @@ pinctrl-1 = <&qupv3_se1_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -232,6 +288,10 @@ pinctrl-1 = <&qupv3_se2_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -250,6 +310,10 @@ pinctrl-1 = <&qupv3_se3_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 3 1 64 0>, + <&gpi_dma0 1 3 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -268,6 +332,10 @@ pinctrl-1 = <&qupv3_se4_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 4 1 64 0>, + <&gpi_dma0 1 4 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -286,6 +354,10 @@ pinctrl-1 = <&qupv3_se5_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -304,6 +376,10 @@ pinctrl-1 = <&qupv3_se6_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 6 1 64 0>, + <&gpi_dma0 1 6 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -322,15 +398,32 @@ pinctrl-1 = <&qupv3_se7_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 7 1 64 0>, + <&gpi_dma0 1 7 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; /* QUPv3 North Instances */ + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x6c3 0x0>; + }; + }; + /* 2-wire UART */ /* Debug UART Instance for CDP/MTP platform */ qupv3_se9_2uart: qcom,qup_uart@0xa84000 { - compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart"; + compatible = "qcom,msm-geni-console"; reg = <0xa84000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -340,14 +433,14 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se9_2uart_active>; pinctrl-1 = <&qupv3_se9_2uart_sleep>; - qcom,bus-mas = ; interrupts = ; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; /* Debug UART Instance for RUMI platform */ qupv3_se10_2uart: qcom,qup_uart@0xa88000 { - compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart"; + compatible = "qcom,msm-geni-console"; reg = <0xa88000 0x4000>; reg-names = "se_phys"; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -358,7 +451,7 @@ pinctrl-0 = <&qupv3_se10_2uart_active>; pinctrl-1 = <&qupv3_se10_2uart_sleep>; interrupts = ; - qcom,bus-mas = ; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -373,9 +466,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se8_i2c_active>; pinctrl-1 = <&qupv3_se8_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -389,9 +486,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se9_i2c_active>; pinctrl-1 = <&qupv3_se9_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -405,9 +506,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se10_i2c_active>; pinctrl-1 = <&qupv3_se10_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -421,9 +526,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 3 3 64 0>, + <&gpi_dma1 1 3 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se11_i2c_active>; pinctrl-1 = <&qupv3_se11_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -437,9 +546,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 4 3 64 0>, + <&gpi_dma1 1 4 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se12_i2c_active>; pinctrl-1 = <&qupv3_se12_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -453,9 +566,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 5 3 64 0>, + <&gpi_dma1 1 5 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se13_i2c_active>; pinctrl-1 = <&qupv3_se13_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -469,9 +586,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 6 3 64 0>, + <&gpi_dma1 1 6 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se14_i2c_active>; pinctrl-1 = <&qupv3_se14_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -485,9 +606,13 @@ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 7 3 64 0>, + <&gpi_dma1 1 7 3 64 0>; + dma-names = "tx", "rx"; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se15_i2c_active>; pinctrl-1 = <&qupv3_se15_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -504,9 +629,13 @@ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se8_spi_active>; - pinctrl-1 = <&qupv3_se8_spi_sleep>; + pinctrl-1 = <&qupv3_se8_spi_active>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -525,6 +654,10 @@ pinctrl-1 = <&qupv3_se9_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 1 1 64 0>, + <&gpi_dma1 1 1 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -543,6 +676,10 @@ pinctrl-1 = <&qupv3_se10_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 2 1 64 0>, + <&gpi_dma1 1 2 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -561,6 +698,10 @@ pinctrl-1 = <&qupv3_se11_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 3 1 64 0>, + <&gpi_dma1 1 3 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -579,6 +720,10 @@ pinctrl-1 = <&qupv3_se12_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 4 1 64 0>, + <&gpi_dma1 1 4 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -597,6 +742,10 @@ pinctrl-1 = <&qupv3_se13_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 5 1 64 0>, + <&gpi_dma1 1 5 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -615,6 +764,10 @@ pinctrl-1 = <&qupv3_se14_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 6 1 64 0>, + <&gpi_dma1 1 6 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -633,6 +786,10 @@ pinctrl-1 = <&qupv3_se15_spi_sleep>; interrupts = ; spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 7 1 64 0>, + <&gpi_dma1 1 7 1 64 0>; + dma-names = "tx", "rx"; status = "disabled"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..77a89f078d3159310b57f4e1d3550a8a52d19f6d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-qvr-audio-overlay.dtsi @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, 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 "sdm845-audio-overlay.dtsi" + +&snd_934x { + qcom,model = "sdm845-qvr-tavil-snd-card"; + + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC1", "Handset Mic", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + /delete-property/ qcom,hph-en0-gpio; + /delete-property/ qcom,hph-en1-gpio; + /delete-property/ qcom,usbc-analog-en1-gpio; + /delete-property/ qcom,usbc-analog-en2-gpio; + /delete-property/ pinctrl-names; + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-1; + + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a5c6ab55c3f5474f33b8e837e50ed3aaad192b51 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi @@ -0,0 +1,246 @@ +/* Copyright (c) 2017-2018, 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 +#include +#include +#include +#include + +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" +#include "smb1355.dtsi" + +&vendor { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pm8998_s3>; + qca,bt-vdd-xtal-supply = <&pm8998_s5>; + qca,bt-vdd-core-supply = <&pm8998_l7>; + qca,bt-vdd-pa-supply = <&pm8998_l17>; + qca,bt-vdd-ldo-supply = <&pm8998_l25>; + + qca,bt-vdd-io-voltage-level = <1352000 1352000>; + qca,bt-vdd-xtal-voltage-level = <2040000 2040000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + 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 */ + }; + + qvr_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen3-batterydata-mlp446579-3800mah.dtsi" + }; +}; + +&pmi8998_pdphy { + vbus-supply = <&smb2_vbus>; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&pmi8998_fg { + qcom,battery-data = <&qvr_batterydata>; + qcom,fg-bmd-en-delay-ms = <300>; +}; + +&pmi8998_charger { + qcom,battery-data = <&qvr_batterydata>; + qcom,sw-jeita-enable; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 63 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 62 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; +}; + +&qupv3_se10_i2c { + status = "ok"; +}; + +&smb1355_charger_0 { + status = "ok"; +}; + +&smb1355_charger_1 { + status = "ok"; +}; + +&soc { + qcom,qbt1000 { + status = "disabled"; + }; + + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default + &key_home_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + home { + label = "home"; + gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <102>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x00 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x27 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; + +&pmi8998_haptics { + qcom,vmax-mv = <1800>; + qcom,wave-play-rate-us = <4255>; + qcom,lra-auto-mode; + status = "okay"; +}; + +&qupv3_se9_2uart { + status = "ok"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&pm8998_l1>; /* 0.88v */ + vdda-pll-supply = <&pm8998_l26>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8998_l20>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8998_s4>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm8998_l2>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8998_l21>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8998_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 126 GPIO_ACTIVE_HIGH>; + + status = "ok"; +}; + +&wil6210 { + status = "ok"; +}; + +&qupv3_se5_i2c { + status = "ok"; + synaptics_dsx@20 { + compatible = "synaptics,dsx-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <122 0x2008>; + vdd-supply = <&pm8998_l14>; + avdd-supply = <&pm8998_l28>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,ub-i2c-addr = <0x2c>; + synaptics,irq-gpio = <&tlmm 122 0x2008>; + synaptics,reset-gpio = <&tlmm 99 0x0>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi index 5c39e8665f58a44e825c328387b2f6806d7837ef..ec8665b603f8795121d035d981b8ad1d3b4c0005 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include #include /* Stub regulators */ @@ -28,355 +29,7 @@ }; }; -&spmi_bus { - qcom,pm8998@1 { - /* PM8998 S12 + S11 + S10 = VDD_APC1 supply */ - pm8998_s12: regulator@3500 { - compatible = "qcom,qpnp-regulator"; - reg = <0x3500 0x100>; - regulator-name = "pm8998_s12"; - regulator-min-microvolt = <568000>; - regulator-max-microvolt = <1056000>; - qcom,enable-time = <500>; - regulator-always-on; - }; - - /* PM8998 S13 = VDD_APC0 supply */ - pm8998_s13: regulator@3800 { - compatible = "qcom,qpnp-regulator"; - reg = <0x3800 0x100>; - regulator-name = "pm8998_s13"; - regulator-min-microvolt = <568000>; - regulator-max-microvolt = <928000>; - qcom,enable-time = <500>; - regulator-always-on; - }; - }; -}; - &soc { - /* CPR controller regulators */ - apc0_cpr: cprh-ctrl@17dc0000 { - compatible = "qcom,cprh-sdm845-v1-kbss-regulator"; - reg = <0x17dc0000 0x4000>, - <0x00784000 0x1000>, - <0x17840000 0x1000>; - reg-names = "cpr_ctrl", "fuse_base", "saw"; - clocks = <&clock_gcc GCC_CPUSS_RBCPR_CLK>; - clock-names = "core_clk"; - qcom,cpr-ctrl-name = "apc0"; - qcom,cpr-controller-id = <0>; - - qcom,cpr-sensor-time = <1000>; - qcom,cpr-loop-time = <5000000>; - qcom,cpr-idle-cycles = <15>; - qcom,cpr-up-down-delay-time = <3000>; - qcom,cpr-step-quot-init-min = <11>; - qcom,cpr-step-quot-init-max = <12>; - qcom,cpr-count-mode = <0>; /* All at once */ - qcom,cpr-count-repeat = <20>; - qcom,cpr-down-error-step-limit = <1>; - qcom,cpr-up-error-step-limit = <1>; - qcom,cpr-corner-switch-delay-time = <1042>; - qcom,cpr-voltage-settling-time = <1760>; - - qcom,voltage-step = <4000>; - qcom,voltage-base = <352000>; - qcom,cpr-saw-use-unit-mV; - - qcom,saw-avs-ctrl = <0x101C031>; - qcom,saw-avs-limit = <0x3A003A0>; - - qcom,cpr-enable; - qcom,cpr-hw-closed-loop; - - qcom,cpr-panic-reg-addr-list = - <0x17dc3a84 0x17dc3a88 0x17840c18>; - qcom,cpr-panic-reg-name-list = - "APSS_SILVER_CPRH_STATUS_0", - "APSS_SILVER_CPRH_STATUS_1", - "SILVER_SAW4_PMIC_STS"; - - qcom,cpr-aging-ref-voltage = <928000>; - vdd-supply = <&pm8998_s13>; - - thread@1 { - qcom,cpr-thread-id = <1>; - qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <0>; - qcom,cpr-up-threshold = <2>; - qcom,cpr-down-threshold = <2>; - - apc0_pwrcl_vreg: regulator { - regulator-name = "apc0_pwrcl_corner"; - regulator-min-microvolt = <1>; - regulator-max-microvolt = <17>; - - qcom,cpr-fuse-corners = <3>; - qcom,cpr-fuse-combos = <8>; - qcom,cpr-speed-bins = <1>; - qcom,cpr-speed-bin-corners = <17>; - qcom,cpr-corners = <17>; - - qcom,cpr-corner-fmax-map = <6 12 17>; - - qcom,cpr-voltage-ceiling = - <872000 872000 872000 872000 872000 - 872000 872000 872000 872000 872000 - 872000 872000 872000 872000 872000 - 872000 928000>; - - qcom,cpr-voltage-floor = - <568000 568000 568000 568000 568000 - 568000 568000 568000 568000 584000 - 584000 584000 632000 632000 632000 - 632000 672000>; - - qcom,cpr-floor-to-ceiling-max-range = - <32000 32000 32000 32000 32000 - 32000 32000 32000 32000 32000 - 32000 32000 32000 32000 32000 - 32000 32000>; - - qcom,corner-frequencies = - <300000000 422400000 499200000 - 576000000 652800000 748800000 - 825600000 902400000 979200000 - 1056000000 1132800000 1209600000 - 1286400000 1363200000 1440000000 - 1516800000 1593600000>; - - qcom,cpr-ro-scaling-factor = - <2594 2795 2576 2761 2469 2673 2198 - 2553 3188 3255 3191 2962 3055 2984 - 2043 2947>, - <2594 2795 2576 2761 2469 2673 2198 - 2553 3188 3255 3191 2962 3055 2984 - 2043 2947>, - <2259 2389 2387 2531 2294 2464 2218 - 2476 2525 2855 2817 2836 2740 2490 - 1950 2632>; - - qcom,cpr-open-loop-voltage-fuse-adjustment = - <100000 100000 100000>; - - qcom,cpr-closed-loop-voltage-fuse-adjustment = - <100000 100000 100000>; - - qcom,allow-voltage-interpolation; - qcom,allow-quotient-interpolation; - qcom,cpr-scaled-open-loop-voltage-as-ceiling; - - qcom,cpr-aging-max-voltage-adjustment = <15000>; - qcom,cpr-aging-ref-corner = <17>; - qcom,cpr-aging-ro-scaling-factor = <1620>; - qcom,allow-aging-voltage-adjustment = - <0 1 1 1 1 1 1 1>; - qcom,allow-aging-open-loop-voltage-adjustment = - <1>; - }; - }; - - thread@0 { - qcom,cpr-thread-id = <0>; - qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <0>; - qcom,cpr-up-threshold = <2>; - qcom,cpr-down-threshold = <2>; - - apc0_l3_vreg: regulator { - regulator-name = "apc0_l3_corner"; - regulator-min-microvolt = <1>; - regulator-max-microvolt = <9>; - - qcom,cpr-fuse-corners = <3>; - qcom,cpr-fuse-combos = <8>; - qcom,cpr-speed-bins = <1>; - qcom,cpr-speed-bin-corners = <9>; - qcom,cpr-corners = <9>; - - qcom,cpr-corner-fmax-map = <4 7 9>; - - qcom,cpr-voltage-ceiling = - <872000 872000 872000 872000 872000 - 872000 872000 872000 928000>; - - qcom,cpr-voltage-floor = - <568000 568000 568000 568000 568000 - 584000 584000 632000 672000>; - - qcom,cpr-floor-to-ceiling-max-range = - <32000 32000 32000 32000 32000 - 32000 32000 32000 32000>; - - qcom,corner-frequencies = - <300000000 422400000 499200000 - 576000000 652800000 729600000 - 806400000 883200000 960000000>; - - qcom,cpr-ro-scaling-factor = - <2857 3056 2828 2952 2699 2796 2447 - 2631 2630 2579 2244 3343 3287 3137 - 3164 2656>, - <2857 3056 2828 2952 2699 2796 2447 - 2631 2630 2579 2244 3343 3287 3137 - 3164 2656>, - <2439 2577 2552 2667 2461 2577 2394 - 2536 2132 2307 2191 2903 2838 2912 - 2501 2095>; - - qcom,cpr-open-loop-voltage-fuse-adjustment = - <100000 100000 100000>; - - qcom,cpr-closed-loop-voltage-fuse-adjustment = - <100000 100000 100000>; - - qcom,allow-voltage-interpolation; - qcom,allow-quotient-interpolation; - qcom,cpr-scaled-open-loop-voltage-as-ceiling; - - qcom,cpr-aging-max-voltage-adjustment = <15000>; - qcom,cpr-aging-ref-corner = <9>; - qcom,cpr-aging-ro-scaling-factor = <1620>; - qcom,allow-aging-voltage-adjustment = - <0 1 1 1 1 1 1 1>; - qcom,allow-aging-open-loop-voltage-adjustment = - <1>; - }; - }; - }; - - apc1_cpr: cprh-ctrl@17db0000 { - compatible = "qcom,cprh-sdm845-kbss-regulator"; - reg = <0x17db0000 0x4000>, - <0x00784000 0x1000>, - <0x17830000 0x1000>; - reg-names = "cpr_ctrl", "fuse_base", "saw"; - clocks = <&clock_gcc GCC_CPUSS_RBCPR_CLK>; - clock-names = "core_clk"; - qcom,cpr-ctrl-name = "apc1"; - qcom,cpr-controller-id = <1>; - - qcom,cpr-sensor-time = <1000>; - qcom,cpr-loop-time = <5000000>; - qcom,cpr-idle-cycles = <15>; - qcom,cpr-up-down-delay-time = <3000>; - qcom,cpr-step-quot-init-min = <9>; - qcom,cpr-step-quot-init-max = <14>; - qcom,cpr-count-mode = <0>; /* All at once */ - qcom,cpr-count-repeat = <20>; - qcom,cpr-down-error-step-limit = <1>; - qcom,cpr-up-error-step-limit = <1>; - qcom,cpr-corner-switch-delay-time = <1042>; - qcom,cpr-voltage-settling-time = <1760>; - - qcom,apm-threshold-voltage = <800000>; - qcom,apm-crossover-voltage = <880000>; - qcom,mem-acc-threshold-voltage = <852000>; - qcom,mem-acc-crossover-voltage = <852000>; - - qcom,voltage-step = <4000>; - qcom,voltage-base = <352000>; - qcom,cpr-saw-use-unit-mV; - - qcom,saw-avs-ctrl = <0x101C031>; - qcom,saw-avs-limit = <0x4200420>; - - qcom,cpr-enable; - qcom,cpr-hw-closed-loop; - - qcom,cpr-panic-reg-addr-list = - <0x17db3a84 0x17830c18>; - qcom,cpr-panic-reg-name-list = - "APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS"; - - qcom,cpr-aging-ref-voltage = <1056000>; - vdd-supply = <&pm8998_s12>; - - thread@0 { - qcom,cpr-thread-id = <0>; - qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <0>; - qcom,cpr-up-threshold = <2>; - qcom,cpr-down-threshold = <2>; - - apc1_perfcl_vreg: regulator { - regulator-name = "apc1_perfcl_corner"; - regulator-min-microvolt = <1>; - regulator-max-microvolt = <24>; - - qcom,cpr-fuse-corners = <3>; - qcom,cpr-fuse-combos = <8>; - qcom,cpr-speed-bins = <1>; - qcom,cpr-speed-bin-corners = <22>; - qcom,cpr-corners = <22>; - - qcom,cpr-corner-fmax-map = - <10 17 22>; - - qcom,cpr-voltage-ceiling = - <828000 828000 828000 828000 828000 - 828000 828000 828000 828000 828000 - 828000 828000 828000 828000 828000 - 828000 828000 884000 952000 952000 - 1056000 1056000>; - - qcom,cpr-voltage-floor = - <568000 568000 568000 568000 568000 - 568000 568000 568000 568000 568000 - 584000 584000 632000 632000 632000 - 632000 632000 672000 712000 712000 - 772000 772000>; - - qcom,cpr-floor-to-ceiling-max-range = - <32000 32000 32000 32000 32000 - 32000 32000 32000 32000 32000 - 32000 32000 32000 32000 32000 - 32000 32000 40000 40000 40000 - 40000 40000>; - - qcom,corner-frequencies = - <300000000 422400000 499200000 - 576000000 652800000 729600000 - 806400000 883200000 960000000 - 1036800000 1113600000 1190400000 - 1267200000 1344000000 1420800000 - 1497600000 1574400000 1651200000 - 1728000000 1804800000 1881600000 - 1958400000>; - - qcom,cpr-ro-scaling-factor = - <2857 3056 2828 2952 2699 2796 2447 - 2631 2630 2579 2244 3343 3287 3137 - 3164 2656>, - <2857 3056 2828 2952 2699 2796 2447 - 2631 2630 2579 2244 3343 3287 3137 - 3164 2656>, - <2086 2208 2273 2408 2203 2327 2213 - 2340 1755 2039 2049 2474 2437 2618 - 2003 1675>; - - qcom,cpr-open-loop-voltage-fuse-adjustment = - <100000 100000 100000>; - - qcom,cpr-closed-loop-voltage-fuse-adjustment = - <100000 100000 100000>; - - qcom,allow-voltage-interpolation; - qcom,allow-quotient-interpolation; - qcom,cpr-scaled-open-loop-voltage-as-ceiling; - - qcom,cpr-aging-max-voltage-adjustment = <15000>; - qcom,cpr-aging-ref-corner = <22>; - qcom,cpr-aging-ro-scaling-factor = <1700>; - qcom,allow-aging-voltage-adjustment = - <0 1 1 1 1 1 1 1>; - qcom,allow-aging-open-loop-voltage-adjustment = - <1>; - }; - }; - }; - /* RPMh regulators: */ /* PM8998 S1 = VDD_EBI supply */ @@ -390,6 +43,13 @@ regulator-min-microvolt = ; regulator-max-microvolt = ; }; + + ebi_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "ebi"; + #cooling-cells = <2>; + }; }; rpmh-regulator-smpa2 { @@ -449,6 +109,14 @@ regulator-min-microvolt = ; regulator-max-microvolt = ; }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pm8998_s6_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; }; rpmh-regulator-smpa7 { @@ -486,23 +154,53 @@ regulator-max-microvolt = ; qcom,min-dropout-voltage-level = <(-1)>; }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; }; rpmh-regulator-ldoa1 { compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8998_l1>; pm8998_l1: regulator-l1 { regulator-name = "pm8998_l1"; qcom,set = ; regulator-min-microvolt = <880000>; regulator-max-microvolt = <880000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <72000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + + pm8998_l1_ao: regulator-l1-ao { + regulator-name = "pm8998_l1_ao"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; qcom,init-voltage = <880000>; - qcom,init-mode = ; + qcom,init-mode = ; + }; + + regulator-l1-so { + regulator-name = "pm8998_l1_so"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + qcom,init-enable = <0>; }; }; @@ -510,9 +208,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 30000>; pm8998_l2: regulator-l2 { regulator-name = "pm8998_l2"; @@ -520,7 +219,7 @@ regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; qcom,init-voltage = <1200000>; - qcom,init-mode = ; + qcom,init-mode = ; regulator-always-on; }; }; @@ -529,9 +228,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l3: regulator-l3 { regulator-name = "pm8998_l3"; @@ -539,7 +239,7 @@ regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; qcom,init-voltage = <1000000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -560,9 +260,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l5: regulator-l5 { regulator-name = "pm8998_l5"; @@ -570,7 +271,7 @@ regulator-min-microvolt = <800000>; regulator-max-microvolt = <800000>; qcom,init-voltage = <800000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -578,9 +279,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l6: regulator-l6 { regulator-name = "pm8998_l6"; @@ -588,7 +290,7 @@ regulator-min-microvolt = <1856000>; regulator-max-microvolt = <1856000>; qcom,init-voltage = <1856000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -596,17 +298,18 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; - qcom,mode-threshold-currents = <0 1>; + ; + qcom,mode-threshold-currents = <0 10000>; pm8998_l7: regulator-l7 { regulator-name = "pm8998_l7"; qcom,set = ; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,init-voltage = <1800000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -614,9 +317,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l8: regulator-l8 { regulator-name = "pm8998_l8"; @@ -624,7 +328,7 @@ regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1248000>; qcom,init-voltage = <1200000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -632,9 +336,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l9: regulator-l9 { regulator-name = "pm8998_l9"; @@ -642,7 +347,7 @@ regulator-min-microvolt = <1704000>; regulator-max-microvolt = <2928000>; qcom,init-voltage = <1704000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -650,9 +355,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l10: regulator-l10 { regulator-name = "pm8998_l10"; @@ -660,7 +366,7 @@ regulator-min-microvolt = <1704000>; regulator-max-microvolt = <2928000>; qcom,init-voltage = <1704000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -668,9 +374,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l11: regulator-l11 { regulator-name = "pm8998_l11"; @@ -678,7 +385,7 @@ regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1048000>; qcom,init-voltage = <1000000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -686,9 +393,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l12: regulator-l12 { regulator-name = "pm8998_l12"; @@ -696,7 +404,7 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,init-voltage = <1800000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -704,9 +412,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; pm8998_l13: regulator-l13 { regulator-name = "pm8998_l13"; @@ -714,7 +423,7 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2960000>; qcom,init-voltage = <1800000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -722,17 +431,21 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; + proxy-supply = <&pm8998_l14>; pm8998_l14: regulator-l14 { regulator-name = "pm8998_l14"; qcom,set = ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <115000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1880000>; qcom,init-voltage = <1800000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -740,9 +453,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l15: regulator-l15 { regulator-name = "pm8998_l15"; @@ -750,7 +464,7 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,init-voltage = <1800000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -758,9 +472,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l16: regulator-l16 { regulator-name = "pm8998_l16"; @@ -768,7 +483,7 @@ regulator-min-microvolt = <2704000>; regulator-max-microvolt = <2704000>; qcom,init-voltage = <2704000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -776,17 +491,18 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; - qcom,mode-threshold-currents = <0 1>; + ; + qcom,mode-threshold-currents = <0 10000>; pm8998_l17: regulator-l17 { regulator-name = "pm8998_l17"; qcom,set = ; regulator-min-microvolt = <1304000>; regulator-max-microvolt = <1304000>; qcom,init-voltage = <1304000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -794,9 +510,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l18: regulator-l18 { regulator-name = "pm8998_l18"; @@ -804,7 +521,7 @@ regulator-min-microvolt = <2704000>; regulator-max-microvolt = <2960000>; qcom,init-voltage = <2704000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -812,9 +529,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa19"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l19: regulator-l19 { regulator-name = "pm8998_l19"; @@ -822,7 +540,7 @@ regulator-min-microvolt = <2856000>; regulator-max-microvolt = <3104000>; qcom,init-voltage = <2856000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -830,9 +548,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa20"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; pm8998_l20: regulator-l20 { regulator-name = "pm8998_l20"; @@ -840,7 +559,7 @@ regulator-min-microvolt = <2704000>; regulator-max-microvolt = <2960000>; qcom,init-voltage = <2704000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -848,9 +567,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa21"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; pm8998_l21: regulator-l21 { regulator-name = "pm8998_l21"; @@ -858,7 +578,7 @@ regulator-min-microvolt = <2704000>; regulator-max-microvolt = <2960000>; qcom,init-voltage = <2704000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -866,9 +586,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa22"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; pm8998_l22: regulator-l22 { regulator-name = "pm8998_l22"; @@ -876,7 +597,7 @@ regulator-min-microvolt = <2864000>; regulator-max-microvolt = <3312000>; qcom,init-voltage = <2864000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -884,17 +605,18 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa23"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; - qcom,mode-threshold-currents = <0 1>; + ; + qcom,mode-threshold-currents = <0 10000>; pm8998_l23: regulator-l23 { regulator-name = "pm8998_l23"; qcom,set = ; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3312000>; qcom,init-voltage = <3000000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -902,9 +624,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa24"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 10000>; pm8998_l24-parent-supply = <&pm8998_l12>; pm8998_l24: regulator-l24 { @@ -913,7 +636,7 @@ regulator-min-microvolt = <3088000>; regulator-max-microvolt = <3088000>; qcom,init-voltage = <3088000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -921,17 +644,18 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa25"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; - qcom,mode-threshold-currents = <0 1>; + ; + qcom,mode-threshold-currents = <0 10000>; pm8998_l25: regulator-l25 { regulator-name = "pm8998_l25"; qcom,set = ; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3312000>; qcom,init-voltage = <3000000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -939,17 +663,21 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa26"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8998_l26>; pm8998_l26: regulator-l26 { regulator-name = "pm8998_l26"; qcom,set = ; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <43600>; qcom,init-voltage = <1200000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -970,9 +698,10 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa28"; + qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = - ; + ; qcom,mode-threshold-currents = <0 1>; pm8998_l28: regulator-l28 { regulator-name = "pm8998_l28"; @@ -980,7 +709,7 @@ regulator-min-microvolt = <2856000>; regulator-max-microvolt = <3008000>; qcom,init-voltage = <2856000>; - qcom,init-mode = ; + qcom,init-mode = ; }; }; @@ -1012,12 +741,25 @@ compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; qcom,resource-name = "bobb1"; + qcom,regulator-type = "pmic4-bob"; + qcom,send-defaults; + pmi8998_bob: regulator-bob { regulator-name = "pmi8998_bob"; qcom,set = ; regulator-min-microvolt = <3312000>; regulator-max-microvolt = <3600000>; qcom,init-voltage = <3312000>; + qcom,init-mode = ; + }; + + pmi8998_bob_ao: regulator-bob-ao { + regulator-name = "pmi8998_bob_ao"; + qcom,set = ; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <3312000>; + qcom,init-mode = ; }; }; @@ -1029,8 +771,12 @@ pm8005_s1_level: regulator-s1-level { regulator-name = "pm8005_s1_level"; qcom,set = ; - regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; }; }; @@ -1059,14 +805,14 @@ qcom,init-voltage = <600000>; }; }; -}; - -&pmi8998_charger { - smb2_vbus: qcom,smb2-vbus { - regulator-name = "smb2-vbus"; - }; - smb2_vconn: qcom,smb2-vconn { - regulator-name = "smb2-vconn"; + refgen: refgen-regulator@ff1000 { + compatible = "qcom,refgen-regulator"; + reg = <0xff1000 0x60>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + status = "disabled"; + proxy-supply = <&refgen>; + qcom,proxy-consumer-enable; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi index 6991b1754ad9c9508671257c0ac2d2440a238f17..34de0a04da856b74ea107a5d99800f002c6b1763 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi @@ -11,6 +11,8 @@ */ #include +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" &ufsphy_mem { compatible = "qcom,ufs-phy-qrbtc-sdm845"; @@ -31,6 +33,7 @@ vdd-hba-supply = <&ufs_phy_gdsc>; vdd-hba-fixed-regulator; vcc-supply = <&pm8998_l20>; + vcc-voltage-level = <2950000 2960000>; vccq2-supply = <&pm8998_s4>; vcc-max-microamp = <600000>; vccq2-max-microamp = <600000>; @@ -129,45 +132,6 @@ }; }; -&apc0_cpr { - qcom,cpr-ignore-invalid-fuses; -}; - -&apc1_cpr { - qcom,cpr-ignore-invalid-fuses; -}; - -&ufsphy_card { - compatible = "qcom,ufs-phy-qrbtc-sdm845"; - - vdda-phy-supply = <&pm8998_l1>; /* 0.88v */ - vdda-pll-supply = <&pm8998_l26>; /* 1.2v */ - vdda-phy-max-microamp = <62900>; - vdda-pll-max-microamp = <18300>; - - status = "ok"; -}; - -&ufshc_card { - limit-tx-hs-gear = <1>; - limit-rx-hs-gear = <1>; - - vdd-hba-supply = <&ufs_card_gdsc>; - vdd-hba-fixed-regulator; - vcc-supply = <&pm8998_l21>; - vccq2-supply = <&pm8998_s4>; - vcc-max-microamp = <300000>; - vccq2-max-microamp = <300000>; - - qcom,vddp-ref-clk-supply = <&pm8998_l2>; - qcom,vddp-ref-clk-max-microamp = <100>; - - qcom,disable-lpm; - rpm-level = <0>; - spm-level = <0>; - status = "ok"; -}; - &pmi8998_charger { qcom,suspend-input; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi index 7f24c8bbb61629020e12773064c766025966d7d1..dd4e0b1684737398096a74f2e904616c64bcdea7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi @@ -12,8 +12,10 @@ #include "dsi-panel-sim-video.dtsi" #include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" #include "dsi-panel-sim-dualmipi-video.dtsi" #include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" #include "dsi-panel-sharp-dsc-4k-video.dtsi" #include "dsi-panel-sharp-dsc-4k-cmd.dtsi" #include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" @@ -23,6 +25,9 @@ #include "dsi-panel-sharp-1080p-cmd.dtsi" #include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi" #include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" #include &soc { @@ -116,6 +121,7 @@ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>; vddio-supply = <&pm8998_l14>; @@ -139,6 +145,7 @@ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>; vddio-supply = <&pm8998_l14>; @@ -151,8 +158,8 @@ label = "dsi_sharp_1080_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, <&mdss_dsi0_pll PCLK_MUX_0_CLK>; clock-names = "src_byte_clk", "src_pixel_clk"; @@ -162,6 +169,7 @@ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,dsi-panel = <&dsi_sharp_1080_cmd>; vddio-supply = <&pm8998_l14>; @@ -185,6 +193,7 @@ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>; vddio-supply = <&pm8998_l14>; @@ -231,6 +240,7 @@ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; vddio-supply = <&pm8998_l14>; @@ -243,27 +253,208 @@ label = "dsi_nt35597_truly_dsc_cmd_display"; qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_sim_vid_display: qcom,dsi-display@8 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_dual_sim_vid_display: qcom,dsi-display@9 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_vid_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, <&mdss_dsi0_pll PCLK_MUX_0_CLK>; clock-names = "src_byte_clk", "src_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@10 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_dual_sim_cmd_display: qcom,dsi-display@11 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_cmd>; + }; + + dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; + }; + + dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; + }; + + dsi_dual_nt35597_video_display: qcom,dsi-display@14 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_video>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + + dsi_dual_nt35597_cmd_display: qcom,dsi-display@15 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; pinctrl-0 = <&sde_dsi_active &sde_te_active>; pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; - qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; + qcom,dsi-panel = <&dsi_dual_nt35597_cmd>; vddio-supply = <&pm8998_l14>; lab-supply = <&lab_regulator>; ibb-supply = <&ibb_regulator>; }; - dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { + dsi_dual_nt36850_truly_cmd_display: qcom,dsi-display@16 { compatible = "qcom,dsi-display"; - label = "dsi_nt35597_truly_dsc_video_display"; + label = "dsi_dual_nt36850_truly_cmd_display"; qcom,display-type = "primary"; qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; @@ -277,8 +468,9 @@ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; qcom,platform-te-gpio = <&tlmm 10 0>; qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; - qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; + qcom,dsi-panel = <&dsi_dual_nt36850_truly_cmd>; vddio-supply = <&pm8998_l14>; lab-supply = <&lab_regulator>; ibb-supply = <&ibb_regulator>; @@ -289,50 +481,339 @@ cell-index = <0>; label = "wb_display"; }; + + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pmi8998_pdphy>; + qcom,ext-disp = <&ext_disp>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 43 0>; + qcom,aux-sel-gpio = <&tlmm 51 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; }; &mdss_mdp { - connectors = <&sde_wb &dsi_dual_nt35597_truly_video_display>; + connectors = <&sde_rscc &sde_wb &sde_dp>; }; &dsi_dual_nt35597_truly_video { - qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04]; qcom,mdss-dsi-t-clk-post = <0x0D>; qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; }; &dsi_dual_nt35597_truly_cmd { - qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04]; qcom,mdss-dsi-t-clk-post = <0x0D>; qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; }; &dsi_nt35597_truly_dsc_cmd { - qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04]; qcom,mdss-dsi-t-clk-post = <0x0b>; qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; }; &dsi_nt35597_truly_dsc_video { - qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04]; qcom,mdss-dsi-t-clk-post = <0x0b>; qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 04 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; }; &dsi_sharp_4k_dsc_video { - qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04]; - qcom,mdss-dsi-t-clk-post = <0x0a>; - qcom,mdss-dsi-t-clk-pre = <0x1e>; + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; }; &dsi_sharp_4k_dsc_cmd { - qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04]; - qcom,mdss-dsi-t-clk-post = <0x0a>; - qcom,mdss-dsi-t-clk-pre = <0x1e>; + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; }; &dsi_dual_sharp_1080_120hz_cmd { - qcom,mdss-dsi-panel-timings = [00 24 09 09 26 24 09 09 06 03 04]; qcom,mdss-dsi-t-clk-post = <0x0f>; qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 05 03 04 00]; + qcom,mdss-dsi-panel-clockrate = <900000000>; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + timing@1{ + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + timing@2{ + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 30 0c 0d 2a 27 0c + 0d 09 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 03 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_video { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-timings = [00 1c 08 07 23 22 07 07 + 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-timings = [00 1c 08 07 23 22 07 07 + 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08 + 08 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi index 168f2a9e349258e69acdf555ea2e5ac9802dfdf9..967865b3ec10d1adb38a6e7263bc1235f28d6c4b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi @@ -23,6 +23,8 @@ clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; clock-names = "iface_clk"; clock-rate = <0>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; gdsc-supply = <&mdss_core_gdsc>; qcom,platform-supply-entries { #address-cells = <1>; @@ -50,6 +52,8 @@ clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; clock-names = "iface_clk"; clock-rate = <0>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; gdsc-supply = <&mdss_core_gdsc>; qcom,platform-supply-entries { #address-cells = <1>; @@ -64,4 +68,46 @@ }; }; }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + compatible = "qcom,mdss_dp_pll_10nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + gdsc-supply = <&mdss_core_gdsc>; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk", + "cfg_ahb_clk", "pipe_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + + }; + }; + }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index cb5d924698b86921fc31731ff104bed0a7d27561..4194e67560493d51fe0eb9b0b63ce465d2688a19 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -9,14 +9,17 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include &soc { mdss_mdp: qcom,mdss_mdp@ae00000 { compatible = "qcom,sde-kms"; reg = <0x0ae00000 0x81d40>, - <0x0aeb0000 0x2008>; + <0x0aeb0000 0x2008>, + <0x0aeac000 0xf0>; reg-names = "mdp_phys", - "vbif_phys"; + "vbif_phys", + "regdma_phys"; clocks = <&clock_gcc GCC_DISP_AHB_CLK>, @@ -28,21 +31,23 @@ clock-names = "gcc_iface", "gcc_bus", "iface_clk", "bus_clk", "core_clk", "vsync_clk"; clock-rate = <0 0 0 0 300000000 19200000 0>; - clock-max-rate = <0 0 0 0 430000000 19200000 0>; + clock-max-rate = <0 0 0 0 412500000 19200000 0>; sde-vdd-supply = <&mdss_core_gdsc>; /* interrupt config */ - interrupt-parent = <&intc>; + interrupt-parent = <&pdc>; interrupts = <0 83 0>; interrupt-controller; #interrupt-cells = <1>; - iommus = <&apps_smmu 0x880>, <&apps_smmu 0x888>, - <&apps_smmu 0xc80>, <&apps_smmu 0xc88>; + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; #address-cells = <1>; #size-cells = <0>; + #power-domain-cells = <0>; + /* hw blocks */ qcom,sde-off = <0x1000>; qcom,sde-len = <0x45C>; @@ -50,19 +55,31 @@ qcom,sde-ctl-off = <0x2000 0x2200 0x2400 0x2600 0x2800>; qcom,sde-ctl-size = <0xE4>; + qcom,sde-ctl-display-pref = "primary", "primary", "none", + "none", "none"; - qcom,sde-mixer-off = <0x45000 0x46000 0x47000 - 0x48000 0x49000 0x4a000>; + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 0 0 0x4a000>; qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0xc>; qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>; - qcom,sde-dspp-size = <0x4>; + qcom,sde-dspp-size = <0x17e0>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0xc>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0x800>; qcom,sde-wb-off = <0x66000>; qcom,sde-wb-size = <0x2c8>; - qcom,sde-wb-xin-id = <6>; qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x3b8 24>; + qcom,sde-intf-off = <0x6b000 0x6b800 0x6c000 0x6c800>; qcom,sde-intf-size = <0x280>; @@ -80,12 +97,10 @@ qcom,sde-dsc-off = <0x81000 0x81400 0x81800 0x81c00>; qcom,sde-dsc-size = <0x140>; - qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0 0x0>; qcom,sde-dither-version = <0x00010000>; qcom,sde-dither-size = <0x20>; - qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>; - qcom,sde-sspp-type = "vig", "vig", "vig", "vig", "dma", "dma", "dma", "dma"; @@ -118,20 +133,89 @@ qcom,sde-wb-linewidth = <4096>; qcom,sde-mixer-blendstages = <0xb>; qcom,sde-highest-bank-bit = <0x2>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-smart-panel-align-mode = <0xc>; qcom,sde-panic-per-pipe; qcom,sde-has-cdp; qcom,sde-has-src-split; qcom,sde-has-dim-layer; - qcom,sde-max-bw-low-kbps = <9600000>; - qcom,sde-max-bw-high-kbps = <9600000>; + qcom,sde-has-idle-pc; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <6800000>; + qcom,sde-max-bw-high-kbps = <6800000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; qcom,sde-dram-channels = <2>; qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ad-version = <0x00040000>; + qcom,sde-dspp-ad-off = <0x28000 0x27000>; qcom,sde-vbif-off = <0>; qcom,sde-vbif-size = <0x1040>; qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 + 0x00000000>; + qcom,sde-safe-lut-linear = + <4 0xfff8>, + <0 0xfff0>; + qcom,sde-safe-lut-macrotile = + <10 0xfe00>, + <11 0xfc00>, + <12 0xf800>, + <0 0xf000>; + qcom,sde-safe-lut-nrt = + <0 0xffff>; + qcom,sde-safe-lut-cwb = + <0 0xffff>; + qcom,sde-qos-lut-linear = + <4 0x00000000 0x00000357>, + <5 0x00000000 0x00003357>, + <6 0x00000000 0x00023357>, + <7 0x00000000 0x00223357>, + <8 0x00000000 0x02223357>, + <9 0x00000000 0x22223357>, + <10 0x00000002 0x22223357>, + <11 0x00000022 0x22223357>, + <12 0x00000222 0x22223357>, + <13 0x00002222 0x22223357>, + <14 0x00012222 0x22223357>, + <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = + <10 0x00000003 0x44556677>, + <11 0x00000033 0x44556677>, + <12 0x00000233 0x44556677>, + <13 0x00002233 0x44556677>, + <14 0x00012233 0x44556677>, + <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-nrt = + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = + <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; qcom,sde-inline-rotator = <&mdss_rotator 0>; + qcom,sde-inline-rot-xin = <10 11>; + qcom,sde-inline-rot-xin-type = "sspp", "wb"; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>; + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x1>; + qcom,sde-reg-dma-trigger-off = <0x119c>; qcom,sde-sspp-vig-blocks { qcom,sde-vig-csc-off = <0x1a00>; @@ -139,6 +223,18 @@ qcom,sde-vig-qseed-size = <0xa0>; }; + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040000>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + }; + qcom,platform-supply-entries { #address-cells = <1>; #size-cells = <0>; @@ -153,15 +249,41 @@ }; }; + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x881 0x8>, + <&apps_smmu 0xc81 0x8>; + }; + /* data and reg bus scale settings */ qcom,sde-data-bus { - qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,name = "mdss_sde_mnoc"; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = - <22 512 0 0>, <23 512 0 0>, - <22 512 0 6400000>, <23 512 0 6400000>, - <22 512 0 6400000>, <23 512 0 6400000>; + <22 773 0 0>, <23 773 0 0>, + <22 773 0 6400000>, <23 773 0 6400000>, + <22 773 0 6400000>, <23 773 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "mdss_sde_llcc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <132 770 0 0>, + <132 770 0 6400000>, + <132 770 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "mdss_sde_ebi"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 6400000>, + <129 512 0 6400000>; }; qcom,sde-reg-bus { @@ -178,7 +300,6 @@ }; sde_rscc: qcom,sde_rscc@af20000 { - status = "disabled"; cell-index = <0>; compatible = "qcom,sde-rsc"; reg = <0xaf20000 0x1c44>, @@ -187,28 +308,52 @@ qcom,sde-rsc-version = <1>; vdd-supply = <&mdss_core_gdsc>; - clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>, - <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>; - clock-names = "iface_clk", "vsync_clk"; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "iface_clk"; clock-rate = <0 0>; qcom,sde-dram-channels = <2>; + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + /* data and reg bus scale settings */ qcom,sde-data-bus { - qcom,msm-bus,name = "disp_rsc"; + qcom,msm-bus,name = "disp_rsc_mnoc"; qcom,msm-bus,active-only; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = - <20003 20512 0 0>, <20004 20512 0 0>, - <20003 20512 0 6400000>, <20004 20512 0 6400000>, - <20003 20512 0 6400000>, <20004 20512 0 6400000>; + <20003 20515 0 0>, <20004 20515 0 0>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; }; }; mdss_rotator: qcom,mdss_rotator@ae00000 { - status = "disabled"; compatible = "qcom,sde_rotator"; reg = <0x0ae00000 0xac000>, <0x0aeb8000 0x3000>; @@ -219,8 +364,6 @@ qcom,mdss-rot-mode = <1>; qcom,mdss-highest-bank-bit = <0x2>; - qcom,sde-ubwc-malsize = <1>; - qcom,sde-ubwc-swizzle = <1>; /* Bus Scale Settings */ qcom,msm-bus,name = "mdss_rotator"; @@ -238,17 +381,30 @@ <&clock_gcc GCC_DISP_AHB_CLK>, <&clock_gcc GCC_DISP_AXI_CLK>, <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, - <&clock_dispcc DISP_CC_MDSS_ROT_CLK_SRC>, <&clock_dispcc DISP_CC_MDSS_ROT_CLK>, <&clock_dispcc DISP_CC_MDSS_AXI_CLK>; clock-names = "gcc_iface", "gcc_bus", - "iface_clk", "rot_core_clk", - "rot_clk", "axi_clk"; + "iface_clk", "rot_clk", "axi_clk"; interrupt-parent = <&mdss_mdp>; interrupts = <2 0>; - qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>; + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + /* Inline rotator QoS Setting */ + /* setting default register values for RD - qos/danger/safe */ + qcom,mdss-inline-rot-qos-lut = <0x44556677 0x00112233 + 0x44556677 0x00112233>; + qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>; + qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>; qcom,mdss-default-ot-rd-limit = <32>; qcom,mdss-default-ot-wr-limit = <32>; @@ -258,17 +414,25 @@ cache-slice-names = "rotator"; cache-slices = <&llcc 4>; + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { compatible = "qcom,smmu_sde_rot_unsec"; - iommus = <&apps_smmu 0x1090>; - gdsc-mdss-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; + iommus = <&apps_smmu 0x1090 0x0>; }; smmu_rot_sec: qcom,smmu_rot_sec_cb { - status = "disabled"; compatible = "qcom,smmu_sde_rot_sec"; - iommus = <&apps_smmu 0x1091>; - gdsc-mdss-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; + iommus = <&apps_smmu 0x1091 0x0>; }; }; @@ -291,7 +455,7 @@ clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", "pixel_clk", "pixel_clk_rcg", "esc_clk"; - + qcom,null-insertion-enabled; qcom,ctrl-supply-entries { #address-cells = <1>; #size-cells = <0>; @@ -325,6 +489,7 @@ <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>; clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", "pixel_clk", "pixel_clk_rcg", "esc_clk"; + qcom,null-insertion-enabled; qcom,ctrl-supply-entries { #address-cells = <1>; #size-cells = <0>; @@ -406,4 +571,91 @@ }; }; + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + gdsc-supply = <&mdss_core_gdsc>; + vdda-1p2-supply = <&pm8998_l26>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea030 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_pixel_clk", + "crypto_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13 23 1d]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 bb]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi index a03148d6620ece612c7e9a7046737c1b0dca3565..efb337dbe3f96d3ccd3ec62006604428238b9238 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" + &pmi8998_charger { qcom,suspend-input; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi index 7b8b425c627fa49e332ada7ae261977dfd0de069..a2978358bfbb4822a132a355f0dec833d491fdb9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi @@ -330,4 +330,16 @@ interrupt-controller; #interrupt-cells = <2>; }; + + /* wlan - inbound entry from mss/WLAN PD */ + smp2pgpio_wlan_1_in: qcom,smp2pgpio-wlan-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "wlan"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5b3e96426edf09a1a98e57e31b25d46ab9750877 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <1 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..0d6c5e08c98fb2575a1d6f8bf3b296241ce5c021 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <8 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..764c1455c83997f5e6860add8186807ebc4c3997 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts @@ -0,0 +1,64 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <11 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..05d77d329851b8571d4e4aa0f66c97d3a5241a34 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2017, 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 { + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy3: qcom,csiphy@ac68000 { + cell-index = <3>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac68000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x68000>; + interrupts = <0 448 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY3_CLK>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + non-fatal-fault-disabled; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1038 0x0>, + <&apps_smmu 0x1058 0x0>, + <&apps_smmu 0x1039 0x0>, + <&apps_smmu 0x1059 0x0>; + label = "lrme"; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x808 0x0>, + <&apps_smmu 0x810 0x8>, + <&apps_smmu 0xc08 0x0>, + <&apps_smmu 0xc10 0x8>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x107A 0x2>, + <&apps_smmu 0x1020 0x8>, + <&apps_smmu 0x1040 0x8>, + <&apps_smmu 0x1030 0x0>, + <&apps_smmu 0x1050 0x0>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0xd800000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.3 GB */ + iova-region-name = "io"; + iova-region-start = <0xd900000>; + iova-region-len = <0xd2700000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1000 0x0>; + label = "cpas-cdm0"; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 19200000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "csiphy3", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas0"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_hf_2", + "cam_sf_1", "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 200000000 200000000>, + <0 0 0 0 0 269000000 269000000>, + <0 0 0 0 0 320000000 320000000>, + <0 0 0 0 0 400000000 400000000>; + + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3cd7678b2b618538726f1314daf3f8576cd226ed --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2 CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts index 8ab05935ab8b4465a383735d736713e602f6a6aa..66ee4c71aea5a8ac5930689e655ce7771853ba8b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-cdp.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845-v2.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-cdp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..e049357e6f61b571a48572fef8519910d735b3db --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts index 57c3e7168d92721e20afe9a3e1ad30bfb4c6252e..cea38e6fe7fd82b9bb58c125fc5b169107dcbf58 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts @@ -14,6 +14,7 @@ /dts-v1/; #include "sdm845-v2.dtsi" +#include "sdm845-sde-display.dtsi" #include "sdm845-mtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a5a32ab25093088819bf7ffd8bd1dac2a69250da --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2 QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..9a876175d87058841e11cca821c726486f41d5ac --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2017, 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 "sdm845-v2.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2 QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d26c975fd3e2196f92781913d371dfd51cc8f81a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt-overlay.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include "sdm845-v2-qvr-dvt.dtsi" +#include "sdm845-qvr-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2 DVT QVR"; + compatible = "qcom,sdm845-qvr", "qcom,sdm845", "qcom,qvr"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <0x02000B 0x20>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dts new file mode 100644 index 0000000000000000000000000000000000000000..9110954107ef859b612df718c314e50c8fdd38fa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017-2018, 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 "sdm845-v2.dtsi" +#include "sdm845-v2-qvr-dvt.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2 DVT QVR"; + compatible = "qcom,sdm845-qvr", "qcom,sdm845", "qcom,qvr"; + qcom,board-id = <0x02000B 0x20>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c629c53cb0644bf992a32d9afdcb16a2c5623e4a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-dvt.dtsi @@ -0,0 +1,15 @@ +/* Copyright (c) 2017-2018, 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 "sdm845-qvr.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-camera-sensor-qvr.dtsi" + diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..51720980daf5519e9c50eccf31e18c81655f0e60 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt-overlay.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2017-2018, 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/; +/plugin/; + +#include "sdm845-v2-qvr-evt.dtsi" +#include "sdm845-qvr-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2 EVT QVR"; + compatible = "qcom,sdm845-qvr", "qcom,sdm845", "qcom,qvr"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <0x01000B 0x20>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt.dts new file mode 100644 index 0000000000000000000000000000000000000000..19b12e292714c9af67b5677f95745c45bf70c1cc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2017-2018, 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 "sdm845-v2.dtsi" +#include "sdm845-v2-qvr-evt.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2 EVT QVR"; + compatible = "qcom,sdm845-qvr", "qcom,sdm845", "qcom,qvr"; + qcom,board-id = <0x01000B 0x20>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c629c53cb0644bf992a32d9afdcb16a2c5623e4a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qvr-evt.dtsi @@ -0,0 +1,15 @@ +/* Copyright (c) 2017-2018, 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 "sdm845-qvr.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-camera-sensor-qvr.dtsi" + diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..b7bc3dc44a46798153861529d4910c4acb5bdc9f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-cdp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 v2.1 4K Display Panel CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <1 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..95bd94b862cb1d375eeb344619d177692becefa9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-mtp-overlay.dts @@ -0,0 +1,66 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 v2.1 4K Display Panel MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..42ccbf5f619e05a050ce14987fb52525f5c1a570 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-4k-panel-qrd-overlay.dts @@ -0,0 +1,64 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. sdm845 v2.1 4K Display Panel QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <11 1>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/ qcom,dsi-display-active; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,mdss-dsi-panel-orientation = "180"; +}; + +&dsi_sharp_4k_dsc_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..0825f4b56b158e2ed34419dfe13e6949f016642a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-cdp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-cdp.dtsi" +#include "sdm845-cdp-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 CDP"; + compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7b3573a3b03008937bf71ea43fff515f37e6adff --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..15d79c28d7cf7140cc2c1a1fa1f5e05594e5e72a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-qrd-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-qrd.dtsi" +#include "sdm845-qrd-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 QRD"; + compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts new file mode 100644 index 0000000000000000000000000000000000000000..2902a6042927c9d9dced6e9e000d63fb287ad64f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2017, 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 "sdm845-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 SoC"; + compatible = "qcom,sdm845"; + qcom,board-id = <0 0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b29827270c268f3400664e4672ecca0716334484 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi @@ -0,0 +1,31 @@ +/* Copyright (c) 2017, 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 "sdm845-v2.dtsi" +#include "sdm845-v2-camera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2.1"; + qcom,msm-id = <321 0x20001>; +}; + +&spmi_bus { + /delete-property/ qcom,enable-ahb-bus-workaround; +}; + +&clock_gcc { + compatible = "qcom,gcc-sdm845-v2.1", "syscon"; +}; + +&apps_smmu { + /delete-property/ qcom,no-asid-retention; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.dts new file mode 100644 index 0000000000000000000000000000000000000000..d36d0fd55d831c68fed7a06a452d185ab0235201 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sdm845-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2 SoC"; + compatible = "qcom,sdm845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index efd8c32f3ea680b6839dadfcc1aa95e47851a2cd..947d28b9a9eb31d476a1c5e0e0dd35552abe809c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -11,12 +11,664 @@ */ #include "sdm845.dtsi" +#include "sdm845-v2-camera.dtsi" / { model = "Qualcomm Technologies, Inc. SDM845 V2"; qcom,msm-id = <321 0x20000>; }; -&spmi_debug_bus { +&sdhc_2 { + /delete-property/ qcom,sdr104-wa; +}; + +/delete-node/ &pdc; + +&tlmm { + compatible = "qcom,sdm845-pinctrl-v2"; +}; + +&soc { + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + label = "modem"; + }; + }; + + gpu_gx_domain_addr: syscon@0x5091508 { + compatible = "syscon"; + reg = <0x5091508 0x4>; + }; + + gpu_gx_sw_reset: syscon@0x5091008 { + compatible = "syscon"; + reg = <0x5091008 0x4>; + }; + + pdc: interrupt-controller@0xb220000{ + compatible = "qcom,pdc-sdm845-v2"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + +}; + +&pil_modem { + qcom,mss_pdc_offset = <9>; +}; + +&clock_cpucc { + compatible = "qcom,clk-cpu-osm-v2"; +}; + +&pcie1 { + qcom,phy-sequence = <0x1804 0x03 0x0 + 0x00dc 0x27 0x0 + 0x0014 0x01 0x0 + 0x0020 0x31 0x0 + 0x0024 0x01 0x0 + 0x0028 0xde 0x0 + 0x002c 0x07 0x0 + 0x0034 0x4c 0x0 + 0x0038 0x06 0x0 + 0x0054 0x18 0x0 + 0x0058 0xb0 0x0 + 0x006c 0x8c 0x0 + 0x0070 0x20 0x0 + 0x0078 0x14 0x0 + 0x007c 0x34 0x0 + 0x00b4 0x06 0x0 + 0x00b8 0x06 0x0 + 0x00c0 0x16 0x0 + 0x00c4 0x16 0x0 + 0x00cc 0x36 0x0 + 0x00d0 0x36 0x0 + 0x00f0 0x05 0x0 + 0x00f8 0x42 0x0 + 0x0100 0x82 0x0 + 0x0108 0x68 0x0 + 0x011c 0x55 0x0 + 0x0120 0x55 0x0 + 0x0124 0x03 0x0 + 0x0128 0xab 0x0 + 0x012c 0xaa 0x0 + 0x0130 0x02 0x0 + 0x0150 0x3f 0x0 + 0x0158 0x3f 0x0 + 0x0178 0x10 0x0 + 0x01cc 0x04 0x0 + 0x01d0 0x30 0x0 + 0x01e0 0x04 0x0 + 0x01e8 0x73 0x0 + 0x01f0 0x1c 0x0 + 0x01fc 0x15 0x0 + 0x021c 0x04 0x0 + 0x0224 0x01 0x0 + 0x0228 0x22 0x0 + 0x022c 0x00 0x0 + 0x0098 0x05 0x0 + 0x080c 0x00 0x0 + 0x0818 0x0d 0x0 + 0x0860 0x01 0x0 + 0x0864 0x3a 0x0 + 0x087c 0x2f 0x0 + 0x08c0 0x09 0x0 + 0x08c4 0x09 0x0 + 0x08c8 0x1a 0x0 + 0x08d0 0x01 0x0 + 0x08d4 0x07 0x0 + 0x08d8 0x31 0x0 + 0x08dc 0x31 0x0 + 0x08e0 0x03 0x0 + 0x08fc 0x02 0x0 + 0x0900 0x01 0x0 + 0x0908 0x12 0x0 + 0x0914 0x25 0x0 + 0x0918 0x00 0x0 + 0x091c 0x05 0x0 + 0x0920 0x01 0x0 + 0x0924 0x26 0x0 + 0x0928 0x12 0x0 + 0x0930 0x04 0x0 + 0x0934 0x04 0x0 + 0x0938 0x09 0x0 + 0x0954 0x15 0x0 + 0x0960 0x32 0x0 + 0x0968 0x7f 0x0 + 0x096c 0x07 0x0 + 0x0978 0x04 0x0 + 0x0980 0x70 0x0 + 0x0984 0x8b 0x0 + 0x0988 0x08 0x0 + 0x098c 0x09 0x0 + 0x0990 0x03 0x0 + 0x0994 0x04 0x0 + 0x0998 0x02 0x0 + 0x099c 0x0c 0x0 + 0x09a4 0x02 0x0 + 0x09c0 0x5c 0x0 + 0x09c4 0x3e 0x0 + 0x09c8 0x3f 0x0 + 0x0a30 0x01 0x0 + 0x0a34 0xa0 0x0 + 0x0a38 0x08 0x0 + 0x0aa4 0x01 0x0 + 0x0aac 0xc3 0x0 + 0x0ab0 0x00 0x0 + 0x0ab8 0x8c 0x0 + 0x0ac0 0x7f 0x0 + 0x0ac4 0x2a 0x0 + 0x0810 0x0c 0x0 + 0x0814 0x00 0x0 + 0x0acc 0x04 0x0 + 0x093c 0x20 0x0 + 0x100c 0x00 0x0 + 0x1018 0x0d 0x0 + 0x1060 0x01 0x0 + 0x1064 0x3a 0x0 + 0x107c 0x2f 0x0 + 0x10c0 0x09 0x0 + 0x10c4 0x09 0x0 + 0x10c8 0x1a 0x0 + 0x10d0 0x01 0x0 + 0x10d4 0x07 0x0 + 0x10d8 0x31 0x0 + 0x10dc 0x31 0x0 + 0x10e0 0x03 0x0 + 0x10fc 0x02 0x0 + 0x1100 0x01 0x0 + 0x1108 0x12 0x0 + 0x1114 0x25 0x0 + 0x1118 0x00 0x0 + 0x111c 0x05 0x0 + 0x1120 0x01 0x0 + 0x1124 0x26 0x0 + 0x1128 0x12 0x0 + 0x1130 0x04 0x0 + 0x1134 0x04 0x0 + 0x1138 0x09 0x0 + 0x1154 0x15 0x0 + 0x1160 0x32 0x0 + 0x1168 0x7f 0x0 + 0x116c 0x07 0x0 + 0x1178 0x04 0x0 + 0x1180 0x70 0x0 + 0x1184 0x8b 0x0 + 0x1188 0x08 0x0 + 0x118c 0x09 0x0 + 0x1190 0x03 0x0 + 0x1194 0x04 0x0 + 0x1198 0x02 0x0 + 0x119c 0x0c 0x0 + 0x11a4 0x02 0x0 + 0x11c0 0x5c 0x0 + 0x11c4 0x3e 0x0 + 0x11c8 0x3f 0x0 + 0x1230 0x01 0x0 + 0x1234 0xa0 0x0 + 0x1238 0x08 0x0 + 0x12a4 0x01 0x0 + 0x12ac 0xc3 0x0 + 0x12b0 0x00 0x0 + 0x12b8 0x8c 0x0 + 0x12c0 0x7f 0x0 + 0x12c4 0x2a 0x0 + 0x1010 0x0c 0x0 + 0x1014 0x0f 0x0 + 0x12cc 0x04 0x0 + 0x113c 0x20 0x0 + 0x195c 0x3f 0x0 + 0x1974 0x50 0x0 + 0x196c 0x9f 0x0 + 0x182c 0x19 0x0 + 0x1840 0x07 0x0 + 0x1854 0x17 0x0 + 0x1868 0x09 0x0 + 0x1800 0x00 0x0 + 0x0aa8 0x01 0x0 + 0x12a8 0x01 0x0 + 0x1808 0x01 0x0>; +}; + +&devfreq_l3lat_0 { + qcom,core-dev-table = + < 300000 300000000 >, + < 480000 403200000 >, + < 652800 480000000 >, + < 748800 576000000 >, + < 902400 652800000 >, + < 979200 748800000 >, + < 1132800 844800000 >, + < 1228800 940800000 >, + < 1324800 1036800000 >, + < 1420800 1132800000 >, + < 1516800 1209600000 >, + < 1689600 1305600000 >, + < 1766400 1401600000 >; +}; + +&devfreq_l3lat_4 { + qcom,core-dev-table = + < 300000 300000000 >, + < 825600 576000000 >, + < 1132800 748800000 >, + < 1363200 940800000 >, + < 1689600 1209600000 >, + < 1996800 1305600000 >, + < 2400000 1401600000 >, + < 2745600 1593600000 >; +}; + +&bwmon { + qcom,count-unit = <0x10000>; +}; + +&cpubw { + qcom,bw-tbl = + < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ + < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */ + < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */ + < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ + < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */ + < MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */ + < MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */ +}; + +&devfreq_cpufreq { + mincpubw-cpufreq { + cpu-to-dev-map-4 = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2400000 MHZ_TO_MBPS(1017, 4) >; + }; +}; + +&devfreq_compute { + qcom,core-dev-table = + < 1881600 MHZ_TO_MBPS( 200, 4) >, + < 2649600 MHZ_TO_MBPS(1017, 4) >, + < 2745600 MHZ_TO_MBPS(1804, 4) >; +}; + +&clock_gcc { + compatible = "qcom,gcc-sdm845-v2", "syscon"; +}; + +&clock_camcc { + compatible = "qcom,cam_cc-sdm845-v2", "syscon"; + qcom,cam_cc_csi3phytimer_clk_src-opp-handle = <&cam_csiphy3>; +}; + +&clock_dispcc { + compatible = "qcom,dispcc-sdm845-v2", "syscon"; +}; + +&clock_gpucc { + compatible = "qcom,gpucc-sdm845-v2", "syscon"; +}; + +&clock_gfx { + compatible = "qcom,gfxcc-sdm845-v2"; +}; + +&clock_videocc { + compatible = "qcom,video_cc-sdm845-v2", "syscon"; +}; + +&msm_vidc { + qcom,allowed-clock-rates = <100000000 200000000 330000000 + 404000000 444000000 533000000>; +}; + +&refgen { status = "ok"; }; + +&spss_utils { + qcom,spss-dev-firmware-name = "spss2d"; /* 8 chars max */ + qcom,spss-test-firmware-name = "spss2t"; /* 8 chars max */ + qcom,spss-prod-firmware-name = "spss2p"; /* 8 chars max */ +}; + +&mdss_mdp { + clock-max-rate = <0 0 0 0 430000000 19200000 0>; + qcom,sde-min-core-ib-kbps = <4800000>; + qcom,sde-max-bw-low-kbps = <9600000>; + qcom,sde-max-bw-high-kbps = <9600000>; +}; + +&mdss_dsi0 { + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&mdss_dsi1 { + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&sde_dp { + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&energy_costs { + CPU_COST_0: core-cost0 { + busy-cost-data = < + 300000 12 + 403200 17 + 480000 21 + 576000 27 + 652800 31 + 748800 37 + 825600 42 + 902400 47 + 979200 52 + 1056000 57 + 1132800 62 + 1228800 70 + 1324800 78 + 1420800 89 + 1516800 103 + 1612800 122 + 1689600 141 + 1766400 160 + >; + idle-cost-data = < + 22 18 14 12 + >; + }; + CPU_COST_1: core-cost1 { + busy-cost-data = < + 300000 189 + 403200 523 + 480000 763 + 576000 1052 + 652800 1273 + 748800 1536 + 825600 1736 + 902400 1926 + 979200 2108 + 1056000 2284 + 1132800 2456 + 1209600 2628 + 1286400 2804 + 1363200 2992 + 1459200 3255 + 1536000 3499 + 1612800 3786 + 1689600 4128 + 1766400 4535 + 1843200 5019 + 1920000 5583 + 1996800 6226 + 2092800 7120 + 2169600 7876 + 2246400 8628 + 2323200 9344 + 2400000 10030 + 2476800 10806 + 2553600 12045 + 2649600 15686 + 2745600 25586 + 2764800 30000 + 2784000 35000 + 2803200 40000 + >; + idle-cost-data = < + 100 80 60 40 + >; + }; + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 300000 3 + 403200 4 + 480000 4 + 576000 4 + 652800 5 + 748800 5 + 825600 6 + 902400 7 + 979200 7 + 1056000 8 + 1132800 9 + 1228800 9 + 1324800 10 + 1420800 11 + 1516800 12 + 1612800 13 + 1689600 15 + 1766400 17 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 300000 24 + 403200 24 + 480000 25 + 576000 25 + 652800 26 + 748800 27 + 825600 28 + 902400 29 + 979200 30 + 1056000 32 + 1132800 34 + 1209600 37 + 1286400 40 + 1363200 45 + 1459200 50 + 1536000 57 + 1612800 64 + 1689600 74 + 1766400 84 + 1843200 96 + 1920000 106 + 1996800 113 + 2092800 120 + 2169600 125 + 2246400 127 + 2323200 130 + 2400000 135 + 2476800 140 + 2553600 145 + 2649600 150 + 2745600 155 + 2764800 160 + 2784000 165 + 2803200 170 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; +}; + +&gpu_gx_gdsc { + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; + qcom,reset-aon-logic; +}; + +/* GPU overrides */ +&msm_gpu { + /* Updated chip ID */ + qcom,chipid = <0x06030001>; + qcom,initial-pwrlevel = <6>; + + qcom,gpu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <710000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <12>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <675000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <596000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <520000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <414000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <342000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <257000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; +}; + +&gmu { + qcom,gmu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gmu-pwrlevels"; + + /* GMU power levels must go from lowest to highest */ + qcom,gmu-pwrlevel@0 { + reg = <0>; + qcom,gmu-freq = <0>; + }; + + qcom,gmu-pwrlevel@1 { + reg = <1>; + qcom,gmu-freq = <200000000>; + }; + + qcom,gmu-pwrlevel@2 { + reg = <2>; + qcom,gmu-freq = <500000000>; + }; + }; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index b9dc816b79214a5d1bb8e23bb6598854372c8247..42299cd4355389943b4b26a844677a6741419499 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -16,16 +16,14 @@ &soc { msm_vidc: qcom,vidc@aa00000 { - compatible = "qcom,msm-vidc"; + compatible = "qcom,msm-vidc", "qcom,sdm845-vidc"; status = "ok"; reg = <0xaa00000 0x200000>; interrupts = ; - qcom,hfi = "venus"; - qcom,firmware-name = "venus"; - qcom,never-unload-fw; - qcom,sw-power-collapse; - qcom,max-secure-instances = <5>; - qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */ + + /* LLCC Info */ + cache-slice-names = "vidsc0", "vidsc1"; + cache-slices = <&llcc 2>, <&llcc 3>; /* Supply */ venus-supply = <&venus_gdsc>; @@ -47,23 +45,8 @@ "bus_clk", "core0_clk", "core0_bus_clk", "core1_clk", "core1_bus_clk"; qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>; - qcom,allowed-clock-rates = <200000000 320000000 380000000 - 444000000 533000000>; - qcom,max-hq-mbs-per-frame = <8160>; - qcom,max-hq-frames-per-sec = <60>; - qcom,clock-freq-tbl { - qcom,profile-enc { - qcom,codec-mask = <0x55555555>; - qcom,vpp-cycles-per-mb = <675>; - qcom,vsp-cycles-per-mb = <125>; - qcom,low-power-cycles-per-mb = <320>; - }; - qcom,profile-dec { - qcom,codec-mask = <0xffffffff>; - qcom,vpp-cycles-per-mb = <200>; - qcom,vsp-cycles-per-mb = <50>; - }; - }; + qcom,allowed-clock-rates = <100000000 200000000 320000000 + 380000000 444000000 533000000>; /* Buses */ bus_cnoc { @@ -80,7 +63,7 @@ label = "venus-ddr"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "performance"; + qcom,bus-governor = "msm-vidc-ddr"; qcom,bus-range-kbps = <1000 3388000>; }; arm9_bus_ddr { @@ -91,15 +74,22 @@ qcom,bus-governor = "performance"; qcom,bus-range-kbps = <1000 1000>; }; + venus_bus_llcc { + compatible = "qcom,msm-vidc,bus"; + label = "venus-llcc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-llcc"; + qcom,bus-range-kbps = <17000 125700>; + }; /* MMUs */ non_secure_cb { compatible = "qcom,msm-vidc,context-bank"; label = "venus_ns"; iommus = - <&apps_smmu 0x10a0>, - <&apps_smmu 0x10a8>, - <&apps_smmu 0x10b0>; + <&apps_smmu 0x10a0 0x8>, + <&apps_smmu 0x10b0 0x0>; buffer-types = <0xfff>; virtual-addr-pool = <0x70800000 0x6f800000>; }; @@ -108,10 +98,8 @@ compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_bitstream"; iommus = - <&apps_smmu 0x10a1>, - <&apps_smmu 0x10a9>, - <&apps_smmu 0x10a5>, - <&apps_smmu 0x10ad>; + <&apps_smmu 0x10a1 0x8>, + <&apps_smmu 0x10a5 0x8>; buffer-types = <0x241>; virtual-addr-pool = <0x4b000000 0x25800000>; qcom,secure-context-bank; @@ -121,8 +109,7 @@ compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_pixel"; iommus = - <&apps_smmu 0x10a3>, - <&apps_smmu 0x10ab>; + <&apps_smmu 0x10a3 0x8>; buffer-types = <0x106>; virtual-addr-pool = <0x25800000 0x25800000>; qcom,secure-context-bank; @@ -132,9 +119,8 @@ compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_non_pixel"; iommus = - <&apps_smmu 0x10a4>, - <&apps_smmu 0x10ac>, - <&apps_smmu 0x10b4>; + <&apps_smmu 0x10a4 0x8>, + <&apps_smmu 0x10b4 0x0>; buffer-types = <0x480>; virtual-addr-pool = <0x1000000 0x24800000>; qcom,secure-context-bank; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dts b/arch/arm64/boot/dts/qcom/sdm845.dts new file mode 100644 index 0000000000000000000000000000000000000000..a3fa3afd28b27e72e96c2ef13414b5256790e877 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2017, 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 "sdm845.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 SoC"; + compatible = "qcom,sdm845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0c89e81d7a7b52e17cdccad46940cbd1caac1289..783216594f05ce6a99d4926cb0957bedf99f1710 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -24,19 +24,32 @@ #include #include #include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) / { model = "Qualcomm Technologies, Inc. SDM845"; compatible = "qcom,sdm845"; - qcom,msm-id = <321 0x0>; - interrupt-parent = <&intc>; + qcom,msm-id = <321 0x10000>; + interrupt-parent = <&pdc>; aliases { ufshc1 = &ufshc_mem; /* Embedded UFS slot */ - ufshc2 = &ufshc_card; /* Removable UFS slot */ + pci-domain0 = &pcie0; + pci-domain1 = &pcie1; sdhc2 = &sdhc_2; /* SDC2 SD card slot */ }; + aliases { + serial0 = &qupv3_se9_2uart; + spi0 = &qupv3_se8_spi; + i2c0 = &qupv3_se10_i2c; + i2c1 = &qupv3_se3_i2c; + hsuart0 = &qupv3_se6_4uart; + }; + cpus { #address-cells = <2>; #size-cells = <0>; @@ -67,11 +80,14 @@ }; L1_I_0: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0x12000>; }; L1_D_0: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0xa000>; + }; + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x3000>; }; }; @@ -95,11 +111,14 @@ }; L1_I_100: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0x12000>; }; L1_D_100: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0xa000>; + }; + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x3000>; }; }; @@ -123,11 +142,14 @@ }; L1_I_200: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0x12000>; }; L1_D_200: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0xa000>; + }; + L1_TLB_200: l1-tlb { + qcom,dump-size = <0x3000>; }; }; @@ -151,11 +173,14 @@ }; L1_I_300: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0x12000>; }; L1_D_300: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x9000>; + qcom,dump-size = <0xa000>; + }; + L1_TLB_300: l1-tlb { + qcom,dump-size = <0x3000>; }; }; @@ -179,11 +204,14 @@ }; L1_I_400: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x24000>; }; L1_D_400: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x14000>; + }; + L1_TLB_400: l1-tlb { + qcom,dump-size = <0x3c00>; }; }; @@ -207,11 +235,14 @@ }; L1_I_500: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x24000>; }; L1_D_500: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x14000>; + }; + L1_TLB_500: l1-tlb { + qcom,dump-size = <0x3c00>; }; }; @@ -235,11 +266,14 @@ }; L1_I_600: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x24000>; }; L1_D_600: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x14000>; + }; + L1_TLB_600: l1-tlb { + qcom,dump-size = <0x3c00>; }; }; @@ -263,11 +297,14 @@ }; L1_I_700: l1-icache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x24000>; }; L1_D_700: l1-dcache { compatible = "arm,arch-cache"; - qcom,dump-size = <0x12000>; + qcom,dump-size = <0x14000>; + }; + L1_TLB_700: l1-tlb { + qcom,dump-size = <0x3c00>; }; }; @@ -310,26 +347,32 @@ }; }; - energy-costs { + energy_costs: energy-costs { + compatible = "sched-energy"; + CPU_COST_0: core-cost0 { busy-cost-data = < - 92 34 /* 300000 */ - 129 40 /* 422400 */ - 153 43 /* 499200 */ - 177 48 /* 576000 */ - 200 52 /* 652800 */ - 230 58 /* 748800 */ - 253 64 /* 825600 */ - 277 70 /* 902400 */ - 301 76 /* 979200 */ - 324 83 /* 1056000 */ - 348 90 /* 1132800 */ - 371 98 /* 1209600 */ - 395 105 /* 1286400 */ - 419 114 /* 1363200 */ - 442 123 /* 1440000 */ - 466 135 /* 1516800 */ - 490 152 /* 1593600 */ + 300000 31 + 422400 38 + 499200 42 + 576000 46 + 652800 51 + 748800 58 + 825600 64 + 902400 70 + 979200 76 + 1056000 83 + 1132800 90 + 1209600 97 + 1286400 105 + 1363200 114 + 1440000 124 + 1516800 136 + 1593600 152 + 1651200 167 /* speedbin 0,1 */ + 1670400 173 /* speedbin 2 */ + 1708800 186 /* speedbin 0,1 */ + 1747200 201 /* speedbin 2 */ >; idle-cost-data = < 22 18 14 12 @@ -337,52 +380,60 @@ }; CPU_COST_1: core-cost1 { busy-cost-data = < - 156 240 /* 300000 */ - 220 247 /* 422400 */ - 261 252 /* 499200 */ - 301 257 /* 576000 */ - 341 264 /* 652800 */ - 381 272 /* 729600 */ - 421 281 /* 806400 */ - 461 292 /* 883200 */ - 501 306 /* 960000 */ - 542 324 /* 1036800 */ - 582 346 /* 1113600 */ - 622 373 /* 1190400 */ - 662 407 /* 1267200 */ - 702 450 /* 1344000 */ - 742 504 /* 1420800 */ - 783 570 /* 1497600 */ - 823 649 /* 1574400 */ - 863 743 /* 1651200 */ - 903 849 /* 1728000 */ - 943 960 /* 1804800 */ - 983 1062 /* 1881600 */ - 1024 1131 /* 1958400 */ + 300000 258 + 422400 260 + 499200 261 + 576000 263 + 652800 267 + 729600 272 + 806400 280 + 883200 291 + 960000 305 + 1036800 324 + 1113600 348 + 1190400 378 + 1267200 415 + 1344000 460 + 1420800 513 + 1497600 576 + 1574400 649 + 1651200 732 + 1728000 824 + 1804800 923 + 1881600 1027 + 1958400 1131 + 2035000 1228 /* speedbin 1,2 */ + 2092000 1290 /* speedbin 1 */ + 2112000 1308 /* speedbin 2 */ + 2208000 1363 /* speedbin 2 */ >; idle-cost-data = < - 520 500 480 460 + 100 80 60 40 >; }; CLUSTER_COST_0: cluster-cost0 { busy-cost-data = < - 92 3 /* 300000 */ - 129 4 /* 422400 */ - 153 4 /* 499200 */ - 177 4 /* 576000 */ - 200 5 /* 652800 */ - 230 5 /* 748800 */ - 253 6 /* 825600 */ - 277 7 /* 902400 */ - 301 7 /* 979200 */ - 324 8 /* 1056000 */ - 348 9 /* 1132800 */ - 371 9 /* 1209600 */ - 395 10 /* 1286400 */ - 419 11 /* 1363200 */ - 442 12 /* 1440000 */ - 466 13 /* 1516800 */ - 490 15 /* 1593600 */ + 300000 3 + 422400 4 + 499200 4 + 576000 4 + 652800 5 + 748800 5 + 825600 6 + 902400 7 + 979200 7 + 1056000 8 + 1132800 9 + 1209600 9 + 1286400 10 + 1363200 11 + 1440000 12 + 1516800 13 + 1593600 15 + 1651200 17 /* speedbin 0,1 */ + 1670400 19 /* speedbin 2 */ + 1708800 21 /* speedbin 0,1 */ + 1747200 23 /* speedbin 2 */ >; idle-cost-data = < 4 3 2 1 @@ -390,28 +441,32 @@ }; CLUSTER_COST_1: cluster-cost1 { busy-cost-data = < - 156 24 /* 300000 */ - 220 24 /* 422400 */ - 261 25 /* 499200 */ - 301 25 /* 576000 */ - 341 26 /* 652800 */ - 381 27 /* 729600 */ - 421 28 /* 806400 */ - 461 29 /* 883200 */ - 501 30 /* 960000 */ - 542 32 /* 1036800 */ - 582 34 /* 1113600 */ - 622 37 /* 1190400 */ - 662 40 /* 1267200 */ - 702 45 /* 1344000 */ - 742 50 /* 1420800 */ - 783 57 /* 1497600 */ - 823 64 /* 1574400 */ - 863 74 /* 1651200 */ - 903 84 /* 1728000 */ - 943 96 /* 1804800 */ - 983 106 /* 1881600 */ - 1024 113 /* 1958400 */ + 300000 24 + 422400 24 + 499200 25 + 576000 25 + 652800 26 + 729600 27 + 806400 28 + 883200 29 + 960000 30 + 1036800 32 + 1113600 34 + 1190400 37 + 1267200 40 + 1344000 45 + 1420800 50 + 1497600 57 + 1574400 64 + 1651200 74 + 1728000 84 + 1804800 96 + 1881600 106 + 1958400 113 + 2035000 120 /* speedbin 1,2 */ + 2092000 125 /* speedbin 1 */ + 2112000 127 /* speedbin 2 */ + 2208000 130 /* speedbin 2 */ >; idle-cost-data = < 4 3 2 1 @@ -424,82 +479,136 @@ method = "smc"; }; + chosen { + bootargs = "rcupdate.rcu_expedited=1"; + }; + soc: soc { }; + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + }; + }; + }; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; - removed_regions: removed_regions@85800000 { + hyp_region: hyp_region@85700000 { + no-map; + reg = <0 0x85700000 0 0x600000>; + }; + + xbl_region: xbl_region@85e00000 { + no-map; + reg = <0 0x85e00000 0 0x100000>; + }; + + removed_region: removed_region@85fc0000 { + no-map; + reg = <0 0x85fc0000 0 0x2f40000>; + }; + + qseecom_mem: qseecom_region@0x8ab00000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0 0x8ab00000 0 0x1400000>; + }; + + pil_camera_mem: camera_region@0x8bf00000 { + compatible = "removed-dma-pool"; no-map; - reg = <0 0x85800000 0 0x3700000>; + reg = <0 0x8bf00000 0 0x500000>; }; - pil_camera_mem: camera_region@8ab00000 { + pil_ipa_fw_mem: ips_fw_region@0x8c400000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8ab00000 0 0x500000>; + reg = <0 0x8c400000 0 0x10000>; }; - pil_modem_mem: modem_region@8b000000 { + pil_ipa_gsi_mem: ipa_gsi_region@0x8c410000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8b000000 0 0x7300000>; + reg = <0 0x8c410000 0 0x5000>; }; - pil_video_mem: pil_video_region@92300000 { + pil_gpu_mem: gpu_region@0x8c415000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x92300000 0 0x500000>; + reg = <0 0x8c415000 0 0x2000>; }; - pil_cdsp_mem: cdsp_regions@92800000 { + pil_adsp_mem: adsp_region@0x8c500000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x92800000 0 0x800000>; + reg = <0 0x8c500000 0 0x1a00000>; }; - pil_adsp_mem: pil_adsp_region@93000000 { + wlan_fw_region: wlan_fw_region@0x8df00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93000000 0 0x1a00000>; + reg = <0 0x8df00000 0 0x100000>; }; - pil_mba_mem: pil_mba_region@0x94a00000 { + pil_modem_mem: modem_region@0x8e000000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x94a00000 0 0x200000>; + reg = <0 0x8e000000 0 0x7800000>; }; - pil_slpi_mem: pil_slpi_region@94c00000 { + pil_video_mem: video_region@0x95800000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x94c00000 0 0x1400000>; + reg = <0 0x95800000 0 0x500000>; }; - pil_ipa_fw_mem: pil_ipa_fw_region@96000000 { + pil_cdsp_mem: cdsp_region@0x95d00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96000000 0 0x10000>; + reg = <0 0x95d00000 0 0x800000>; }; - pil_ipa_gsi_mem: pil_ipa_gsi_region@96010000 { + pil_mba_mem: mba_region@0x96500000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96010000 0 0x5000>; + reg = <0 0x96500000 0 0x200000>; }; - pil_gpu_mem: pil_gpu_region@96015000 { + pil_slpi_mem: slpi_region@0x96700000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96015000 0 0x1000>; + reg = <0 0x96700000 0 0x1400000>; }; - pil_spss_mem: spss_region@96100000 { + pil_spss_mem: pil_spss_region@0x97b00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96100000 0 0x100000>; + reg = <0 0x97b00000 0 0x100000>; }; adsp_mem: adsp_region { @@ -507,18 +616,18 @@ alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0xc00000>; + size = <0 0x1000000>; }; - qseecom_mem: qseecom_region { + qseecom_ta_mem: qseecom_ta_region { compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0x1400000>; + size = <0 0x1000000>; }; - sp_mem: sp_region { /* SPSS-HLOS ION shared mem */ + secure_sp_mem: secure_sp_region { /* SPSS-HLOS ION shared mem */ compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; /* 32-bit */ reusable; @@ -526,6 +635,11 @@ size = <0 0x800000>; }; + cont_splash_memory: cont_splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x02400000>; + label = "cont_splash_region"; + }; + secure_display_memory: secure_display_region { compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; @@ -534,6 +648,12 @@ size = <0 0x5c00000>; }; + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + reusable; + size = <0 0x2400000>; + }; + /* global autoconfigured region for contiguous allocations */ linux,cma { compatible = "shared-dma-pool"; @@ -548,8 +668,8 @@ #include "msm-gdsc-sdm845.dtsi" #include "sdm845-sde-pll.dtsi" +#include "msm-rdbg.dtsi" #include "sdm845-sde.dtsi" -#include "sdm845-sde-display.dtsi" #include "sdm845-qupv3.dtsi" &soc { @@ -558,6 +678,94 @@ ranges = <0 0 0 0xffffffff>; compatible = "simple-bus"; + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + intc: interrupt-controller@17a00000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; @@ -567,6 +775,15 @@ reg = <0x17a00000 0x10000>, /* GICD */ <0x17a60000 0x100000>; /* GICR * 8 */ interrupts = <1 9 4>; + interrupt-parent = <&intc>; + }; + + pdc: interrupt-controller@b220000{ + compatible = "qcom,pdc-sdm845"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; }; timer { @@ -644,6 +861,12 @@ reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0xc440000 0x1100>, @@ -661,22 +884,25 @@ interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; + qcom,enable-ahb-bus-workaround; }; spmi_debug_bus: qcom,spmi-debug@6b22000 { compatible = "qcom,spmi-pmic-arb-debug"; reg = <0x6b22000 0x60>, <0x7820A8 4>; reg-names = "core", "fuse"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; qcom,fuse-disable-bit = <12>; #address-cells = <2>; #size-cells = <0>; - status = "disabled"; qcom,pm8998-debug@0 { compatible = "qcom,spmi-pmic"; reg = <0x0 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; + qcom,can-sleep; }; qcom,pm8998-debug@1 { @@ -684,6 +910,7 @@ reg = <0x1 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; + qcom,can-sleep; }; qcom,pmi8998-debug@2 { @@ -691,6 +918,7 @@ reg = <0x2 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; + qcom,can-sleep; }; qcom,pmi8998-debug@3 { @@ -698,6 +926,7 @@ reg = <0x3 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; + qcom,can-sleep; }; qcom,pm8005-debug@4 { @@ -705,6 +934,7 @@ reg = <0x4 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; + qcom,can-sleep; }; qcom,pm8005-debug@5 { @@ -712,77 +942,23 @@ reg = <0x5 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; + qcom,can-sleep; }; }; - msm_cpufreq: qcom,msm-cpufreq { - compatible = "qcom,msm-cpufreq"; - clock-names = "cpu0_clk", "cpu4_clk"; - clocks = <&clock_cpucc CPU0_PWRCL_CLK>, - <&clock_cpucc CPU4_PERFCL_CLK>; - - qcom,governor-per-policy; - - qcom,cpufreq-table-0 = - < 300000 >, - < 422400 >, - < 499200 >, - < 576000 >, - < 652800 >, - < 748800 >, - < 825600 >, - < 902400 >, - < 979200 >, - < 1056000 >, - < 1132800 >, - < 1209600 >, - < 1286400 >, - < 1363200 >, - < 1440000 >, - < 1516800 >, - < 1593600 >; - - qcom,cpufreq-table-4 = - < 300000 >, - < 422400 >, - < 499200 >, - < 576000 >, - < 652800 >, - < 729600 >, - < 806400 >, - < 883200 >, - < 960000 >, - < 1036800 >, - < 1113600 >, - < 1190400 >, - < 1267200 >, - < 1344000 >, - < 1420800 >, - < 1497600 >, - < 1574400 >, - < 1651200 >, - < 1728000 >, - < 1804800 >, - < 1881600 >, - < 1958400 >; - }; - cpubw: qcom,cpubw { compatible = "qcom,devbw"; governor = "performance"; - qcom,src-dst-ports = <1 512>; + qcom,src-dst-ports = + ; qcom,active-only; qcom,bw-tbl = - < 762 /* 200 MHz */ >, - < 1144 /* 300 MHz */ >, - < 1720 /* 451 MHz */ >, - < 2086 /* 547 MHz */ >, - < 2597 /* 681 MHz */ >, - < 2929 /* 768 MHz */ >, - < 3879 /* 1017 MHz */ >, - < 4943 /* 1296 MHz */ >, - < 5931 /* 1555 MHz */ >, - < 6881 /* 1804 MHz */ >; + < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ + < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */ + < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */ + < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ + < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */ + < MHZ_TO_MBPS(700, 16) >; /* 10681 MB/s */ }; bwmon: qcom,cpu-bwmon { @@ -795,22 +971,53 @@ qcom,target-dev = <&cpubw>; }; + llccbw: qcom,llccbw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + llcc_bwmon: qcom,llcc-bwmon { + compatible = "qcom,bimc-bwmon5"; + reg = <0x0114A000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&llccbw>; + qcom,count-unit = <0x400000>; + qcom,byte-mid-mask = <0xe000>; + qcom,byte-mid-match = <0xe000>; + }; + memlat_cpu0: qcom,memlat-cpu0 { compatible = "qcom,devbw"; governor = "powersave"; qcom,src-dst-ports = <1 512>; qcom,active-only; qcom,bw-tbl = - < 762 /* 200 MHz */ >, - < 1144 /* 300 MHz */ >, - < 1720 /* 451 MHz */ >, - < 2086 /* 547 MHz */ >, - < 2597 /* 681 MHz */ >, - < 2929 /* 768 MHz */ >, - < 3879 /* 1017 MHz */ >, - < 4943 /* 1296 MHz */ >, - < 5931 /* 1555 MHz */ >, - < 6881 /* 1804 MHz */ >; + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ }; memlat_cpu4: qcom,memlat-cpu4 { @@ -820,16 +1027,16 @@ qcom,active-only; status = "ok"; qcom,bw-tbl = - < 762 /* 200 MHz */ >, - < 1144 /* 300 MHz */ >, - < 1720 /* 451 MHz */ >, - < 2086 /* 547 MHz */ >, - < 2597 /* 681 MHz */ >, - < 2929 /* 768 MHz */ >, - < 3879 /* 1017 MHz */ >, - < 4943 /* 1296 MHz */ >, - < 5931 /* 1555 MHz */ >, - < 6881 /* 1804 MHz */ >; + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ }; snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { @@ -848,12 +1055,11 @@ qcom,target-dev = <&memlat_cpu0>; qcom,cachemiss-ev = <0x2A>; qcom,core-dev-table = - < 300000 762 >, - < 748800 1720 >, - < 979200 2929 >, - < 1209600 3879 >, - < 1516800 4943 >, - < 1593600 5931 >; + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 748800 MHZ_TO_MBPS( 451, 4) >, + < 1132800 MHZ_TO_MBPS( 547, 4) >, + < 1440000 MHZ_TO_MBPS( 768, 4) >, + < 1593600 MHZ_TO_MBPS(1017, 4) >; }; devfreq_memlat_4: qcom,cpu4-memlat-mon { @@ -862,12 +1068,14 @@ qcom,target-dev = <&memlat_cpu4>; qcom,cachemiss-ev = <0x2A>; qcom,core-dev-table = - < 300000 762 >, - < 1036800 2929 >, - < 1190400 3879 >, - < 1574400 4943 >, - < 1804800 5931 >, - < 1958400 6881 >; + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 499200 MHZ_TO_MBPS( 451, 4) >, + < 806400 MHZ_TO_MBPS( 547, 4) >, + < 1036800 MHZ_TO_MBPS( 768, 4) >, + < 1190400 MHZ_TO_MBPS(1017, 4) >, + < 1574400 MHZ_TO_MBPS(1296, 4) >, + < 1728000 MHZ_TO_MBPS(1555, 4) >, + < 1958400 MHZ_TO_MBPS(1804, 4) >; }; l3_cpu0: qcom,l3-cpu0 { @@ -875,16 +1083,6 @@ clock-names = "devfreq_clk"; clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; governor = "performance"; - freq-tbl-khz = - < 300000 >, - < 422400 >, - < 499200 >, - < 576000 >, - < 652800 >, - < 729600 >, - < 806400 >, - < 883200 >, - < 960000 >; }; l3_cpu4: qcom,l3-cpu4 { @@ -892,16 +1090,6 @@ clock-names = "devfreq_clk"; clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; governor = "performance"; - freq-tbl-khz = - < 300000 >, - < 422400 >, - < 499200 >, - < 576000 >, - < 652800 >, - < 729600 >, - < 806400 >, - < 883200 >, - < 960000 >; }; devfreq_l3lat_0: qcom,cpu0-l3lat-mon { @@ -910,12 +1098,13 @@ qcom,target-dev = <&l3_cpu0>; qcom,cachemiss-ev = <0x17>; qcom,core-dev-table = - < 300000 300000 >, - < 748800 576000 >, - < 979200 652800 >, - < 1209600 806400 >, - < 1516800 883200 >, - < 1593600 960000 >; + < 300000 300000000 >, + < 748800 576000000 >, + < 979200 652800000 >, + < 1209600 806400000 >, + < 1516800 883200000 >, + < 1593600 960000000 >, + < 1708800 1305600000 >; }; devfreq_l3lat_4: qcom,cpu4-l3lat-mon { @@ -924,11 +1113,19 @@ qcom,target-dev = <&l3_cpu4>; qcom,cachemiss-ev = <0x17>; qcom,core-dev-table = - < 300000 300000 >, - < 1036800 652800 >, - < 1190400 806400 >, - < 1574400 883200 >, - < 1651200 960000 >; + < 300000 300000000 >, + < 1036800 576000000 >, + < 1190400 806400000 >, + < 1574400 883200000 >, + < 1804800 960000000 >, + < 1958400 1305600000 >; + }; + + l3_cdsp: qcom,l3-cdsp { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; + governor = "powersave"; }; cpu_pmu: cpu-pmu { @@ -937,6 +1134,51 @@ interrupts = <1 5 4>; }; + mincpubw: qcom,mincpubw { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + devfreq_cpufreq: devfreq-cpufreq { + mincpubw-cpufreq { + target-dev = <&mincpubw>; + cpu-to-dev-map-0 = + < 1708800 MHZ_TO_MBPS(200, 4) >; + cpu-to-dev-map-4 = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2208000 MHZ_TO_MBPS(681, 4) >; + }; + }; + + devfreq_compute: qcom,devfreq-compute { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&mincpubw>; + qcom,core-dev-table = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2208000 MHZ_TO_MBPS(681, 4) >; + }; + + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sdm845"; + #clock-cells = <1>; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + }; + clock_gcc: qcom,gcc@100000 { compatible = "qcom,gcc-sdm845", "syscon"; reg = <0x100000 0x1f0000>; @@ -962,6 +1204,20 @@ reg-names = "cc_base"; vdd_cx-supply = <&pm8998_s9_level>; vdd_mx-supply = <&pm8998_s6_level>; + qcom,cam_cc_csi0phytimer_clk_src-opp-handle = <&cam_csiphy0>; + qcom,cam_cc_csi1phytimer_clk_src-opp-handle = <&cam_csiphy1>; + qcom,cam_cc_csi2phytimer_clk_src-opp-handle = <&cam_csiphy2>; + qcom,cam_cc_cci_clk_src-opp-handle = <&cam_cci>; + qcom,cam_cc_ife_0_csid_clk_src-opp-handle = <&cam_csid0>; + qcom,cam_cc_ife_0_clk_src-opp-handle = <&cam_vfe0>; + qcom,cam_cc_ife_1_csid_clk_src-opp-handle = <&cam_csid1>; + qcom,cam_cc_ife_1_clk_src-opp-handle = <&cam_vfe1>; + qcom,cam_cc_ife_lite_csid_clk_src-opp-handle = <&cam_csid_lite>; + qcom,cam_cc_ife_lite_clk_src-opp-handle = <&cam_vfe_lite>; + qcom,cam_cc_icp_clk_src-opp-handle = <&cam_a5>; + qcom,cam_cc_ipe_0_clk_src-opp-handle = <&cam_ipe0>; + qcom,cam_cc_ipe_1_clk_src-opp-handle = <&cam_ipe1>; + qcom,cam_cc_bps_clk_src-opp-handle = <&cam_bps>; #clock-cells = <1>; #reset-cells = <1>; }; @@ -980,6 +1236,7 @@ reg = <0x5090000 0x9000>; reg-names = "cc_base"; vdd_cx-supply = <&pm8998_s9_level>; + vdd_mx-supply = <&pm8998_s6_level>; qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>; #clock-cells = <1>; #reset-cells = <1>; @@ -990,132 +1247,31 @@ reg = <0x5090000 0x9000>; reg-names = "cc_base"; vdd_gfx-supply = <&pm8005_s1_level>; - vdd_mx-supply = <&pm8998_s6_level>; qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>; #clock-cells = <1>; #reset-cells = <1>; }; + cpucc_debug: syscon@17970018 { + compatible = "syscon"; + reg = <0x17970018 0x4>; + }; + clock_cpucc: qcom,cpucc@0x17d41000 { compatible = "qcom,clk-cpu-osm"; reg = <0x17d41000 0x1400>, <0x17d43000 0x1400>, - <0x17d45800 0x1400>, - <0x178d0000 0x1000>, - <0x178c0000 0x1000>, - <0x178b0000 0x1000>, - <0x17d42400 0x0c00>, - <0x17d44400 0x0c00>, - <0x17d46c00 0x0c00>; - reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base", - "l3_pll", "pwrcl_pll", "perfcl_pll", - "l3_sequencer", "pwrcl_sequencer", - "perfcl_sequencer"; - - vdd-l3-supply = <&apc0_l3_vreg>; - vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; - vdd-perfcl-supply = <&apc1_perfcl_vreg>; - - qcom,l3-speedbin0-v0 = - < 300000000 0x000c000f 0x00002020 0x1 1 >, - < 422400000 0x50140116 0x00002020 0x1 2 >, - < 499200000 0x5014021a 0x00002020 0x1 3 >, - < 576000000 0x5014031e 0x00002020 0x1 4 >, - < 652800000 0x401c0422 0x00002020 0x1 5 >, - < 729600000 0x401c0526 0x00002020 0x1 6 >, - < 806400000 0x401c062a 0x00002222 0x1 7 >; - - qcom,pwrcl-speedbin0-v0 = - < 300000000 0x000c000f 0x00002020 0x1 1 >, - < 422400000 0x50140116 0x00002020 0x1 2 >, - < 499200000 0x5014021a 0x00002020 0x1 3 >, - < 576000000 0x5014031e 0x00002020 0x1 4 >, - < 652800000 0x401c0422 0x00002020 0x1 5 >, - < 748800000 0x401c0527 0x00002020 0x1 6 >, - < 825600000 0x401c062b 0x00002222 0x1 7 >, - < 902400000 0x4024072f 0x00002626 0x1 8 >, - < 979200000 0x40240833 0x00002929 0x1 9 >, - < 1056000000 0x402c0937 0x00002c2c 0x1 10 >, - < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >, - < 1209600000 0x402c0b3f 0x00003333 0x1 12 >; - - qcom,perfcl-speedbin0-v0 = - < 300000000 0x000c000f 0x00002020 0x1 1 >, - < 422400000 0x50140116 0x00002020 0x1 2 >, - < 499200000 0x5014021a 0x00002020 0x1 3 >, - < 576000000 0x5014031e 0x00002020 0x1 4 >, - < 652800000 0x401c0422 0x00002020 0x1 5 >, - < 729600000 0x401c0526 0x00002020 0x1 6 >, - < 806400000 0x401c062a 0x00002222 0x1 7 >, - < 883200000 0x4024072e 0x00002525 0x1 8 >, - < 960000000 0x40240832 0x00002828 0x1 9 >, - < 1036800000 0x40240936 0x00002b2b 0x1 10 >, - < 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >, - < 1190400000 0x402c0b3e 0x00003232 0x1 12 >; - - qcom,l3-min-cpr-vc-bin0 = <7>; - qcom,pwrcl-min-cpr-vc-bin0 = <6>; - qcom,perfcl-min-cpr-vc-bin0 = <7>; - - qcom,up-timer = - <1000 1000 1000>; - qcom,down-timer = - <100000 100000 100000>; - qcom,pc-override-index = - <0 0 0>; - qcom,set-ret-inactive; - qcom,enable-llm-freq-vote; - qcom,llm-freq-up-timer = - <1000 1000 1000>; - qcom,llm-freq-down-timer = - <327675 327675 327675>; - qcom,enable-llm-volt-vote; - qcom,llm-volt-up-timer = - <1000 1000 1000>; - qcom,llm-volt-down-timer = - <327675 327675 327675>; - qcom,cc-reads = <10>; - qcom,cc-delay = <5>; - qcom,cc-factor = <100>; - qcom,osm-clk-rate = <100000000>; - qcom,xo-clk-rate = <19200000>; - - qcom,l-val-base = - <0x178d0004 0x178c0004 0x178b0004>; - qcom,apcs-pll-user-ctl = - <0x178d000c 0x178c000c 0x178b000c>; - qcom,apcs-pll-min-freq = - <0x17d41094 0x17d43094 0x17d45894>; - qcom,apm-mode-ctl = - <0x0 0x0 0x17d20010>; - qcom,apm-status-ctrl = - <0x0 0x0 0x17d20000>; - qcom,perfcl-isense-addr = <0x17871480>; - qcom,l3-mem-acc-addr = <0x17990170 0x17990170 0x17990170>; - qcom,pwrcl-mem-acc-addr = <0x17990160 0x17990164 0x17990164>; - qcom,perfcl-mem-acc-addr = <0x17990168 0x1799016c 0x1799016c>; - qcom,cfg-gfmux-addr =<0x178d0084 0x178c0084 0x178b0084>; - qcom,apcs-cbc-addr = <0x178d008c 0x178c008c 0x178b008c>; - qcom,apcs-ramp-ctl-addr = <0x17840904 0x17840904 0x17830904>; - - qcom,perfcl-apcs-apm-threshold-voltage = <800000>; - qcom,perfcl-apcs-mem-acc-threshold-voltage = <852000>; - qcom,boost-fsm-en; - qcom,safe-fsm-en; - qcom,ps-fsm-en; - qcom,droop-fsm-en; + <0x17d45800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base"; + vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>; + vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>; + + qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>; + l3-devs = <&l3_cpu0 &l3_cpu4 &l3_cdsp>; clock-names = "xo_ao"; clocks = <&clock_rpmh RPMH_CXO_CLK_A>; #clock-cells = <1>; - #reset-cells = <1>; - }; - - clock_rpmh: qcom,rpmhclk { - compatible = "qcom,rpmh-clk-sdm845"; - #clock-cells = <1>; - mboxes = <&apps_rsc 0>; - mbox-names = "apps"; }; clock_debug: qcom,cc-debug@100000 { @@ -1126,18 +1282,42 @@ qcom,camcc = <&clock_camcc>; qcom,dispcc = <&clock_dispcc>; qcom,gpucc = <&clock_gpucc>; + qcom,cpucc = <&cpucc_debug>; clock-names = "xo_clk_src"; clocks = <&clock_rpmh RPMH_CXO_CLK>; #clock-cells = <1>; }; clock_aop: qcom,aopclk { - compatible = "qcom,aop-qmp-clk"; + compatible = "qcom,aop-qmp-clk-v1"; #clock-cells = <1>; mboxes = <&qmp_aop 0>; mbox-names = "qdss_clk"; }; + ufs_ice: ufsice@1d90000 { + compatible = "qcom,ice"; + reg = <0x1d90000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_phy_gdsc>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + ufsphy_mem: ufsphy_mem@1d87000 { reg = <0x1d87000 0xda8>; /* PHY regs */ reg-names = "phy_mem"; @@ -1150,17 +1330,18 @@ "ref_aux_clk"; clocks = <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, - <&clock_gcc GCC_UFS_PHY_PHY_AUX_CLK>; + <&clock_gcc GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK>; status = "disabled"; }; - ufshc_mem: ufshc_mem@1d84000 { + ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; reg = <0x1d84000 0x2500>; interrupts = <0 265 0>; phys = <&ufsphy_mem>; phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <2>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ @@ -1175,13 +1356,12 @@ "tx_lane0_sync_clk", "rx_lane0_sync_clk", "rx_lane1_sync_clk"; - /* TODO: add HW CTL clocks when available */ clocks = - <&clock_gcc GCC_UFS_PHY_AXI_CLK>, - <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_PHY_AXI_HW_CTL_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK>, <&clock_gcc GCC_UFS_PHY_AHB_CLK>, - <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, - <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK>, <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, @@ -1197,6 +1377,7 @@ <0 0>, <0 0>; + non-removable; qcom,msm-bus,name = "ufshc_mem"; qcom,msm-bus,num-cases = <22>; qcom,msm-bus,num-paths = <2>; @@ -1231,7 +1412,13 @@ <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */ <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */ - <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RB L2 */ + /* As UFS working in HS G3 RB L2 mode, aggregated + * bandwidth (AB) should take care of providing + * optimum throughput requested. However, as tested, + * in order to scale up CNOC clock, instantaneous + * bindwidth (IB) needs to be given a proper value too. + */ + <123 512 4194304 0>, <1 757 204800 409600>, /* HS G3 RB L2 */ <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ qcom,bus-vector-names = "MIN", @@ -1258,97 +1445,6 @@ status = "disabled"; }; - ufsphy_card: ufsphy_card@1da7000 { - reg = <0x1da7000 0xda8>; /* PHY regs */ - reg-names = "phy_mem"; - #phy-cells = <0>; - - lanes-per-direction = <1>; - - clock-names = "ref_clk_src", - "ref_clk", - "ref_aux_clk"; - clocks = <&clock_rpmh RPMH_CXO_CLK>, - <&clock_gcc GCC_UFS_CARD_CLKREF_CLK>, - <&clock_gcc GCC_UFS_CARD_PHY_AUX_CLK>; - - status = "disabled"; - }; - - ufshc_card: ufshc_card@1da4000 { - compatible = "qcom,ufshc"; - reg = <0x1da4000 0x2500>; - interrupts = <0 125 0>; - phys = <&ufsphy_card>; - phy-names = "ufsphy"; - - lanes-per-direction = <1>; - dev-ref-clk-freq = <0>; /* 19.2 MHz */ - - 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"; - /* TODO: add HW CTL clocks when available */ - clocks = - <&clock_gcc GCC_UFS_CARD_AXI_CLK>, - <&clock_gcc GCC_AGGRE_UFS_CARD_AXI_CLK>, - <&clock_gcc GCC_UFS_CARD_AHB_CLK>, - <&clock_gcc GCC_UFS_CARD_UNIPRO_CORE_CLK>, - <&clock_gcc GCC_UFS_CARD_ICE_CORE_CLK>, - <&clock_rpmh RPMH_CXO_CLK>, - <&clock_gcc GCC_UFS_CARD_TX_SYMBOL_0_CLK>, - <&clock_gcc GCC_UFS_CARD_RX_SYMBOL_0_CLK>; - freq-table-hz = - <50000000 200000000>, - <0 0>, - <0 0>, - <37500000 150000000>, - <75000000 300000000>, - <0 0>, - <0 0>, - <0 0>; - - qcom,msm-bus,name = "ufshc_card"; - qcom,msm-bus,num-cases = <9>; - qcom,msm-bus,num-paths = <2>; - qcom,msm-bus,vectors-KBps = - <122 512 0 0>, <1 756 0 0>, /* No vote */ - <122 512 922 0>, <1 756 1000 0>, /* PWM G1 */ - <122 512 127796 0>, <1 756 1000 0>, /* HS G1 RA */ - <122 512 255591 0>, <1 756 1000 0>, /* HS G2 RA */ - <122 512 2097152 0>, <1 756 102400 0>, /* HS G3 RA */ - <122 512 149422 0>, <1 756 1000 0>, /* HS G1 RB */ - <122 512 298189 0>, <1 756 1000 0>, /* HS G2 RB */ - <122 512 2097152 0>, <1 756 102400 0>, /* HS G3 RB */ - <122 512 7643136 0>, <1 756 307200 0>; /* Max. bandwidth */ - qcom,bus-vector-names = "MIN", - "PWM_G1_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"; - - /* PM QoS */ - qcom,pm-qos-cpu-groups = <0x0f 0xf0>; - qcom,pm-qos-cpu-group-latency-us = <70 70>; - qcom,pm-qos-default-cpu = <0>; - - /* - * Note: this instance doesn't have control over UFS device - * reset - */ - - resets = <&clock_gcc GCC_UFS_CARD_BCR>; - reset-names = "core_reset"; - - status = "disabled"; - }; - sdhc_2: sdhci@8804000 { compatible = "qcom,sdhci-msm-v5"; reg = <0x8804000 0x1000>; @@ -1388,15 +1484,28 @@ <81 512 1338562 4096000>, <1 608 1338562 4096000>; qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 - 100000000 200000000 4294967295>; + 100750000 200000000 4294967295>; qcom,sdr104-wa; - qcom,devfreq,freq-table = <50000000 200000000>; + qcom,restore-after-cx-collapse; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 201500000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 201500000>; clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, <&clock_gcc GCC_SDCC2_APPS_CLK>; clock-names = "iface_clk", "core_clk"; + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <70 70>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <70 70>, <70 70>; + status = "disabled"; }; @@ -1407,9 +1516,12 @@ <0x1f65000 0x008>, <0x1f64000 0x008>, <0x4180000 0x020>, - <0xc2b0000 0x004>; + <0xc2b0000 0x004>, + <0xb2e0100 0x004>, + <0x4180044 0x004>; reg-names = "qdsp6_base", "halt_q6", "halt_modem", - "halt_nc", "rmb_base", "restart_reg"; + "halt_nc", "rmb_base", "restart_reg", + "pdc_sync", "alt_reset"; clocks = <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GCC_MSS_CFG_AHB_CLK>, @@ -1432,12 +1544,16 @@ vdd_cx-voltage = ; vdd_mx-supply = <&pm8998_s6_level>; vdd_mx-uV = ; + vdd_mss-supply = <&pm8005_s2_level>; + vdd_mss-uV = ; qcom,firmware-name = "modem"; qcom,pil-self-auth; qcom,sysmon-id = <0>; qcom,ssctl-instance-id = <0x12>; qcom,override-acc; + qcom,signal-aop; qcom,qdsp6v65-1-0; + qcom,mss_pdc_offset = <8>; status = "ok"; memory-region = <&pil_modem_mem>; qcom,mem-protect-id = <0xF>; @@ -1451,6 +1567,9 @@ /* GPIO output to mss */ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "mss-pil"; qcom,mba-mem@0 { compatible = "qcom,pil-mba-mem"; memory-region = <&pil_mba_mem>; @@ -1477,6 +1596,7 @@ status = "ok"; qcom,ssctl-instance-id = <0x14>; qcom,firmware-name = "adsp"; + qcom,signal-aop; memory-region = <&pil_adsp_mem>; /* GPIO inputs from lpass */ @@ -1487,17 +1607,21 @@ /* GPIO output to lpass */ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; }; qcom,ssc@5c00000 { compatible = "qcom,pil-tz-generic"; reg = <0x5c00000 0x4000>; - interrupts = <0 377 1>; + interrupts = <0 494 1>; vdd_cx-supply = <&pm8998_l27_level>; - vdd_px-supply = <&pm8998_lvs2>; qcom,vdd_cx-uV-uA = ; - qcom,proxy-reg-names = "vdd_cx", "vdd_px"; + vdd_mx-supply = <&pm8998_l4_level>; + qcom,vdd_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx", "vdd_mx"; qcom,keep-proxy-regs-on; clocks = <&clock_rpmh RPMH_CXO_CLK>; @@ -1509,6 +1633,7 @@ qcom,smem-id = <424>; qcom,sysmon-id = <3>; qcom,ssctl-instance-id = <0x16>; + qcom,signal-aop; qcom,firmware-name = "slpi"; status = "ok"; memory-region = <&pil_slpi_mem>; @@ -1521,6 +1646,9 @@ /* GPIO output to ssc */ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_3_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "slpi-pil"; }; slim_aud: slim@171c0000 { @@ -1533,9 +1661,19 @@ interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,apps-ch-pipes = <0x780000>; qcom,ea-pc = <0x270>; + qcom,iommu-s1-bypass; + + iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1806 0x0>, + <&apps_smmu 0x180d 0x0>, + <&apps_smmu 0x180e 0x1>, + <&apps_smmu 0x1810 0x1>; + }; }; slim_qca: slim@17240000 { + status = "ok"; cell-index = <3>; compatible = "qcom,slim-ngd"; reg = <0x17240000 0x2c000>, @@ -1543,6 +1681,20 @@ reg-names = "slimbus_physical", "slimbus_bam_physical"; interrupts = <0 291 0>, <0 292 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,iommu-s1-bypass; + + iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1813 0x0>; + }; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; }; eud: qcom,msm-eud@88e0000 { @@ -1551,6 +1703,9 @@ interrupts = ; reg = <0x88e0000 0x2000>; reg-names = "eud_base"; + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "cfg_ahb_clk"; + vdda33-supply = <&pm8998_l24>; status = "ok"; }; @@ -1579,9 +1734,13 @@ qcom,pas-id = <14>; qcom,proxy-timeout-ms = <10000>; + qcom,signal-aop; qcom,firmware-name = "spss"; memory-region = <&pil_spss_mem>; qcom,spss-scsr-bits = <24 25>; + + mboxes = <&qmp_aop 0>; + mbox-names = "spss-pil"; }; wdog: qcom,wdt@17980000{ @@ -1590,7 +1749,7 @@ reg-names = "wdt-base"; interrupts = <0 0 0>, <0 1 0>; qcom,bark-time = <11000>; - qcom,pet-time = <10000>; + qcom,pet-time = <9360>; qcom,ipi-ping; qcom,wakeup-enable; }; @@ -1614,6 +1773,7 @@ qcom,sysmon-id = <7>; qcom,ssctl-instance-id = <0x17>; qcom,firmware-name = "cdsp"; + qcom,signal-aop; memory-region = <&pil_cdsp_mem>; /* GPIO inputs from turing */ @@ -1625,6 +1785,9 @@ /* GPIO output to turing*/ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>; status = "ok"; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; }; qcom,msm-rtb { @@ -1650,80 +1813,81 @@ qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-compute"; + qcom,rpc-latency-us = <611>; qcom,msm_fastrpc_compute_cb1 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1401>, - <&apps_smmu 0x1421>; + iommus = <&apps_smmu 0x1401 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb2 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1402>, - <&apps_smmu 0x1422>; + iommus = <&apps_smmu 0x1402 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb3 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1403>, - <&apps_smmu 0x1423>; + iommus = <&apps_smmu 0x1403 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb4 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1404>, - <&apps_smmu 0x1424>; + iommus = <&apps_smmu 0x1404 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb5 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1405>, - <&apps_smmu 0x1425>; + iommus = <&apps_smmu 0x1405 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb6 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1406>, - <&apps_smmu 0x1426>; + iommus = <&apps_smmu 0x1406 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb7 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1407>, - <&apps_smmu 0x1427>; + iommus = <&apps_smmu 0x1407 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb8 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1408>, - <&apps_smmu 0x1428>; + iommus = <&apps_smmu 0x1408 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb9 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; qcom,secure-context-bank; - iommus = <&apps_smmu 0x1409>, - <&apps_smmu 0x1419>, - <&apps_smmu 0x1429>; + iommus = <&apps_smmu 0x1409 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb10 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; qcom,secure-context-bank; - iommus = <&apps_smmu 0x140A>, - <&apps_smmu 0x141A>, - <&apps_smmu 0x142A>; + iommus = <&apps_smmu 0x140A 0x30>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb11 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "adsprpc-smd"; - iommus = <&apps_smmu 0x1823>; + iommus = <&apps_smmu 0x1823 0x0>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb12 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "adsprpc-smd"; - iommus = <&apps_smmu 0x1824>; + iommus = <&apps_smmu 0x1824 0x0>; + dma-coherent; }; }; @@ -1758,6 +1922,11 @@ compatible = "qcom,msm-imem-kaslr_offset"; reg = <0x6d0 12>; }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; }; qcom,venus@aae0000 { @@ -1786,6 +1955,12 @@ status = "ok"; }; + ssc_sensors: qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + status = "ok"; + qcom,firmware-name = "slpi"; + }; + cpuss_dump { compatible = "qcom,cpuss-dump"; qcom,l1_i_cache0 { @@ -1854,19 +2029,51 @@ }; qcom,llcc1_d_cache { qcom,dump-node = <&LLCC_1>; - qcom,dump-id = <0x121>; + qcom,dump-id = <0x140>; }; qcom,llcc2_d_cache { qcom,dump-node = <&LLCC_2>; - qcom,dump-id = <0x122>; + qcom,dump-id = <0x141>; }; qcom,llcc3_d_cache { qcom,dump-node = <&LLCC_3>; - qcom,dump-id = <0x123>; + qcom,dump-id = <0x142>; }; qcom,llcc4_d_cache { qcom,dump-node = <&LLCC_4>; - qcom,dump-id = <0x124>; + qcom,dump-id = <0x143>; + }; + qcom,l1_tlb_dump0 { + qcom,dump-node = <&L1_TLB_0>; + qcom,dump-id = <0x20>; + }; + qcom,l1_tlb_dump100 { + qcom,dump-node = <&L1_TLB_100>; + qcom,dump-id = <0x21>; + }; + qcom,l1_tlb_dump200 { + qcom,dump-node = <&L1_TLB_200>; + qcom,dump-id = <0x22>; + }; + qcom,l1_tlb_dump300 { + qcom,dump-node = <&L1_TLB_300>; + qcom,dump-id = <0x23>; + }; + qcom,l1_tlb_dump400 { + qcom,dump-node = <&L1_TLB_400>; + qcom,dump-id = <0x24>; + }; + qcom,l1_tlb_dump500 { + qcom,dump-node = <&L1_TLB_500>; + qcom,dump-id = <0x25>; + }; + qcom,l1_tlb_dump600 { + qcom,dump-node = <&L1_TLB_600>; + qcom,dump-id = <0x26>; + }; + qcom,l1_tlb_dump700 { + qcom,dump-node = <&L1_TLB_700>; + qcom,dump-id = <0x27>; }; }; @@ -1894,7 +2101,10 @@ compatible = "qcom,sdm845-llcc"; #cache-cells = <1>; max-slices = <32>; - qcom,dump-size = <0x3c0000>; + }; + + qcom,llcc-perfmon { + compatible = "qcom,llcc-perfmon"; }; qcom,llcc-erp { @@ -1908,19 +2118,19 @@ }; LLCC_1: llcc_1_dcache { - qcom,dump-size = <0xd8000>; + qcom,dump-size = <0x1141c0>; }; LLCC_2: llcc_2_dcache { - qcom,dump-size = <0xd8000>; + qcom,dump-size = <0x1141c0>; }; LLCC_3: llcc_3_dcache { - qcom,dump-size = <0xd8000>; + qcom,dump-size = <0x1141c0>; }; LLCC_4: llcc_4_dcache { - qcom,dump-size = <0xd8000>; + qcom,dump-size = <0x1141c0>; }; }; @@ -1956,7 +2166,7 @@ qcom,rx-ring-size = <0x400>; }; - qmp_aop: mailbox@1799000c { + qmp_aop: qcom,qmp-aop@c300000 { compatible = "qcom,qmp-mbox"; label = "aop"; reg = <0xc300000 0x100000>, @@ -1964,6 +2174,7 @@ reg-names = "msgram", "irq-reg-base"; qcom,irq-mask = <0x1>; interrupts = <0 389 1>; + priority = <0>; mbox-desc-offset = <0x0>; #mbox-cells = <1>; }; @@ -2017,6 +2228,19 @@ qcom,irq-mask = <0x100>; interrupts = ; label = "lpass"; + cpu-affinity = <1 2>; + qcom,qos-config = <&glink_qos_adsp>; + qcom,ramp-time = <0xaf>; + }; + + glink_qos_adsp: qcom,glink-qos-config-adsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x3c 0x0>, + <0x3c 0x0>, + <0x3c 0x0>, + <0x3c 0x0>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; }; qcom,glink-smem-native-xprt-dsps@86000000 { @@ -2029,10 +2253,39 @@ label = "dsps"; }; - qcom,glink-smem-native-xprt-cdsp@86000000 { - compatible = "qcom,glink-smem-native-xprt"; - reg = <0x86000000 0x200000>, - <0x1799000c 0x4>; + glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp { + compatible = "qcom,glink-spi-xprt"; + label = "wdsp"; + qcom,remote-fifo-config = <&glink_fifo_wdsp>; + qcom,qos-config = <&glink_qos_wdsp>; + qcom,ramp-time = <0x10>, + <0x20>, + <0x30>, + <0x40>; + }; + + glink_fifo_wdsp: qcom,glink-fifo-config-wdsp { + compatible = "qcom,glink-fifo-config"; + qcom,out-read-idx-reg = <0x12000>; + qcom,out-write-idx-reg = <0x12004>; + qcom,in-read-idx-reg = <0x1200C>; + qcom,in-write-idx-reg = <0x12010>; + }; + + glink_qos_wdsp: qcom,glink-qos-config-wdsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x80 0x0>, + <0x70 0x1>, + <0x60 0x2>, + <0x50 0x3>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + + qcom,glink-smem-native-xprt-cdsp@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; reg-names = "smem", "irq-reg-base"; qcom,irq-mask = <0x10>; interrupts = ; @@ -2115,6 +2368,7 @@ qcom,xprt-linkid = <1>; qcom,xprt-version = <1>; qcom,fragmented-data; + qcom,dynamic-wakeup-source; }; qcom,ipc_router_cdsp_xprt { @@ -2127,6 +2381,18 @@ qcom,fragmented-data; }; + qcom,qsee_ipc_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,rx-irq-clr = <0x1888008 0x4>; + qcom,rx-irq-clr-mask = <0x1>; + qcom,dev-name = "qsee_ipc_irq_spss"; + interrupts = <0 349 4>; + label = "spss"; + }; + }; + qcom,spcom { compatible = "qcom,spcom"; @@ -2214,6 +2480,14 @@ qcom,pipe-attr-ee; }; + qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clock-frequency = <25000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&pm8998_gpios 5 0>; + }; + qcom_seecom: qseecom@86d00000 { compatible = "qcom,qseecom"; reg = <0x86d00000 0x2200000>; @@ -2224,6 +2498,7 @@ qcom,disk-encrypt-pipe-pair = <2>; qcom,support-fde; qcom,no-clock-support; + qcom,fde-key-size; qcom,msm-bus,name = "qseecom-noc"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <1>; @@ -2252,7 +2527,7 @@ qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <1 618 0 0>, /* No vote */ - <1 618 0 800>; /* 100 KHz */ + <1 618 0 300000>; /* 75 MHz */ clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; clock-names = "iface_clk"; }; @@ -2265,6 +2540,77 @@ hyplog-size-offset = <0x414>; }; + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,request-bw-before-clk; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x706 0x1>, + <&apps_smmu 0x716 0x1>; + }; + + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,request-bw-before-clk; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x704 0x1>, + <&apps_smmu 0x714 0x1>; + }; + qcom,msm_gsi { compatible = "qcom,msm_gsi"; }; @@ -2274,6 +2620,7 @@ reg = <0x0 0x200000>; reg-names = "rmtfs"; qcom,client-id = <0x00000001>; + qcom,guard-memory; }; qcom,rmnet-ipa { @@ -2301,10 +2648,10 @@ qcom,ipa-wdi2; qcom,use-64-bit-dma-mask; qcom,arm-smmu; - qcom,smmu-s1-bypass; + qcom,smmu-fast-map; qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; - qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-cases = <5>; qcom,msm-bus,num-paths = <4>; qcom,msm-bus,vectors-KBps = /* No vote */ @@ -2312,22 +2659,28 @@ <90 585 0 0>, <1 676 0 0>, <143 777 0 0>, + /* SVS2 */ + <90 512 80000 600000>, + <90 585 80000 350000>, + <1 676 40000 40000>, /*gcc_config_noc_clk_src */ + <143 777 0 75>, /* IB defined for IPA2X_clk in MHz*/ /* SVS */ <90 512 80000 640000>, <90 585 80000 640000>, <1 676 80000 80000>, - <143 777 0 150000000>, + <143 777 0 150>, /* IB defined for IPA2X_clk in MHz*/ /* NOMINAL */ <90 512 206000 960000>, <90 585 206000 960000>, <1 676 206000 160000>, - <143 777 0 300000000>, + <143 777 0 300>, /* IB defined for IPA2X_clk in MHz*/ /* TURBO */ <90 512 206000 3600000>, <90 585 206000 3600000>, <1 676 206000 300000>, - <143 777 0 355333333>; - qcom,bus-vector-names = "MIN", "SVS", "NOMINAL", "TURBO"; + <143 777 0 355>; /* IB defined for IPA clk in MHz*/ + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; /* IPA RAM mmap */ qcom,ipa-ram-mmap = < @@ -2418,18 +2771,24 @@ ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; - iommus = <&apps_smmu 0x720>; + iommus = <&apps_smmu 0x720 0x0>; qcom,iova-mapping = <0x20000000 0x40000000>; + qcom,additional-mapping = + /* modem tables in IMEM */ + <0x146BD000 0x146BD000 0x2000>; }; ipa_smmu_wlan: ipa_smmu_wlan { compatible = "qcom,ipa-smmu-wlan-cb"; - iommus = <&apps_smmu 0x721>; + iommus = <&apps_smmu 0x721 0x0>; + qcom,additional-mapping = + /* ipa-uc ram */ + <0x1E60000 0x1E60000 0x80000>; }; ipa_smmu_uc: ipa_smmu_uc { compatible = "qcom,ipa-smmu-uc-cb"; - iommus = <&apps_smmu 0x722>; + iommus = <&apps_smmu 0x722 0x0>; qcom,iova-mapping = <0x40000000 0x20000000>; }; }; @@ -2438,6 +2797,8 @@ compatible = "qcom,pil-tz-generic"; qcom,pas-id = <0xf>; qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; }; qcom,chd_sliver { @@ -2473,7 +2834,7 @@ cmd_db: qcom,cmd-db@861e0000 { compatible = "qcom,cmd-db"; - reg = <0x861e0000 0x4000>; + reg = <0xc3f000c 8>; }; dcc: dcc_v2@10a2000 { @@ -2483,6 +2844,214 @@ reg-names = "dcc-base", "dcc-ram-base"; dcc-ram-offset = <0x6000>; + + qcom,curr-link-list = <2>; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; qcom,msm-core@780000 { @@ -2496,8 +3065,7 @@ <0xa0000000 0x10000000>, <0xb0000000 0x10000>; reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; - iommus = <&apps_smmu 0x0040>, - <&apps_smmu 0x0041>; + iommus = <&apps_smmu 0x0040 0x1>; interrupts = <0 414 0 /* CE0 */ >, <0 415 0 /* CE1 */ >, <0 416 0 /* CE2 */ >, @@ -2511,213 +3079,281 @@ <0 424 0 /* CE10 */ >, <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; + qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; + + vdd-0.8-cx-mx-supply = <&pm8998_l5>; + vdd-1.8-xo-supply = <&pm8998_l7>; + vdd-1.3-rfa-supply = <&pm8998_l17>; + vdd-3.3-ch0-supply = <&pm8998_l25>; + qcom,vdd-0.8-cx-mx-config = <800000 800000>; + qcom,vdd-3.3-ch0-config = <3104000 3312000>; + }; + + qmi-tmd-devices { + compatible = "qcom,qmi_cooling_devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + slpi { + qcom,instance-id = <0x53>; + + slpi_vdd: slpi_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; }; thermal_zones: thermal-zones { - aoss0-ts0-h { + aoss0-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "user_space"; thermal-sensors = <&tsens0 0>; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu0-silver-ts0-h { + cpu0-silver-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "user_space"; thermal-sensors = <&tsens0 1>; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu1-silver-ts0-h { + cpu1-silver-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "user_space"; thermal-sensors = <&tsens0 2>; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu2-silver-ts0-h { + cpu2-silver-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "user_space"; thermal-sensors = <&tsens0 3>; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu3-silver-ts0-h { + cpu3-silver-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 4>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - kryo-l3-0-ts0-h { + kryo-l3-0-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 5>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - kryo-l3-1-ts0-h { + kryo-l3-1-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 6>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu0-gold-ts0-h { + cpu0-gold-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 7>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu1-gold-ts0-h { + cpu1-gold-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 8>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu2-gold-ts0-h { + cpu2-gold-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 9>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - cpu3-gold-ts0-h { + cpu3-gold-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 10>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - gpu0-ts0-h { + gpu0-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens0 11>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - gpu1-ts0-h { + gpu1-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-governor = "user_space"; thermal-sensors = <&tsens0 12>; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - aoss1-ts1-h { + aoss1-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 0>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - mdm-dsp-ts1-h { + mdm-dsp-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 1>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; @@ -2726,133 +3362,137 @@ - ddr-ts1-h { + ddr-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 2>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - wlan-ts1-h { + wlan-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 3>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - compute-hvx-ts1-h { + compute-hvx-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 4>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - camera-ts1-h { + camera-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 5>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - mmss-ts1-h { + mmss-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 6>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - mdm-core-ts1-h { + mdm-core-usr { polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&tsens1 7>; thermal-governor = "user_space"; trips { active-config0 { - temperature = <65000>; + temperature = <125000>; hysteresis = <1000>; type = "passive"; }; }; }; - gpu0 { + gpu-virt-max-step { polling-delay-passive = <10>; - polling-delay = <0>; - thermal-sensors = <&tsens0 11>; + polling-delay = <100>; thermal-governor = "step_wise"; trips { - gpu0_trip: gpu0-trip { + gpu_trip0: gpu-trip0 { temperature = <95000>; hysteresis = <0>; type = "passive"; }; }; cooling-maps { - gpu0_cdev { - trip = <&gpu0_trip>; + gpu_cdev0 { + trip = <&gpu_trip0>; cooling-device = - <&msm_gpu 1 THERMAL_NO_LIMIT>; + <&msm_gpu 0 THERMAL_NO_LIMIT>; }; }; }; - gpu1 { - polling-delay-passive = <10>; + silv-virt-max-step { + polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&tsens0 12>; thermal-governor = "step_wise"; trips { - gpu1_trip: gpu1-trip { - temperature = <95000>; + silver-trip { + temperature = <120000>; hysteresis = <0>; type = "passive"; }; }; - cooling-maps { - gpu1_cdev { - trip = <&gpu1_trip>; - cooling-device = - <&msm_gpu 1 THERMAL_NO_LIMIT>; + }; + + gold-virt-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + trips { + gold-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; }; }; }; - pop-mem { + pop-mem-step { polling-delay-passive = <10>; polling-delay = <0>; thermal-sensors = <&tsens1 2>; @@ -2865,691 +3505,455 @@ }; }; cooling-maps { - pop_cdev { + pop_cdev4 { trip = <&pop_trip>; cooling-device = - <&CPU4 1 THERMAL_NO_LIMIT>; - }; - }; - }; - - aoss0-ts0-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 0>; - tracks-low; - trips { - aoss0_trip: aoss0-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; + <&CPU4 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&CPU0 12 12>; + pop_cdev5 { + trip = <&pop_trip>; + cooling-device = + <&CPU5 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; }; - cpu4_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&CPU4 12 12>; + pop_cdev6 { + trip = <&pop_trip>; + cooling-device = + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; }; - gpu_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&msm_gpu 4 4>; + pop_cdev7 { + trip = <&pop_trip>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; }; }; }; - cpu0-silver-ts0-l { - polling-delay-passive = <0>; + cpu0-silver-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; thermal-sensors = <&tsens0 1>; - tracks-low; + thermal-governor = "step_wise"; trips { - cpu0_trip: cpu0-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config0: emerg-config0 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&cpu0_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpu0_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpu0_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev0 { + trip = <&emerg_config0>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - cpu1-silver-ts0-l { - polling-delay-passive = <0>; + cpu1-silver-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; thermal-sensors = <&tsens0 2>; - tracks-low; + thermal-governor = "step_wise"; trips { - cpu1_trip: cpu1-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config1: emerg-config1 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&cpu1_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpu1_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpu1_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev1 { + trip = <&emerg_config1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - cpu2-silver-ts0-l { - polling-delay-passive = <0>; + cpu2-silver-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; thermal-sensors = <&tsens0 3>; - tracks-low; + thermal-governor = "step_wise"; trips { - cpu2_trip: cpu2-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config2: emerg-config2 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&cpu2_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpu2_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpu2_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev2 { + trip = <&emerg_config2>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - cpu3-silver-ts0-l { - polling-delay-passive = <0>; + cpu3-silver-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; thermal-sensors = <&tsens0 4>; - tracks-low; + thermal-governor = "step_wise"; trips { - cpu3_trip: cpu3-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config3: emerg-config3 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&cpu3_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpu3_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpu3_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev3 { + trip = <&emerg_config3>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - kryo-l3-0-ts0-l { - polling-delay-passive = <0>; + cpu0-gold-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 5>; - tracks-low; + thermal-sensors = <&tsens0 7>; + thermal-governor = "step_wise"; trips { - l3_0_trip: l3-0-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config4: emerg-config4 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&l3_0_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&l3_0_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&l3_0_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev4 { + trip = <&emerg_config4>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - kryo-l3-1-ts0-l { - polling-delay-passive = <0>; + cpu1-gold-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 6>; - tracks-low; + thermal-sensors = <&tsens0 8>; + thermal-governor = "step_wise"; trips { - l3_1_trip: l3-1-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config5: emerg-config5 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&l3_1_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&l3_1_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&l3_1_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev5 { + trip = <&emerg_config5>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - cpu0-gold-ts0-l { - polling-delay-passive = <0>; + cpu2-gold-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 7>; - tracks-low; + thermal-sensors = <&tsens0 9>; + thermal-governor = "step_wise"; trips { - cpug0_trip: cpug0-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config6: emerg-config6 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&cpug0_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpug0_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpug0_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev6 { + trip = <&emerg_config6>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - cpu1-gold-ts0-l { - polling-delay-passive = <0>; + cpu3-gold-step { + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 8>; - tracks-low; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; trips { - cpug1_trip: cpug1-trip { - temperature = <5000>; - hysteresis = <5000>; + emerg_config7: emerg-config7 { + temperature = <110000>; + hysteresis = <10000>; type = "passive"; }; }; cooling-maps { - cpu0_vdd_cdev { - trip = <&cpug1_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpug1_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpug1_trip>; - cooling-device = <&msm_gpu 4 4>; + emerg_cdev7 { + trip = <&emerg_config7>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; }; }; }; - cpu2-gold-ts0-l { + lmh-dcvs-01 { polling-delay-passive = <0>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 9>; - tracks-low; + thermal-governor = "user_space"; + thermal-sensors = <&lmh_dcvs1>; + trips { - cpug2_trip: cpug2-trip { - temperature = <5000>; - hysteresis = <5000>; + active-config { + temperature = <95000>; + hysteresis = <30000>; type = "passive"; }; }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&cpug2_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpug2_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpug2_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; }; - cpu3-gold-ts0-l { + lmh-dcvs-00 { polling-delay-passive = <0>; polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 9>; - tracks-low; + thermal-governor = "user_space"; + thermal-sensors = <&lmh_dcvs0>; + trips { - cpug3_trip: cpug3-trip { - temperature = <5000>; - hysteresis = <5000>; + active-config { + temperature = <95000>; + hysteresis = <30000>; type = "passive"; }; }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&cpug3_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&cpug3_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&cpug3_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; }; - gpu0-ts0-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 10>; - tracks-low; - trips { - gpu0_trip_l: gpu0-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&gpu0_trip_l>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&gpu0_trip_l>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&gpu0_trip_l>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + }; + + tsens0: tsens@c222000 { + compatible = "qcom,sdm845-tsens"; + reg = <0xc222000 0x4>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 506 0>, <0 508 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: tsens@c223000 { + compatible = "qcom,sdm845-tsens"; + reg = <0xc223000 0x4>, + <0xc265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 507 0>, <0 509 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh_dump { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; }; - gpu1-ts0-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 11>; - tracks-low; - trips { - gpu1_trip_l: gpu1-trip_l { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&gpu1_trip_l>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&gpu1_trip_l>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&gpu1_trip_l>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + fcm_dump { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; }; - aoss1-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 0>; - tracks-low; - trips { - aoss1_trip: aoss1-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + rpm_sw_dump { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; }; - mdm-dsp-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 1>; - tracks-low; - trips { - dsp_trip: dsp-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&dsp_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&dsp_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&dsp_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + pmic_dump { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xe4>; }; - ddr-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 2>; - tracks-low; - trips { - ddr_trip: ddr-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; - }; - - wlan-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 3>; - tracks-low; - trips { - wlan_trip: wlan-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&wlan_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&wlan_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&wlan_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + tmc_etf_dump { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf0>; }; - compute-hvx-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 4>; - tracks-low; - trips { - hvx_trip: hvx-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&hvx_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&hvx_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&hvx_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + tmc_etf_swao_dump { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xf1>; }; - camera-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 5>; - tracks-low; - trips { - camera_trip: camera-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + tmc_etr_reg_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; }; - mmss-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 6>; - tracks-low; - trips { - mmss_trip: mmss-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&mmss_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&mmss_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&mmss_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + tmc_etf_reg_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x101>; }; - mdm-core-ts1-l { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 7>; - tracks-low; - trips { - mdm_trip: mdm-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_vdd_cdev { - trip = <&mdm_trip>; - cooling-device = <&CPU0 12 12>; - }; - cpu4_vdd_cdev { - trip = <&mdm_trip>; - cooling-device = <&CPU4 12 12>; - }; - gpu_vdd_cdev { - trip = <&mdm_trip>; - cooling-device = <&msm_gpu 4 4>; - }; - }; + tmc_etf_swao_reg_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; }; - lmh-dcvs-01 { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "user_space"; - thermal-sensors = <&lmh_dcvs1>; - - trips { - active-config { - temperature = <95000>; - hysteresis = <30000>; - type = "passive"; - }; - }; + misc_data_dump { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; }; - lmh-dcvs-00 { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "user_space"; - thermal-sensors = <&lmh_dcvs0>; - - trips { - active-config { - temperature = <95000>; - hysteresis = <30000>; - type = "passive"; - }; - }; + tpdm_swao_dump { + qcom,dump-size = <0x512>; + qcom,dump-id = <0xf2>; }; + }; + gpi_dma0: qcom,gpi-dma@0x800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, + <0 252 0>, <0 253 0>, <0 254 0>, <0 255 0>, + <0 256 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x0016 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; }; - tsens0: tsens@c222000 { - compatible = "qcom,sdm845-tsens"; - reg = <0xc222000 0x4>, - <0xc263000 0x1ff>; - reg-names = "tsens_srot_physical", - "tsens_tm_physical"; - interrupts = <0 506 0>, <0 508 0>; - interrupt-names = "tsens-upper-lower", "tsens-critical"; - #thermal-sensor-cells = <1>; + gpi_dma1: qcom,gpi-dma@0xa00000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0xa00000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 279 0>, <0 280 0>, <0 281 0>, <0 282 0>, + <0 283 0>, <0 284 0>, <0 293 0>, <0 294 0>, + <0 295 0>, <0 296 0>, <0 297 0>, <0 298 0>, + <0 299 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x06d6 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; }; - tsens1: tsens@c223000 { - compatible = "qcom,sdm845-tsens"; - reg = <0xc223000 0x4>, - <0xc265000 0x1ff>; - reg-names = "tsens_srot_physical", - "tsens_tm_physical"; - interrupts = <0 507 0>, <0 509 0>; - interrupt-names = "tsens-upper-lower", "tsens-critical"; - #thermal-sensor-cells = <1>; + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x20 0x0f>; }; }; &clock_cpucc { lmh_dcvs0: qcom,limits-dcvs@0 { compatible = "qcom,msm-hw-limits"; - interrupts = ; + interrupts = ; qcom,affinity = <0>; #thermal-sensor-cells = <0>; }; lmh_dcvs1: qcom,limits-dcvs@1 { compatible = "qcom,msm-hw-limits"; - interrupts = ; + interrupts = ; qcom,affinity = <1>; #thermal-sensor-cells = <0>; + isens_vref-supply = <&pm8998_l1_ao>; + isens-vref-settings = <880000 880000 20000>; + }; + + wil6210: qcom,wil6210 { + compatible = "qcom,wil6210"; + qcom,pcie-parent = <&pcie0>; + qcom,wigig-en = <&tlmm 39 0>; + qcom,msm-bus,name = "wil6210"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 600000 800000>; /* ~4.6Gbps (MCS12) */ + qcom,use-ext-supply; + vdd-supply= <&pm8998_s7>; + vddio-supply= <&pm8998_s5>; + qcom,use-ext-clocks; + clocks = <&clock_rpmh RPMH_RF_CLK3>, + <&clock_rpmh RPMH_RF_CLK3_A>; + clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; + qcom,smmu-support; + qcom,smmu-mapping = <0x20000000 0xe0000000>; + qcom,smmu-s1-en; + qcom,smmu-fast-map; + qcom,smmu-coherent; + qcom,keep-radio-on-during-sleep; + status = "disabled"; }; }; @@ -3606,6 +4010,7 @@ }; &bps_gdsc { + qcom,support-hw-trigger; status = "ok"; }; @@ -3618,10 +4023,12 @@ }; &ipe_0_gdsc { + qcom,support-hw-trigger; status = "ok"; }; &ipe_1_gdsc { + qcom,support-hw-trigger; status = "ok"; }; @@ -3646,10 +4053,12 @@ }; &vcodec0_gdsc { + qcom,support-hw-trigger; status = "ok"; }; &vcodec1_gdsc { + qcom,support-hw-trigger; status = "ok"; }; @@ -3658,7 +4067,6 @@ }; #include "pm8998.dtsi" -#include "pmi8998.dtsi" #include "pm8005.dtsi" #include "sdm845-regulator.dtsi" #include "sdm845-coresight.dtsi" @@ -3670,6 +4078,1294 @@ #include "sdm845-vidc.dtsi" #include "sdm845-pm.dtsi" #include "sdm845-pinctrl.dtsi" +#include "sdm845-pcie.dtsi" #include "sdm845-audio.dtsi" #include "sdm845-gpu.dtsi" -#include "sdm845-usb.dtsi" +#include "sdm845-670-usb-common.dtsi" + +&pm8998_temp_alarm { + cooling-maps { + trip0_cpu0 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu1 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU1 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu2 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU2 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu3 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU3 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu4 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu5 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU5 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu6 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu7 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU7 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip1_cpu1 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu2 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu3 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu4 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu5 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu6 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu7 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + }; +}; + +&thermal_zones { + aoss0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + tracks-low; + trips { + aoss0_trip: aoss0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu0-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 1>; + tracks-low; + trips { + cpu0_trip: cpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu1-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 2>; + tracks-low; + trips { + cpu1_trip: cpu1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu2-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 3>; + tracks-low; + trips { + cpu2_trip: cpu2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu3-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 4>; + tracks-low; + trips { + cpu3_trip: cpu3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + kryo-l3-0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 5>; + tracks-low; + trips { + l3_0_trip: l3-0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + kryo-l3-1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 6>; + tracks-low; + trips { + l3_1_trip: l3-1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu0-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 7>; + tracks-low; + trips { + cpug0_trip: cpug0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu1-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 8>; + tracks-low; + trips { + cpug1_trip: cpug1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu2-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 9>; + tracks-low; + trips { + cpug2_trip: cpug2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu3-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 10>; + tracks-low; + trips { + cpug3_trip: cpug3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + gpu0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 11>; + tracks-low; + trips { + gpu0_trip_l: gpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + gpu1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 12>; + tracks-low; + trips { + gpu1_trip_l: gpu1-trip_l { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + aoss1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 0>; + tracks-low; + trips { + aoss1_trip: aoss1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + mdm-dsp-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 1>; + tracks-low; + trips { + dsp_trip: dsp-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + ddr-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 2>; + tracks-low; + trips { + ddr_trip: ddr-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + wlan-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 3>; + tracks-low; + trips { + wlan_trip: wlan-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + compute-hvx-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 4>; + tracks-low; + trips { + hvx_trip: hvx-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + camera-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 5>; + tracks-low; + trips { + camera_trip: camera-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + mmss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 6>; + tracks-low; + trips { + mmss_trip: mmss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + mdm-core-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 7>; + tracks-low; + trips { + mdm_trip: mdm-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3412b25decaa181f22d61ba27f65cd12a638ba23 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi @@ -0,0 +1,109 @@ +/* Copyright (c) 2016-2017, 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 + +&qupv3_se10_i2c { + smb1355_0: qcom,smb1355@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1355_0"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x12 0x13 0x16>; + + smb1355_revid_0: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb1355_charger_0: qcom,smb1355-charger@1000 { + compatible = "qcom,smb1355"; + qcom,pmic-revid = <&smb1355_revid_0>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb1355_0>; + status = "disabled"; + + io-channels = <&pmi8998_rradc 2>, + <&pmi8998_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; + }; + + smb1355_1: qcom,smb1355@c { + compatible = "qcom,i2c-pmic"; + reg = <0xc>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1355_1"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x12 0x13 0x16>; + + smb1355_revid_1: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb1355_charger_1: qcom,smb1355-charger@1000 { + compatible = "qcom,smb1355"; + qcom,pmic-revid = <&smb1355_revid_1>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb1355_1>; + status = "disabled"; + + io-channels = <&pmi8998_rradc 2>, + <&pmi8998_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi index 8c15040f2540d63ada01a1c5acb62692268687fe..9536f2013bf4682eaac6c8bef9165f32397344e2 100644 --- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi @@ -553,6 +553,7 @@ phy-mode = "rgmii-id"; #address-cells = <1>; #size-cells = <0>; + status = "disabled"; }; can0: can@e6c30000 { diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts index 358089687a69b5946851ef7c5ac5c0a776d9d161..ef1b9e573af0f5bd2ed6792ba5c9450a64ecaa45 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts @@ -27,7 +27,7 @@ stdout-path = "serial0:115200n8"; }; - memory { + memory@0 { device_type = "memory"; reg = <0x0 0x0 0x0 0x40000000>; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 68a908334c7b12846e74c16d5c7168d9276747dd..54dc28351c8cb85a0abbd4bbad554d56dbcbac79 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -72,7 +72,7 @@ <1 10 0xf08>; }; - amba_apu { + amba_apu: amba_apu@0 { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; @@ -175,7 +175,7 @@ }; i2c0: i2c@ff020000 { - compatible = "cdns,i2c-r1p10"; + compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10"; status = "disabled"; interrupt-parent = <&gic>; interrupts = <0 17 4>; @@ -185,7 +185,7 @@ }; i2c1: i2c@ff030000 { - compatible = "cdns,i2c-r1p10"; + compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10"; status = "disabled"; interrupt-parent = <&gic>; interrupts = <0 18 4>; diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..801c66addf0b2b0458489a995ddec24ef7afb037 --- /dev/null +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -0,0 +1,558 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_AIO is not set +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8953=y +CONFIG_ARCH_SDM450=y +CONFIG_ARCH_SDM632=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8953=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_QPNP_PIN_DEBUG=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_TYPEC=y +CONFIG_MSM_APM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_CPR4_APSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_QCOM_KGSL=y +CONFIG_DRM=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=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 +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_TZ_SMMU=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..009c420114425133154c84b17f37063292606eb9 --- /dev/null +++ b/arch/arm64/configs/msm8953_defconfig @@ -0,0 +1,631 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_AIO is not set +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8953=y +CONFIG_ARCH_SDM450=y +CONFIG_ARCH_SDM632=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8953=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_GPIO_QPNP_PIN_DEBUG=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_TYPEC=y +CONFIG_MSM_APM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_CPR4_APSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_QCOM_KGSL=y +CONFIG_DRM=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_SERIAL=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=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 +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_TZ_SMMU=y +CONFIG_TRACER_PKT=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_DCC=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y +CONFIG_MEMTEST=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_ARM64_PTDUMP=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_CORESIGHT=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 +CONFIG_CORESIGHT_DBGUI=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..8aa1e7d58a87dc37f07b66293f276b2abe6a4e70 --- /dev/null +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -0,0 +1,632 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SDM670=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_PROCESS_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_SKY2=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +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_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_DIAG_CHAR=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_SDM670=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_NX30P6093=y +CONFIG_QPNP_FG_GEN3=y +CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_QPNP_SMB2=y +CONFIG_QPNP_QNOVO=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP_OLEDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SPECTRA_CAMERA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y +CONFIG_QCOM_KGSL=y +CONFIG_DRM=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_MSM_11AD=m +CONFIG_SEEMP_CORE=y +CONFIG_QCOM_GENI_SE=y +CONFIG_MSM_GCC_SDM845=y +CONFIG_MSM_VIDEOCC_SDM845=y +CONFIG_MSM_CAMCC_SDM845=y +CONFIG_MSM_DISPCC_SDM845=y +CONFIG_CLOCK_QPNP_DIV=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_GPUCC_SDM845=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SDM670_LLCC=y +CONFIG_QCOM_LLCC_PERFMON=m +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_TRACER_PKT=y +CONFIG_QTI_RPMH_API=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_MSM_QBT1000=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_REMOTEQDSS=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_RRADC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_QCOM_QFPROM=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_PFK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..8022e88d07c32b6a7ae9d2b991efd1ec6e73bf84 --- /dev/null +++ b/arch/arm64/configs/sdm670_defconfig @@ -0,0 +1,698 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_BLK_CGROUP=y +CONFIG_DEBUG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SDM670=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_PROCESS_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +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_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_DIAG_CHAR=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_SDM670=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_NX30P6093=y +CONFIG_QPNP_FG_GEN3=y +CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_QPNP_SMB2=y +CONFIG_QPNP_QNOVO=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP_OLEDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SPECTRA_CAMERA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y +CONFIG_QCOM_KGSL=y +CONFIG_DRM=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_KRYO3XX_ARM64=y +CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_MSM_11AD=m +CONFIG_SEEMP_CORE=y +CONFIG_QCOM_GENI_SE=y +CONFIG_MSM_GCC_SDM845=y +CONFIG_MSM_VIDEOCC_SDM845=y +CONFIG_MSM_CAMCC_SDM845=y +CONFIG_MSM_DISPCC_SDM845=y +CONFIG_CLOCK_QPNP_DIV=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_GPUCC_SDM845=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SDM670_LLCC=y +CONFIG_QCOM_LLCC_PERFMON=m +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_MSM_GLADIATOR_ERP=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_TRACER_PKT=y +CONFIG_QTI_RPMH_API=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_MSM_QBT1000=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_REMOTEQDSS=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_RRADC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_QCOM_QFPROM=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y +CONFIG_MEMTEST=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_ARM64_PTDUMP=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_CORESIGHT=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 +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_TGU=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_PFK=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CRC32_ARM64=y +CONFIG_XZ_DEC=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index 94786be6de179401ea2e26f7d870613a12833799..f7ef61e12002553e06b7f8e5fd81604e5a9d196c 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -7,8 +7,13 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 @@ -17,7 +22,9 @@ CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y +CONFIG_SCHED_CORE_ROTATE=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set @@ -29,13 +36,13 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y -# CONFIG_AIO is not set +CONFIG_BPF_SYSCALL=y # CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -47,8 +54,8 @@ CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_SDM845=y -CONFIG_ARCH_SDM830=y CONFIG_PCI=y +CONFIG_PCI_MSM=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y @@ -57,6 +64,7 @@ CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -77,10 +85,9 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y -CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -127,6 +134,7 @@ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -154,6 +162,7 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y @@ -166,6 +175,7 @@ CONFIG_NF_CONNTRACK_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y @@ -181,6 +191,8 @@ CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_IPTABLES_128=y +CONFIG_IP6_NF_MATCH_RPFILTER=y CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y @@ -199,8 +211,6 @@ CONFIG_NET_SCH_MULTIQ=y CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y CONFIG_NET_EMATCH=y CONFIG_NET_EMATCH_CMP=y CONFIG_NET_EMATCH_NBYTE=y @@ -212,21 +222,25 @@ CONFIG_NET_ACT_GACT=y CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y +CONFIG_NFC_NQ=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y @@ -238,9 +252,13 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -249,17 +267,25 @@ CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y CONFIG_SKY2=y -CONFIG_RNDIS_IPA=y CONFIG_SMSC911X=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y +CONFIG_WIL6210=m +# CONFIG_WIL6210_TRACING is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -277,10 +303,11 @@ CONFIG_SERIAL_MSM_GENI=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_QCOM_GENI=y -CONFIG_SOUNDWIRE=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_QCOM_GENI=y @@ -289,7 +316,6 @@ CONFIG_SLIMBUS_MSM_NGD=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PINCTRL_SDM845=y -CONFIG_PINCTRL_SDM830=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y @@ -298,8 +324,8 @@ CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_FG_GEN3=y +CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_SMB2=y -CONFIG_SMB138X_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y @@ -309,22 +335,28 @@ CONFIG_THERMAL_GOV_STEP_WISE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y CONFIG_CPU_THERMAL=y CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_THERMAL_TSENS=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y -CONFIG_WCD934X_CODEC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_QPNP_LABIBB=y CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -332,10 +364,14 @@ CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SPECTRA_CAMERA=y CONFIG_MSM_VIDC_V4L2=y -CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m +CONFIG_QCOM_KGSL=y CONFIG_DRM=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y @@ -347,13 +383,17 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y -CONFIG_SND_SOC_SDM845=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -369,6 +409,7 @@ CONFIG_USB_ISP1760_HOST_ROLE=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -392,10 +433,12 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y +CONFIG_MMC_TEST=m CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -404,10 +447,18 @@ CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y @@ -418,13 +469,16 @@ CONFIG_ION_MSM=y CONFIG_GSI=y CONFIG_IPA3=y CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_COINCELL=y CONFIG_QPNP_REVID=y CONFIG_USB_BAM=y +CONFIG_MSM_11AD=m CONFIG_SEEMP_CORE=y +CONFIG_QCOM_GENI_SE=y CONFIG_MSM_GCC_SDM845=y CONFIG_MSM_VIDEOCC_SDM845=y CONFIG_MSM_CAMCC_SDM845=y @@ -441,10 +495,14 @@ CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM845_LLCC=y +CONFIG_QCOM_LLCC_PERFMON=m +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_EUD=y CONFIG_QCOM_WATCHDOG_V2=y @@ -463,20 +521,27 @@ CONFIG_MSM_SPSS_UTILS=y CONFIG_TRACER_PKT=y CONFIG_QTI_RPMH_API=y CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_GLINK_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_ICNSS=y CONFIG_QCOM_COMMAND_DB=y -CONFIG_MSM_AVTIMER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y +CONFIG_MSM_QBT1000=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y CONFIG_QCOMCCI_HWMON=y @@ -486,7 +551,6 @@ CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y -CONFIG_EXTCON=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y @@ -495,19 +559,25 @@ CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y @@ -515,7 +585,6 @@ CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y @@ -527,16 +596,24 @@ CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index d4405c4d0087324706c1bc41e62f159deabe8fc8..a4f0ffa901c4281077bc9d5635b91325f8a89a90 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -12,6 +12,8 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 @@ -21,7 +23,9 @@ CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y CONFIG_SCHED_CORE_CTL=y +CONFIG_SCHED_CORE_ROTATE=y CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set @@ -33,12 +37,12 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y -# CONFIG_AIO is not set +CONFIG_BPF_SYSCALL=y # CONFIG_MEMBARRIER is not set CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y -CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -52,17 +56,19 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_ARCH_QCOM=y CONFIG_ARCH_SDM845=y -CONFIG_ARCH_SDM830=y CONFIG_PCI=y +CONFIG_PCI_MSM=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y CONFIG_HZ_100=y CONFIG_CLEANCACHE=y CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_SECCOMP=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -82,10 +88,9 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y -CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -132,6 +137,7 @@ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -159,9 +165,9 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y -CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -172,6 +178,7 @@ CONFIG_NF_CONNTRACK_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y CONFIG_IP_NF_MATCH_TTL=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y @@ -187,6 +194,8 @@ CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_IPTABLES_128=y +CONFIG_IP6_NF_MATCH_RPFILTER=y CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y @@ -206,8 +215,6 @@ CONFIG_NET_SCH_MULTIQ=y CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=y CONFIG_NET_EMATCH=y CONFIG_NET_EMATCH_CMP=y CONFIG_NET_EMATCH_NBYTE=y @@ -220,6 +227,7 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y @@ -227,9 +235,11 @@ CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y +CONFIG_NFC_NQ=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y @@ -248,9 +258,13 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -258,16 +272,23 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y -CONFIG_RNDIS_IPA=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y +CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -285,10 +306,11 @@ CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_QCOM_GENI=y -CONFIG_SOUNDWIRE=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPI_QCOM_GENI=y @@ -297,7 +319,6 @@ CONFIG_SLIMBUS_MSM_NGD=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PINCTRL_SDM845=y -CONFIG_PINCTRL_SDM830=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y @@ -306,8 +327,8 @@ CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_FG_GEN3=y +CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_SMB2=y -CONFIG_SMB138X_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y @@ -317,22 +338,28 @@ CONFIG_THERMAL_GOV_STEP_WISE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y CONFIG_CPU_THERMAL=y CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_THERMAL_TSENS=y CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y -CONFIG_WCD934X_CODEC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_QPNP_LABIBB=y CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -340,10 +367,13 @@ CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SPECTRA_CAMERA=y CONFIG_MSM_VIDC_V4L2=y -CONFIG_MSM_VIDC_VMEM=y CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m CONFIG_QCOM_KGSL=y CONFIG_DRM=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y @@ -356,13 +386,17 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y -CONFIG_SND_SOC_SDM845=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -377,6 +411,7 @@ CONFIG_USB_ISP1760_HOST_ROLE=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -400,10 +435,13 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y +CONFIG_MMC_TEST=m CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -412,18 +450,25 @@ CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_TRIGGERS=y CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_EDAC_KRYO3XX_ARM64=y CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_CE=y CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_UE=y -CONFIG_EDAC_QCOM_LLCC=y -CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y -CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_DEBUG=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y @@ -434,13 +479,16 @@ CONFIG_ION_MSM=y CONFIG_GSI=y CONFIG_IPA3=y CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_COINCELL=y CONFIG_QPNP_REVID=y CONFIG_USB_BAM=y +CONFIG_MSM_11AD=m CONFIG_SEEMP_CORE=y +CONFIG_QCOM_GENI_SE=y CONFIG_MSM_GCC_SDM845=y CONFIG_MSM_VIDEOCC_SDM845=y CONFIG_MSM_CAMCC_SDM845=y @@ -457,11 +505,15 @@ CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM845_LLCC=y +CONFIG_QCOM_LLCC_PERFMON=m +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y @@ -482,22 +534,30 @@ CONFIG_MSM_SPSS_UTILS=y CONFIG_TRACER_PKT=y CONFIG_QTI_RPMH_API=y CONFIG_MSM_SMP2P=y -CONFIG_MSM_SMP2P_TEST=y CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y CONFIG_MSM_QMI_INTERFACE=y CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_GLINK_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_ICNSS=y CONFIG_ICNSS_DEBUG=y CONFIG_QCOM_COMMAND_DB=y -CONFIG_MSM_AVTIMER=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y -CONFIG_APSS_CORE_EA=y +CONFIG_MSM_QBT1000=y CONFIG_QCOM_DCC_V2=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_REMOTEQDSS=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y CONFIG_QCOMCCI_HWMON=y @@ -507,7 +567,6 @@ CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y -CONFIG_EXTCON=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y @@ -517,13 +576,18 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_PHY_XGENE=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -531,6 +595,7 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y @@ -548,7 +613,6 @@ CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_FREE=y CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_OBJECTS_WORK=y -CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y @@ -564,14 +628,13 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_TIMER_STATS=y -# CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_LIST=y CONFIG_FAULT_INJECTION=y CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_IPC_LOGGING=y @@ -584,6 +647,7 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_LKDTM=y CONFIG_MEMTEST=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_PTDUMP=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_CORESIGHT=y @@ -596,17 +660,25 @@ CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index 44e1d7f10add1f892fb839ae41bbaae4cfd76442..28196b18e3947c0d946b33bd69e5677b96c2ecd3 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild @@ -1,7 +1,6 @@ generic-y += bugs.h generic-y += clkdev.h generic-y += cputime.h -generic-y += current.h generic-y += delay.h generic-y += div64.h generic-y += dma.h diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index e517088d635fcc0c0f698418cf850b0541c8eb32..de04879bc8b83a344f9cfb8f4ab1a7be2abb8a25 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -22,9 +22,9 @@ #define ACPI_MADT_GICC_LENGTH \ (acpi_gbl_FADT.header.revision < 6 ? 76 : 80) -#define BAD_MADT_GICC_ENTRY(entry, end) \ - (!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) || \ - (entry)->header.length != ACPI_MADT_GICC_LENGTH) +#define BAD_MADT_GICC_ENTRY(entry, end) \ + (!(entry) || (entry)->header.length != ACPI_MADT_GICC_LENGTH || \ + (unsigned long)(entry) + ACPI_MADT_GICC_LENGTH > (end)) /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 6ebd2c3b04f86975fb8fc88640dc5b90b48c339b..f1ace59c545bd8406ecf7f0a75caa53da4156b56 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -21,6 +21,7 @@ #include #define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) +#define ICC_HPPIR1_EL1 sys_reg(3, 0, 12, 12, 2) #define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1) #define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) #define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h new file mode 100644 index 0000000000000000000000000000000000000000..be2d2347d995064668a48f9c96c2fc27cdd2245d --- /dev/null +++ b/arch/arm64/include/asm/asm-uaccess.h @@ -0,0 +1,13 @@ +#ifndef __ASM_ASM_UACCESS_H +#define __ASM_ASM_UACCESS_H + +/* + * Remove the address tag from a virtual address, if present. + */ + .macro clear_address_tag, dst, addr + tst \addr, #(1 << 55) + bic \dst, \addr, #(0xff << 56) + csel \dst, \dst, \addr, eq + .endm + +#endif diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index e3c80f175f40e936173b3b9554f9372479b2ea88..46d04485c999a8b765fc4100f9590f0928c6f072 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -176,22 +176,25 @@ lr .req x30 // link register /* * Pseudo-ops for PC-relative adr/ldr/str , where - * is within the range +/- 4 GB of the PC. + * is within the range +/- 4 GB of the PC when running + * in core kernel context. In module context, a movz/movk sequence + * is used, since modules may be loaded far away from the kernel + * when KASLR is in effect. */ /* * @dst: destination register (64 bit wide) * @sym: name of the symbol - * @tmp: optional scratch register to be used if == sp, which - * is not allowed in an adrp instruction */ - .macro adr_l, dst, sym, tmp= - .ifb \tmp + .macro adr_l, dst, sym +#ifndef MODULE adrp \dst, \sym add \dst, \dst, :lo12:\sym - .else - adrp \tmp, \sym - add \dst, \tmp, :lo12:\sym - .endif +#else + movz \dst, #:abs_g3:\sym + movk \dst, #:abs_g2_nc:\sym + movk \dst, #:abs_g1_nc:\sym + movk \dst, #:abs_g0_nc:\sym +#endif .endm /* @@ -202,6 +205,7 @@ lr .req x30 // link register * the address */ .macro ldr_l, dst, sym, tmp= +#ifndef MODULE .ifb \tmp adrp \dst, \sym ldr \dst, [\dst, :lo12:\sym] @@ -209,6 +213,15 @@ lr .req x30 // link register adrp \tmp, \sym ldr \dst, [\tmp, :lo12:\sym] .endif +#else + .ifb \tmp + adr_l \dst, \sym + ldr \dst, [\dst] + .else + adr_l \tmp, \sym + ldr \dst, [\tmp] + .endif +#endif .endm /* @@ -218,19 +231,35 @@ lr .req x30 // link register * while needs to be preserved. */ .macro str_l, src, sym, tmp +#ifndef MODULE adrp \tmp, \sym str \src, [\tmp, :lo12:\sym] +#else + adr_l \tmp, \sym + str \src, [\tmp] +#endif .endm /* + * @dst: Result of per_cpu(sym, smp_processor_id()) * @sym: The name of the per-cpu variable - * @reg: Result of per_cpu(sym, smp_processor_id()) * @tmp: scratch register */ - .macro this_cpu_ptr, sym, reg, tmp - adr_l \reg, \sym + .macro adr_this_cpu, dst, sym, tmp + adr_l \dst, \sym mrs \tmp, tpidr_el1 - add \reg, \reg, \tmp + add \dst, \dst, \tmp + .endm + + /* + * @dst: Result of READ_ONCE(per_cpu(sym, smp_processor_id())) + * @sym: The name of the per-cpu variable + * @tmp: scratch register + */ + .macro ldr_this_cpu dst, sym, tmp + adr_l \dst, \sym + mrs \tmp, tpidr_el1 + ldr \dst, [\dst, \tmp] .endm /* @@ -423,17 +452,4 @@ alternative_endif mrs \rd, sp_el0 .endm -/* - * Errata workaround post TTBR0_EL1 update. - */ - .macro post_ttbr0_update_workaround -#ifdef CONFIG_CAVIUM_ERRATUM_27456 -alternative_if ARM64_WORKAROUND_CAVIUM_27456 - ic iallu - dsb nsh - isb -alternative_else_nop_endif -#endif - .endm - #endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 4e0497f581a05ea791564badc73ffa7a1f4a0699..0fe7e43b7fbc26bf2f6f2a47354a21943ae56ab9 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -42,25 +42,35 @@ #define __smp_rmb() dmb(ishld) #define __smp_wmb() dmb(ishst) -#define __smp_store_release(p, v) \ +#define __smp_store_release(p, v) \ do { \ + union { typeof(*p) __val; char __c[1]; } __u = \ + { .__val = (__force typeof(*p)) (v) }; \ compiletime_assert_atomic_type(*p); \ switch (sizeof(*p)) { \ case 1: \ asm volatile ("stlrb %w1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u8 *)__u.__c) \ + : "memory"); \ break; \ case 2: \ asm volatile ("stlrh %w1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u16 *)__u.__c) \ + : "memory"); \ break; \ case 4: \ asm volatile ("stlr %w1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u32 *)__u.__c) \ + : "memory"); \ break; \ case 8: \ asm volatile ("stlr %1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u64 *)__u.__c) \ + : "memory"); \ break; \ } \ } while (0) diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 91b26d26af8a5f961ed4d8905daffc11be5d72fa..ae852add053d835cdeb98ede5458419dd2958c6a 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -46,7 +46,7 @@ static inline unsigned long __xchg_case_##name(unsigned long x, \ " swp" #acq_lse #rel #sz "\t%" #w "3, %" #w "0, %2\n" \ __nops(3) \ " " #nop_lse) \ - : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr) \ + : "=&r" (ret), "=&r" (tmp), "+Q" (*(unsigned long *)ptr) \ : "r" (x) \ : cl); \ \ diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index 87b44653518551d39797a67c1cd367e44ea27b55..d64bf94a79a1e3526f24f4678fae824df603d2ba 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -35,6 +35,10 @@ #define ARM64_HYP_OFFSET_LOW 14 #define ARM64_MISMATCHED_CACHE_LINE_SIZE 15 -#define ARM64_NCAPS 16 +#define ARM64_UNMAP_KERNEL_AT_EL0 16 + +#define ARM64_HARDEN_BRANCH_PREDICTOR 17 + +#define ARM64_NCAPS 18 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index f8682a3277009f6cf3938564a0aea2bbbc47a89f..ddbf3b12b91534d31b1e1bb96971d02062d7cd66 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -63,7 +63,6 @@ ({ \ u32 _model = (midr) & MIDR_CPU_MODEL_MASK; \ u32 rv = (midr) & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK); \ - \ _model == (model) && rv >= (rv_min) && rv <= (rv_max); \ }) @@ -76,7 +75,11 @@ #define ARM_CPU_PART_AEM_V8 0xD0F #define ARM_CPU_PART_FOUNDATION 0xD00 #define ARM_CPU_PART_CORTEX_A57 0xD07 +#define ARM_CPU_PART_CORTEX_A72 0xD08 #define ARM_CPU_PART_CORTEX_A53 0xD03 +#define ARM_CPU_PART_CORTEX_A73 0xD09 +#define ARM_CPU_PART_CORTEX_A75 0xD0A +#define ARM_CPU_PART_KRYO3G 0x802 #define APM_CPU_PART_POTENZA 0x000 @@ -87,6 +90,10 @@ #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) +#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) +#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73) +#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75) +#define MIDR_KRYO3G MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3G) #define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX) diff --git a/arch/arm64/include/asm/current.h b/arch/arm64/include/asm/current.h new file mode 100644 index 0000000000000000000000000000000000000000..86c404171305abd290a6a85d7a5edd69c55ecd02 --- /dev/null +++ b/arch/arm64/include/asm/current.h @@ -0,0 +1,30 @@ +#ifndef __ASM_CURRENT_H +#define __ASM_CURRENT_H + +#include + +#include + +#ifndef __ASSEMBLY__ + +struct task_struct; + +/* + * We don't use read_sysreg() as we want the compiler to cache the value where + * possible. + */ +static __always_inline struct task_struct *get_current(void) +{ + unsigned long sp_el0; + + asm ("mrs %0, sp_el0" : "=r" (sp_el0)); + + return (struct task_struct *)sp_el0; +} + +#define current get_current() + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_CURRENT_H */ + diff --git a/arch/arm64/include/asm/debugv8.h b/arch/arm64/include/asm/debugv8.h new file mode 100644 index 0000000000000000000000000000000000000000..e32de804f7c3e5af54ab114f87fbfb3de2279b82 --- /dev/null +++ b/arch/arm64/include/asm/debugv8.h @@ -0,0 +1,229 @@ +/* Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_DEBUGV8_H +#define __ASM_DEBUGV8_H + +#include + +/* 32 bit register reads for aarch 64 bit */ +#define dbg_readl(reg) RSYSL_##reg() +/* 64 bit register reads for aarch 64 bit */ +#define dbg_readq(reg) RSYSQ_##reg() +/* 32 and 64 bit register writes for aarch 64 bit */ +#define dbg_write(val, reg) WSYS_##reg(val) + +#define MRSL(reg) \ +({ \ +uint32_t val; \ +asm volatile("mrs %0, "#reg : "=r" (val)); \ +val; \ +}) + +#define MRSQ(reg) \ +({ \ +uint64_t val; \ +asm volatile("mrs %0, "#reg : "=r" (val)); \ +val; \ +}) + +#define MSR(val, reg) \ +({ \ +asm volatile("msr "#reg", %0" : : "r" (val)); \ +}) + +/* + * Debug Feature Register + * + * Read only + */ +#define RSYSQ_ID_AA64DFR0_EL1() MRSQ(ID_AA64DFR0_EL1) + +/* + * Debug Registers + * + * Available only in DBGv8 + * + * Read only + * MDCCSR_EL0, MDRAR_EL1, OSLSR_EL1, DBGDTRRX_EL0, DBGAUTHSTATUS_EL1 + * + * Write only + * DBGDTRTX_EL0, OSLAR_EL1 + */ +/* 32 bit registers */ +#define RSYSL_DBGDTRRX_EL0() MRSL(DBGDTRRX_EL0) +#define RSYSL_MDCCSR_EL0() MRSL(MDCCSR_EL0) +#define RSYSL_MDSCR_EL1() MRSL(MDSCR_EL1) +#define RSYSL_OSDTRRX_EL1() MRSL(OSDTRRX_EL1) +#define RSYSL_OSDTRTX_EL1() MRSL(OSDTRTX_EL1) +#define RSYSL_OSDLR_EL1() MRSL(OSDLR_EL1) +#define RSYSL_OSLSR_EL1() MRSL(OSLSR_EL1) +#define RSYSL_MDCCINT_EL1() MRSL(MDCCINT_EL1) +#define RSYSL_OSECCR_EL1() MRSL(OSECCR_EL1) +#define RSYSL_DBGPRCR_EL1() MRSL(DBGPRCR_EL1) +#define RSYSL_DBGBCR0_EL1() MRSL(DBGBCR0_EL1) +#define RSYSL_DBGBCR1_EL1() MRSL(DBGBCR1_EL1) +#define RSYSL_DBGBCR2_EL1() MRSL(DBGBCR2_EL1) +#define RSYSL_DBGBCR3_EL1() MRSL(DBGBCR3_EL1) +#define RSYSL_DBGBCR4_EL1() MRSL(DBGBCR4_EL1) +#define RSYSL_DBGBCR5_EL1() MRSL(DBGBCR5_EL1) +#define RSYSL_DBGBCR6_EL1() MRSL(DBGBCR6_EL1) +#define RSYSL_DBGBCR7_EL1() MRSL(DBGBCR7_EL1) +#define RSYSL_DBGBCR8_EL1() MRSL(DBGBCR8_EL1) +#define RSYSL_DBGBCR9_EL1() MRSL(DBGBCR9_EL1) +#define RSYSL_DBGBCR10_EL1() MRSL(DBGBCR10_EL1) +#define RSYSL_DBGBCR11_EL1() MRSL(DBGBCR11_EL1) +#define RSYSL_DBGBCR12_EL1() MRSL(DBGBCR12_EL1) +#define RSYSL_DBGBCR13_EL1() MRSL(DBGBCR13_EL1) +#define RSYSL_DBGBCR14_EL1() MRSL(DBGBCR14_EL1) +#define RSYSL_DBGBCR15_EL1() MRSL(DBGBCR15_EL1) +#define RSYSL_DBGWCR0_EL1() MRSL(DBGWCR0_EL1) +#define RSYSL_DBGWCR1_EL1() MRSL(DBGWCR1_EL1) +#define RSYSL_DBGWCR2_EL1() MRSL(DBGWCR2_EL1) +#define RSYSL_DBGWCR3_EL1() MRSL(DBGWCR3_EL1) +#define RSYSL_DBGWCR4_EL1() MRSL(DBGWCR4_EL1) +#define RSYSL_DBGWCR5_EL1() MRSL(DBGWCR5_EL1) +#define RSYSL_DBGWCR6_EL1() MRSL(DBGWCR6_EL1) +#define RSYSL_DBGWCR7_EL1() MRSL(DBGWCR7_EL1) +#define RSYSL_DBGWCR8_EL1() MRSL(DBGWCR8_EL1) +#define RSYSL_DBGWCR9_EL1() MRSL(DBGWCR9_EL1) +#define RSYSL_DBGWCR10_EL1() MRSL(DBGWCR10_EL1) +#define RSYSL_DBGWCR11_EL1() MRSL(DBGWCR11_EL1) +#define RSYSL_DBGWCR12_EL1() MRSL(DBGWCR12_EL1) +#define RSYSL_DBGWCR13_EL1() MRSL(DBGWCR13_EL1) +#define RSYSL_DBGWCR14_EL1() MRSL(DBGWCR14_EL1) +#define RSYSL_DBGWCR15_EL1() MRSL(DBGWCR15_EL1) +#define RSYSL_DBGCLAIMSET_EL1() MRSL(DBGCLAIMSET_EL1) +#define RSYSL_DBGCLAIMCLR_EL1() MRSL(DBGCLAIMCLR_EL1) +#define RSYSL_DBGAUTHSTATUS_EL1() MRSL(DBGAUTHSTATUS_EL1) +#define RSYSL_DBGVCR32_EL2() MRSL(DBGVCR32_EL2) +#define RSYSL_MDCR_EL2() MRSL(MDCR_EL2) +#define RSYSL_MDCR_EL3() MRSL(MDCR_EL3) +/* 64 bit registers */ +#define RSYSQ_DBGDTR_EL0() MRSQ(DBGDTR_EL0) +#define RSYSQ_MDRAR_EL1() MRSQ(MDRAR_EL1) +#define RSYSQ_DBGBVR0_EL1() MRSQ(DBGBVR0_EL1) +#define RSYSQ_DBGBVR1_EL1() MRSQ(DBGBVR1_EL1) +#define RSYSQ_DBGBVR2_EL1() MRSQ(DBGBVR2_EL1) +#define RSYSQ_DBGBVR3_EL1() MRSQ(DBGBVR3_EL1) +#define RSYSQ_DBGBVR4_EL1() MRSQ(DBGBVR4_EL1) +#define RSYSQ_DBGBVR5_EL1() MRSQ(DBGBVR5_EL1) +#define RSYSQ_DBGBVR6_EL1() MRSQ(DBGBVR6_EL1) +#define RSYSQ_DBGBVR7_EL1() MRSQ(DBGBVR7_EL1) +#define RSYSQ_DBGBVR8_EL1() MRSQ(DBGBVR8_EL1) +#define RSYSQ_DBGBVR9_EL1() MRSQ(DBGBVR9_EL1) +#define RSYSQ_DBGBVR10_EL1() MRSQ(DBGBVR10_EL1) +#define RSYSQ_DBGBVR11_EL1() MRSQ(DBGBVR11_EL1) +#define RSYSQ_DBGBVR12_EL1() MRSQ(DBGBVR12_EL1) +#define RSYSQ_DBGBVR13_EL1() MRSQ(DBGBVR13_EL1) +#define RSYSQ_DBGBVR14_EL1() MRSQ(DBGBVR14_EL1) +#define RSYSQ_DBGBVR15_EL1() MRSQ(DBGBVR15_EL1) +#define RSYSQ_DBGWVR0_EL1() MRSQ(DBGWVR0_EL1) +#define RSYSQ_DBGWVR1_EL1() MRSQ(DBGWVR1_EL1) +#define RSYSQ_DBGWVR2_EL1() MRSQ(DBGWVR2_EL1) +#define RSYSQ_DBGWVR3_EL1() MRSQ(DBGWVR3_EL1) +#define RSYSQ_DBGWVR4_EL1() MRSQ(DBGWVR4_EL1) +#define RSYSQ_DBGWVR5_EL1() MRSQ(DBGWVR5_EL1) +#define RSYSQ_DBGWVR6_EL1() MRSQ(DBGWVR6_EL1) +#define RSYSQ_DBGWVR7_EL1() MRSQ(DBGWVR7_EL1) +#define RSYSQ_DBGWVR8_EL1() MRSQ(DBGWVR8_EL1) +#define RSYSQ_DBGWVR9_EL1() MRSQ(DBGWVR9_EL1) +#define RSYSQ_DBGWVR10_EL1() MRSQ(DBGWVR10_EL1) +#define RSYSQ_DBGWVR11_EL1() MRSQ(DBGWVR11_EL1) +#define RSYSQ_DBGWVR12_EL1() MRSQ(DBGWVR12_EL1) +#define RSYSQ_DBGWVR13_EL1() MRSQ(DBGWVR13_EL1) +#define RSYSQ_DBGWVR14_EL1() MRSQ(DBGWVR14_EL1) +#define RSYSQ_DBGWVR15_EL1() MRSQ(DBGWVR15_EL1) + +/* 32 bit registers */ +#define WSYS_DBGDTRTX_EL0(val) MSR(val, DBGDTRTX_EL0) +#define WSYS_MDCCINT_EL1(val) MSR(val, MDCCINT_EL1) +#define WSYS_MDSCR_EL1(val) MSR(val, MDSCR_EL1) +#define WSYS_OSDTRRX_EL1(val) MSR(val, OSDTRRX_EL1) +#define WSYS_OSDTRTX_EL1(val) MSR(val, OSDTRTX_EL1) +#define WSYS_OSDLR_EL1(val) MSR(val, OSDLR_EL1) +#define WSYS_OSECCR_EL1(val) MSR(val, OSECCR_EL1) +#define WSYS_DBGPRCR_EL1(val) MSR(val, DBGPRCR_EL1) +#define WSYS_DBGBCR0_EL1(val) MSR(val, DBGBCR0_EL1) +#define WSYS_DBGBCR1_EL1(val) MSR(val, DBGBCR1_EL1) +#define WSYS_DBGBCR2_EL1(val) MSR(val, DBGBCR2_EL1) +#define WSYS_DBGBCR3_EL1(val) MSR(val, DBGBCR3_EL1) +#define WSYS_DBGBCR4_EL1(val) MSR(val, DBGBCR4_EL1) +#define WSYS_DBGBCR5_EL1(val) MSR(val, DBGBCR5_EL1) +#define WSYS_DBGBCR6_EL1(val) MSR(val, DBGBCR6_EL1) +#define WSYS_DBGBCR7_EL1(val) MSR(val, DBGBCR7_EL1) +#define WSYS_DBGBCR8_EL1(val) MSR(val, DBGBCR8_EL1) +#define WSYS_DBGBCR9_EL1(val) MSR(val, DBGBCR9_EL1) +#define WSYS_DBGBCR10_EL1(val) MSR(val, DBGBCR10_EL1) +#define WSYS_DBGBCR11_EL1(val) MSR(val, DBGBCR11_EL1) +#define WSYS_DBGBCR12_EL1(val) MSR(val, DBGBCR12_EL1) +#define WSYS_DBGBCR13_EL1(val) MSR(val, DBGBCR13_EL1) +#define WSYS_DBGBCR14_EL1(val) MSR(val, DBGBCR14_EL1) +#define WSYS_DBGBCR15_EL1(val) MSR(val, DBGBCR15_EL1) +#define WSYS_DBGWCR0_EL1(val) MSR(val, DBGWCR0_EL1) +#define WSYS_DBGWCR1_EL1(val) MSR(val, DBGWCR1_EL1) +#define WSYS_DBGWCR2_EL1(val) MSR(val, DBGWCR2_EL1) +#define WSYS_DBGWCR3_EL1(val) MSR(val, DBGWCR3_EL1) +#define WSYS_DBGWCR4_EL1(val) MSR(val, DBGWCR4_EL1) +#define WSYS_DBGWCR5_EL1(val) MSR(val, DBGWCR5_EL1) +#define WSYS_DBGWCR6_EL1(val) MSR(val, DBGWCR6_EL1) +#define WSYS_DBGWCR7_EL1(val) MSR(val, DBGWCR7_EL1) +#define WSYS_DBGWCR8_EL1(val) MSR(val, DBGWCR8_EL1) +#define WSYS_DBGWCR9_EL1(val) MSR(val, DBGWCR9_EL1) +#define WSYS_DBGWCR10_EL1(val) MSR(val, DBGWCR10_EL1) +#define WSYS_DBGWCR11_EL1(val) MSR(val, DBGWCR11_EL1) +#define WSYS_DBGWCR12_EL1(val) MSR(val, DBGWCR12_EL1) +#define WSYS_DBGWCR13_EL1(val) MSR(val, DBGWCR13_EL1) +#define WSYS_DBGWCR14_EL1(val) MSR(val, DBGWCR14_EL1) +#define WSYS_DBGWCR15_EL1(val) MSR(val, DBGWCR15_EL1) +#define WSYS_DBGCLAIMSET_EL1(val) MSR(val, DBGCLAIMSET_EL1) +#define WSYS_DBGCLAIMCLR_EL1(val) MSR(val, DBGCLAIMCLR_EL1) +#define WSYS_OSLAR_EL1(val) MSR(val, OSLAR_EL1) +#define WSYS_DBGVCR32_EL2(val) MSR(val, DBGVCR32_EL2) +#define WSYS_MDCR_EL2(val) MSR(val, MDCR_EL2) +#define WSYS_MDCR_EL3(val) MSR(val, MDCR_EL3) +/* 64 bit registers */ +#define WSYS_DBGDTR_EL0(val) MSR(val, DBGDTR_EL0) +#define WSYS_DBGBVR0_EL1(val) MSR(val, DBGBVR0_EL1) +#define WSYS_DBGBVR1_EL1(val) MSR(val, DBGBVR1_EL1) +#define WSYS_DBGBVR2_EL1(val) MSR(val, DBGBVR2_EL1) +#define WSYS_DBGBVR3_EL1(val) MSR(val, DBGBVR3_EL1) +#define WSYS_DBGBVR4_EL1(val) MSR(val, DBGBVR4_EL1) +#define WSYS_DBGBVR5_EL1(val) MSR(val, DBGBVR5_EL1) +#define WSYS_DBGBVR6_EL1(val) MSR(val, DBGBVR6_EL1) +#define WSYS_DBGBVR7_EL1(val) MSR(val, DBGBVR7_EL1) +#define WSYS_DBGBVR8_EL1(val) MSR(val, DBGBVR8_EL1) +#define WSYS_DBGBVR9_EL1(val) MSR(val, DBGBVR9_EL1) +#define WSYS_DBGBVR10_EL1(val) MSR(val, DBGBVR10_EL1) +#define WSYS_DBGBVR11_EL1(val) MSR(val, DBGBVR11_EL1) +#define WSYS_DBGBVR12_EL1(val) MSR(val, DBGBVR12_EL1) +#define WSYS_DBGBVR13_EL1(val) MSR(val, DBGBVR13_EL1) +#define WSYS_DBGBVR14_EL1(val) MSR(val, DBGBVR14_EL1) +#define WSYS_DBGBVR15_EL1(val) MSR(val, DBGBVR15_EL1) +#define WSYS_DBGWVR0_EL1(val) MSR(val, DBGWVR0_EL1) +#define WSYS_DBGWVR1_EL1(val) MSR(val, DBGWVR1_EL1) +#define WSYS_DBGWVR2_EL1(val) MSR(val, DBGWVR2_EL1) +#define WSYS_DBGWVR3_EL1(val) MSR(val, DBGWVR3_EL1) +#define WSYS_DBGWVR4_EL1(val) MSR(val, DBGWVR4_EL1) +#define WSYS_DBGWVR5_EL1(val) MSR(val, DBGWVR5_EL1) +#define WSYS_DBGWVR6_EL1(val) MSR(val, DBGWVR6_EL1) +#define WSYS_DBGWVR7_EL1(val) MSR(val, DBGWVR7_EL1) +#define WSYS_DBGWVR8_EL1(val) MSR(val, DBGWVR8_EL1) +#define WSYS_DBGWVR9_EL1(val) MSR(val, DBGWVR9_EL1) +#define WSYS_DBGWVR10_EL1(val) MSR(val, DBGWVR10_EL1) +#define WSYS_DBGWVR11_EL1(val) MSR(val, DBGWVR11_EL1) +#define WSYS_DBGWVR12_EL1(val) MSR(val, DBGWVR12_EL1) +#define WSYS_DBGWVR13_EL1(val) MSR(val, DBGWVR13_EL1) +#define WSYS_DBGWVR14_EL1(val) MSR(val, DBGWVR14_EL1) +#define WSYS_DBGWVR15_EL1(val) MSR(val, DBGWVR15_EL1) + +#endif diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h index ab0e5b27c84d69cc2e92165973d837912615f2c2..cfd49b29978c1e86616de67c1e107b283568d742 100644 --- a/arch/arm64/include/asm/dma-iommu.h +++ b/arch/arm64/include/asm/dma-iommu.h @@ -14,13 +14,17 @@ struct dma_iommu_mapping { /* iommu specific data */ struct iommu_domain *domain; + bool init; + struct kref kref; + const struct dma_map_ops *ops; + /* Protects bitmap */ + spinlock_t lock; void *bitmap; size_t bits; dma_addr_t base; - - spinlock_t lock; - struct kref kref; + u32 min_iova_align; + struct page *guard_page; struct dma_fast_smmu_mapping *fast; }; diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index b89a7f382c6c65c62dc2377c6a84cff58b96ce4b..0f2704c7e9593b31a72290bc04cd42eb6a614901 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -65,8 +65,6 @@ void arch_teardown_dma_ops(struct device *dev); /* do not use this function in a driver */ static inline bool is_device_dma_coherent(struct device *dev) { - if (!dev) - return false; return dev->archdata.dma_coherent; } diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 3a405dccb6cff592fea3600b5c7b7addf2da73b8..4e7eec79cbc8bea18e2091fa934cef848c88c022 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -93,11 +93,9 @@ static inline void efi_set_pgd(struct mm_struct *mm) * Defer the switch to the current thread's TTBR0_EL1 * until uaccess_enable(). Restore the current * thread's saved ttbr0 corresponding to its active_mm - * (if different from init_mm). */ cpu_set_reserved_ttbr0(); - if (current->active_mm != &init_mm) - update_saved_ttbr0(current, current->active_mm); + update_saved_ttbr0(current, current->active_mm); } } } diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index a55384f4a5d7bf4e92886a247fb19f09df417357..40a8a94db23b9cc43414377413b6c44e851407c5 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -113,12 +113,11 @@ #define ELF_EXEC_PAGESIZE PAGE_SIZE /* - * This is the location that an ET_DYN program is loaded if exec'ed. Typical - * use of this is to invoke "./ld.so someprog" to test out a new version of - * the loader. We need to make sure that it is out of the way of the program - * that it will "exec", and that there is sufficient room for the brk. + * This is the base location for PIE (ET_DYN with INTERP) loads. On + * 64-bit, this is above 4GB to leave the entire 32-bit address + * space open for things that want to use the area for 32-bit pointers. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) +#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) #ifndef __ASSEMBLY__ @@ -169,6 +168,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, #ifdef CONFIG_COMPAT +/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */ #define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3) /* AArch32 registers. */ diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index d14c478976d0abeb435163da5c16599a0f2c3b53..85997c0e544312a3d4e60157c4ba30d4d93239bd 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -175,6 +175,12 @@ #define ESR_ELx_SYS64_ISS_SYS_CTR_READ (ESR_ELx_SYS64_ISS_SYS_CTR | \ ESR_ELx_SYS64_ISS_DIR_READ) +#define ESR_ELx_SYS64_ISS_SYS_CNTVCT (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + +#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + #ifndef __ASSEMBLY__ #include diff --git a/arch/arm64/include/asm/etmv4x.h b/arch/arm64/include/asm/etmv4x.h new file mode 100644 index 0000000000000000000000000000000000000000..4fb91ca0d5fe912e9b945d3127ed30553781cd9f --- /dev/null +++ b/arch/arm64/include/asm/etmv4x.h @@ -0,0 +1,385 @@ +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_ETMV4X_H +#define __ASM_ETMV4X_H + +#include + +/* 32 bit register reads for AArch64 */ +#define trc_readl(reg) RSYSL_##reg() +/* 64 bit register reads for AArch64 */ +#define trc_readq(reg) RSYSQ_##reg() +/* 32 and 64 bit register writes for AArch64 */ +#define trc_write(val, reg) WSYS_##reg(val) + +#define MRSL(op0, op1, crn, crm, op2) \ +({ \ +uint32_t val; \ +asm volatile("mrs %0, S"#op0"_"#op1"_"#crn"_"#crm"_"#op2 : "=r" (val)); \ +val; \ +}) + +#define MRSQ(op0, op1, crn, crm, op2) \ +({ \ +uint64_t val; \ +asm volatile("mrs %0, S"#op0"_"#op1"_"#crn"_"#crm"_"#op2 : "=r" (val)); \ +val; \ +}) + +#define MSR(val, op0, op1, crn, crm, op2) \ +({ \ +asm volatile("msr S"#op0"_"#op1"_"#crn"_"#crm"_"#op2", %0" : : "r" (val)); \ +}) + +/* Clock and Power Management Register */ +#define RSYSL_CPMR_EL1() MRSL(3, 7, c15, c0, 5) +#define WSYS_CPMR_EL1(val) MSR(val, 3, 7, c15, c0, 5) + +/* + * ETMv4 Registers + * + * Read only + * ETMAUTHSTATUS, ETMDEVARCH, ETMDEVID, ETMIDRn[0-13], ETMOSLSR, ETMSTATR + * + * Write only + * ETMOSLAR + */ +/* 32 bit registers */ +#define RSYSL_ETMAUTHSTATUS() MRSL(2, 1, c7, c14, 6) +#define RSYSL_ETMAUXCTLR() MRSL(2, 1, c0, c6, 0) +#define RSYSL_ETMCCCTLR() MRSL(2, 1, c0, c14, 0) +#define RSYSL_ETMCIDCCTLR0() MRSL(2, 1, c3, c0, 2) +#define RSYSL_ETMCNTCTLR0() MRSL(2, 1, c0, c4, 5) +#define RSYSL_ETMCNTCTLR1() MRSL(2, 1, c0, c5, 5) +#define RSYSL_ETMCNTCTLR2() MRSL(2, 1, c0, c6, 5) +#define RSYSL_ETMCNTCTLR3() MRSL(2, 1, c0, c7, 5) +#define RSYSL_ETMCNTRLDVR0() MRSL(2, 1, c0, c0, 5) +#define RSYSL_ETMCNTRLDVR1() MRSL(2, 1, c0, c1, 5) +#define RSYSL_ETMCNTRLDVR2() MRSL(2, 1, c0, c2, 5) +#define RSYSL_ETMCNTRLDVR3() MRSL(2, 1, c0, c3, 5) +#define RSYSL_ETMCNTVR0() MRSL(2, 1, c0, c8, 5) +#define RSYSL_ETMCNTVR1() MRSL(2, 1, c0, c9, 5) +#define RSYSL_ETMCNTVR2() MRSL(2, 1, c0, c10, 5) +#define RSYSL_ETMCNTVR3() MRSL(2, 1, c0, c11, 5) +#define RSYSL_ETMCONFIGR() MRSL(2, 1, c0, c4, 0) +#define RSYSL_ETMDEVARCH() MRSL(2, 1, c7, c15, 6) +#define RSYSL_ETMDEVID() MRSL(2, 1, c7, c2, 7) +#define RSYSL_ETMEVENTCTL0R() MRSL(2, 1, c0, c8, 0) +#define RSYSL_ETMEVENTCTL1R() MRSL(2, 1, c0, c9, 0) +#define RSYSL_ETMEXTINSELR() MRSL(2, 1, c0, c8, 4) +#define RSYSL_ETMIDR0() MRSL(2, 1, c0, c8, 7) +#define RSYSL_ETMIDR1() MRSL(2, 1, c0, c9, 7) +#define RSYSL_ETMIDR10() MRSL(2, 1, c0, c2, 6) +#define RSYSL_ETMIDR11() MRSL(2, 1, c0, c3, 6) +#define RSYSL_ETMIDR12() MRSL(2, 1, c0, c4, 6) +#define RSYSL_ETMIDR13() MRSL(2, 1, c0, c5, 6) +#define RSYSL_ETMIDR2() MRSL(2, 1, c0, c10, 7) +#define RSYSL_ETMIDR3() MRSL(2, 1, c0, c11, 7) +#define RSYSL_ETMIDR4() MRSL(2, 1, c0, c12, 7) +#define RSYSL_ETMIDR5() MRSL(2, 1, c0, c13, 7) +#define RSYSL_ETMIDR6() MRSL(2, 1, c0, c14, 7) +#define RSYSL_ETMIDR7() MRSL(2, 1, c0, c15, 7) +#define RSYSL_ETMIDR8() MRSL(2, 1, c0, c0, 6) +#define RSYSL_ETMIDR9() MRSL(2, 1, c0, c1, 6) +#define RSYSL_ETMIMSPEC0() MRSL(2, 1, c0, c0, 7) +#define RSYSL_ETMOSLSR() MRSL(2, 1, c1, c1, 4) +#define RSYSL_ETMPRGCTLR() MRSL(2, 1, c0, c1, 0) +#define RSYSL_ETMRSCTLR10() MRSL(2, 1, c1, c10, 0) +#define RSYSL_ETMRSCTLR11() MRSL(2, 1, c1, c11, 0) +#define RSYSL_ETMRSCTLR12() MRSL(2, 1, c1, c12, 0) +#define RSYSL_ETMRSCTLR13() MRSL(2, 1, c1, c13, 0) +#define RSYSL_ETMRSCTLR14() MRSL(2, 1, c1, c14, 0) +#define RSYSL_ETMRSCTLR15() MRSL(2, 1, c1, c15, 0) +#define RSYSL_ETMRSCTLR2() MRSL(2, 1, c1, c2, 0) +#define RSYSL_ETMRSCTLR3() MRSL(2, 1, c1, c3, 0) +#define RSYSL_ETMRSCTLR4() MRSL(2, 1, c1, c4, 0) +#define RSYSL_ETMRSCTLR5() MRSL(2, 1, c1, c5, 0) +#define RSYSL_ETMRSCTLR6() MRSL(2, 1, c1, c6, 0) +#define RSYSL_ETMRSCTLR7() MRSL(2, 1, c1, c7, 0) +#define RSYSL_ETMRSCTLR8() MRSL(2, 1, c1, c8, 0) +#define RSYSL_ETMRSCTLR9() MRSL(2, 1, c1, c9, 0) +#define RSYSL_ETMRSCTLR16() MRSL(2, 1, c1, c0, 1) +#define RSYSL_ETMRSCTLR17() MRSL(2, 1, c1, c1, 1) +#define RSYSL_ETMRSCTLR18() MRSL(2, 1, c1, c2, 1) +#define RSYSL_ETMRSCTLR19() MRSL(2, 1, c1, c3, 1) +#define RSYSL_ETMRSCTLR20() MRSL(2, 1, c1, c4, 1) +#define RSYSL_ETMRSCTLR21() MRSL(2, 1, c1, c5, 1) +#define RSYSL_ETMRSCTLR22() MRSL(2, 1, c1, c6, 1) +#define RSYSL_ETMRSCTLR23() MRSL(2, 1, c1, c7, 1) +#define RSYSL_ETMRSCTLR24() MRSL(2, 1, c1, c8, 1) +#define RSYSL_ETMRSCTLR25() MRSL(2, 1, c1, c9, 1) +#define RSYSL_ETMRSCTLR26() MRSL(2, 1, c1, c10, 1) +#define RSYSL_ETMRSCTLR27() MRSL(2, 1, c1, c11, 1) +#define RSYSL_ETMRSCTLR28() MRSL(2, 1, c1, c12, 1) +#define RSYSL_ETMRSCTLR29() MRSL(2, 1, c1, c13, 1) +#define RSYSL_ETMRSCTLR30() MRSL(2, 1, c1, c14, 1) +#define RSYSL_ETMRSCTLR31() MRSL(2, 1, c1, c15, 1) +#define RSYSL_ETMSEQEVR0() MRSL(2, 1, c0, c0, 4) +#define RSYSL_ETMSEQEVR1() MRSL(2, 1, c0, c1, 4) +#define RSYSL_ETMSEQEVR2() MRSL(2, 1, c0, c2, 4) +#define RSYSL_ETMSEQRSTEVR() MRSL(2, 1, c0, c6, 4) +#define RSYSL_ETMSEQSTR() MRSL(2, 1, c0, c7, 4) +#define RSYSL_ETMSTALLCTLR() MRSL(2, 1, c0, c11, 0) +#define RSYSL_ETMSTATR() MRSL(2, 1, c0, c3, 0) +#define RSYSL_ETMSYNCPR() MRSL(2, 1, c0, c13, 0) +#define RSYSL_ETMTRACEIDR() MRSL(2, 1, c0, c0, 1) +#define RSYSL_ETMTSCTLR() MRSL(2, 1, c0, c12, 0) +#define RSYSL_ETMVICTLR() MRSL(2, 1, c0, c0, 2) +#define RSYSL_ETMVIIECTLR() MRSL(2, 1, c0, c1, 2) +#define RSYSL_ETMVISSCTLR() MRSL(2, 1, c0, c2, 2) +#define RSYSL_ETMSSCCR0() MRSL(2, 1, c1, c0, 2) +#define RSYSL_ETMSSCCR1() MRSL(2, 1, c1, c1, 2) +#define RSYSL_ETMSSCCR2() MRSL(2, 1, c1, c2, 2) +#define RSYSL_ETMSSCCR3() MRSL(2, 1, c1, c3, 2) +#define RSYSL_ETMSSCCR4() MRSL(2, 1, c1, c4, 2) +#define RSYSL_ETMSSCCR5() MRSL(2, 1, c1, c5, 2) +#define RSYSL_ETMSSCCR6() MRSL(2, 1, c1, c6, 2) +#define RSYSL_ETMSSCCR7() MRSL(2, 1, c1, c7, 2) +#define RSYSL_ETMSSCSR0() MRSL(2, 1, c1, c8, 2) +#define RSYSL_ETMSSCSR1() MRSL(2, 1, c1, c9, 2) +#define RSYSL_ETMSSCSR2() MRSL(2, 1, c1, c10, 2) +#define RSYSL_ETMSSCSR3() MRSL(2, 1, c1, c11, 2) +#define RSYSL_ETMSSCSR4() MRSL(2, 1, c1, c12, 2) +#define RSYSL_ETMSSCSR5() MRSL(2, 1, c1, c13, 2) +#define RSYSL_ETMSSCSR6() MRSL(2, 1, c1, c14, 2) +#define RSYSL_ETMSSCSR7() MRSL(2, 1, c1, c15, 2) +#define RSYSL_ETMSSPCICR0() MRSL(2, 1, c1, c0, 3) +#define RSYSL_ETMSSPCICR1() MRSL(2, 1, c1, c1, 3) +#define RSYSL_ETMSSPCICR2() MRSL(2, 1, c1, c2, 3) +#define RSYSL_ETMSSPCICR3() MRSL(2, 1, c1, c3, 3) +#define RSYSL_ETMSSPCICR4() MRSL(2, 1, c1, c4, 3) +#define RSYSL_ETMSSPCICR5() MRSL(2, 1, c1, c5, 3) +#define RSYSL_ETMSSPCICR6() MRSL(2, 1, c1, c6, 3) +#define RSYSL_ETMSSPCICR7() MRSL(2, 1, c1, c7, 3) + +/* 64 bit registers */ +#define RSYSQ_ETMACATR0() MRSQ(2, 1, c2, c0, 2) +#define RSYSQ_ETMACATR1() MRSQ(2, 1, c2, c2, 2) +#define RSYSQ_ETMACATR2() MRSQ(2, 1, c2, c4, 2) +#define RSYSQ_ETMACATR3() MRSQ(2, 1, c2, c6, 2) +#define RSYSQ_ETMACATR4() MRSQ(2, 1, c2, c8, 2) +#define RSYSQ_ETMACATR5() MRSQ(2, 1, c2, c10, 2) +#define RSYSQ_ETMACATR6() MRSQ(2, 1, c2, c12, 2) +#define RSYSQ_ETMACATR7() MRSQ(2, 1, c2, c14, 2) +#define RSYSQ_ETMACATR8() MRSQ(2, 1, c2, c0, 3) +#define RSYSQ_ETMACATR9() MRSQ(2, 1, c2, c2, 3) +#define RSYSQ_ETMACATR10() MRSQ(2, 1, c2, c4, 3) +#define RSYSQ_ETMACATR11() MRSQ(2, 1, c2, c6, 3) +#define RSYSQ_ETMACATR12() MRSQ(2, 1, c2, c8, 3) +#define RSYSQ_ETMACATR13() MRSQ(2, 1, c2, c10, 3) +#define RSYSQ_ETMACATR14() MRSQ(2, 1, c2, c12, 3) +#define RSYSQ_ETMACATR15() MRSQ(2, 1, c2, c14, 3) +#define RSYSQ_ETMCIDCVR0() MRSQ(2, 1, c3, c0, 0) +#define RSYSQ_ETMCIDCVR1() MRSQ(2, 1, c3, c2, 0) +#define RSYSQ_ETMCIDCVR2() MRSQ(2, 1, c3, c4, 0) +#define RSYSQ_ETMCIDCVR3() MRSQ(2, 1, c3, c6, 0) +#define RSYSQ_ETMCIDCVR4() MRSQ(2, 1, c3, c8, 0) +#define RSYSQ_ETMCIDCVR5() MRSQ(2, 1, c3, c10, 0) +#define RSYSQ_ETMCIDCVR6() MRSQ(2, 1, c3, c12, 0) +#define RSYSQ_ETMCIDCVR7() MRSQ(2, 1, c3, c14, 0) +#define RSYSQ_ETMACVR0() MRSQ(2, 1, c2, c0, 0) +#define RSYSQ_ETMACVR1() MRSQ(2, 1, c2, c2, 0) +#define RSYSQ_ETMACVR2() MRSQ(2, 1, c2, c4, 0) +#define RSYSQ_ETMACVR3() MRSQ(2, 1, c2, c6, 0) +#define RSYSQ_ETMACVR4() MRSQ(2, 1, c2, c8, 0) +#define RSYSQ_ETMACVR5() MRSQ(2, 1, c2, c10, 0) +#define RSYSQ_ETMACVR6() MRSQ(2, 1, c2, c12, 0) +#define RSYSQ_ETMACVR7() MRSQ(2, 1, c2, c14, 0) +#define RSYSQ_ETMACVR8() MRSQ(2, 1, c2, c0, 1) +#define RSYSQ_ETMACVR9() MRSQ(2, 1, c2, c2, 1) +#define RSYSQ_ETMACVR10() MRSQ(2, 1, c2, c4, 1) +#define RSYSQ_ETMACVR11() MRSQ(2, 1, c2, c6, 1) +#define RSYSQ_ETMACVR12() MRSQ(2, 1, c2, c8, 1) +#define RSYSQ_ETMACVR13() MRSQ(2, 1, c2, c10, 1) +#define RSYSQ_ETMACVR14() MRSQ(2, 1, c2, c12, 1) +#define RSYSQ_ETMACVR15() MRSQ(2, 1, c2, c14, 1) +#define RSYSQ_ETMVMIDCVR0() MRSQ(2, 1, c3, c0, 1) +#define RSYSQ_ETMVMIDCVR1() MRSQ(2, 1, c3, c2, 1) +#define RSYSQ_ETMVMIDCVR2() MRSQ(2, 1, c3, c4, 1) +#define RSYSQ_ETMVMIDCVR3() MRSQ(2, 1, c3, c6, 1) +#define RSYSQ_ETMVMIDCVR4() MRSQ(2, 1, c3, c8, 1) +#define RSYSQ_ETMVMIDCVR5() MRSQ(2, 1, c3, c10, 1) +#define RSYSQ_ETMVMIDCVR6() MRSQ(2, 1, c3, c12, 1) +#define RSYSQ_ETMVMIDCVR7() MRSQ(2, 1, c3, c14, 1) +#define RSYSQ_ETMDVCVR0() MRSQ(2, 1, c2, c0, 4) +#define RSYSQ_ETMDVCVR1() MRSQ(2, 1, c2, c4, 4) +#define RSYSQ_ETMDVCVR2() MRSQ(2, 1, c2, c8, 4) +#define RSYSQ_ETMDVCVR3() MRSQ(2, 1, c2, c12, 4) +#define RSYSQ_ETMDVCVR4() MRSQ(2, 1, c2, c0, 5) +#define RSYSQ_ETMDVCVR5() MRSQ(2, 1, c2, c4, 5) +#define RSYSQ_ETMDVCVR6() MRSQ(2, 1, c2, c8, 5) +#define RSYSQ_ETMDVCVR7() MRSQ(2, 1, c2, c12, 5) +#define RSYSQ_ETMDVCMR0() MRSQ(2, 1, c2, c0, 6) +#define RSYSQ_ETMDVCMR1() MRSQ(2, 1, c2, c4, 6) +#define RSYSQ_ETMDVCMR2() MRSQ(2, 1, c2, c8, 6) +#define RSYSQ_ETMDVCMR3() MRSQ(2, 1, c2, c12, 6) +#define RSYSQ_ETMDVCMR4() MRSQ(2, 1, c2, c0, 7) +#define RSYSQ_ETMDVCMR5() MRSQ(2, 1, c2, c4, 7) +#define RSYSQ_ETMDVCMR6() MRSQ(2, 1, c2, c8, 7) +#define RSYSQ_ETMDVCMR7() MRSQ(2, 1, c2, c12, 7) + +/* 32 and 64 bit registers */ +#define WSYS_ETMAUXCTLR(val) MSR(val, 2, 1, c0, c6, 0) +#define WSYS_ETMACATR0(val) MSR(val, 2, 1, c2, c0, 2) +#define WSYS_ETMACATR1(val) MSR(val, 2, 1, c2, c2, 2) +#define WSYS_ETMACATR2(val) MSR(val, 2, 1, c2, c4, 2) +#define WSYS_ETMACATR3(val) MSR(val, 2, 1, c2, c6, 2) +#define WSYS_ETMACATR4(val) MSR(val, 2, 1, c2, c8, 2) +#define WSYS_ETMACATR5(val) MSR(val, 2, 1, c2, c10, 2) +#define WSYS_ETMACATR6(val) MSR(val, 2, 1, c2, c12, 2) +#define WSYS_ETMACATR7(val) MSR(val, 2, 1, c2, c14, 2) +#define WSYS_ETMACATR8(val) MSR(val, 2, 1, c2, c0, 3) +#define WSYS_ETMACATR9(val) MSR(val, 2, 1, c2, c2, 3) +#define WSYS_ETMACATR10(val) MSR(val, 2, 1, c2, c4, 3) +#define WSYS_ETMACATR11(val) MSR(val, 2, 1, c2, c6, 3) +#define WSYS_ETMACATR12(val) MSR(val, 2, 1, c2, c8, 3) +#define WSYS_ETMACATR13(val) MSR(val, 2, 1, c2, c10, 3) +#define WSYS_ETMACATR14(val) MSR(val, 2, 1, c2, c12, 3) +#define WSYS_ETMACATR15(val) MSR(val, 2, 1, c2, c14, 3) +#define WSYS_ETMACVR0(val) MSR(val, 2, 1, c2, c0, 0) +#define WSYS_ETMACVR1(val) MSR(val, 2, 1, c2, c2, 0) +#define WSYS_ETMACVR2(val) MSR(val, 2, 1, c2, c4, 0) +#define WSYS_ETMACVR3(val) MSR(val, 2, 1, c2, c6, 0) +#define WSYS_ETMACVR4(val) MSR(val, 2, 1, c2, c8, 0) +#define WSYS_ETMACVR5(val) MSR(val, 2, 1, c2, c10, 0) +#define WSYS_ETMACVR6(val) MSR(val, 2, 1, c2, c12, 0) +#define WSYS_ETMACVR7(val) MSR(val, 2, 1, c2, c14, 0) +#define WSYS_ETMACVR8(val) MSR(val, 2, 1, c2, c0, 1) +#define WSYS_ETMACVR9(val) MSR(val, 2, 1, c2, c2, 1) +#define WSYS_ETMACVR10(val) MSR(val, 2, 1, c2, c4, 1) +#define WSYS_ETMACVR11(val) MSR(val, 2, 1, c2, c6, 1) +#define WSYS_ETMACVR12(val) MSR(val, 2, 1, c2, c8, 1) +#define WSYS_ETMACVR13(val) MSR(val, 2, 1, c2, c10, 1) +#define WSYS_ETMACVR14(val) MSR(val, 2, 1, c2, c12, 1) +#define WSYS_ETMACVR15(val) MSR(val, 2, 1, c2, c14, 1) +#define WSYS_ETMCCCTLR(val) MSR(val, 2, 1, c0, c14, 0) +#define WSYS_ETMCIDCCTLR0(val) MSR(val, 2, 1, c3, c0, 2) +#define WSYS_ETMCIDCVR0(val) MSR(val, 2, 1, c3, c0, 0) +#define WSYS_ETMCIDCVR1(val) MSR(val, 2, 1, c3, c2, 0) +#define WSYS_ETMCIDCVR2(val) MSR(val, 2, 1, c3, c4, 0) +#define WSYS_ETMCIDCVR3(val) MSR(val, 2, 1, c3, c6, 0) +#define WSYS_ETMCIDCVR4(val) MSR(val, 2, 1, c3, c8, 0) +#define WSYS_ETMCIDCVR5(val) MSR(val, 2, 1, c3, c10, 0) +#define WSYS_ETMCIDCVR6(val) MSR(val, 2, 1, c3, c12, 0) +#define WSYS_ETMCIDCVR7(val) MSR(val, 2, 1, c3, c14, 0) +#define WSYS_ETMCNTCTLR0(val) MSR(val, 2, 1, c0, c4, 5) +#define WSYS_ETMCNTCTLR1(val) MSR(val, 2, 1, c0, c5, 5) +#define WSYS_ETMCNTCTLR2(val) MSR(val, 2, 1, c0, c6, 5) +#define WSYS_ETMCNTCTLR3(val) MSR(val, 2, 1, c0, c7, 5) +#define WSYS_ETMCNTRLDVR0(val) MSR(val, 2, 1, c0, c0, 5) +#define WSYS_ETMCNTRLDVR1(val) MSR(val, 2, 1, c0, c1, 5) +#define WSYS_ETMCNTRLDVR2(val) MSR(val, 2, 1, c0, c2, 5) +#define WSYS_ETMCNTRLDVR3(val) MSR(val, 2, 1, c0, c3, 5) +#define WSYS_ETMCNTVR0(val) MSR(val, 2, 1, c0, c8, 5) +#define WSYS_ETMCNTVR1(val) MSR(val, 2, 1, c0, c9, 5) +#define WSYS_ETMCNTVR2(val) MSR(val, 2, 1, c0, c10, 5) +#define WSYS_ETMCNTVR3(val) MSR(val, 2, 1, c0, c11, 5) +#define WSYS_ETMCONFIGR(val) MSR(val, 2, 1, c0, c4, 0) +#define WSYS_ETMEVENTCTL0R(val) MSR(val, 2, 1, c0, c8, 0) +#define WSYS_ETMEVENTCTL1R(val) MSR(val, 2, 1, c0, c9, 0) +#define WSYS_ETMEXTINSELR(val) MSR(val, 2, 1, c0, c8, 4) +#define WSYS_ETMIMSPEC0(val) MSR(val, 2, 1, c0, c0, 7) +#define WSYS_ETMOSLAR(val) MSR(val, 2, 1, c1, c0, 4) +#define WSYS_ETMPRGCTLR(val) MSR(val, 2, 1, c0, c1, 0) +#define WSYS_ETMRSCTLR10(val) MSR(val, 2, 1, c1, c10, 0) +#define WSYS_ETMRSCTLR11(val) MSR(val, 2, 1, c1, c11, 0) +#define WSYS_ETMRSCTLR12(val) MSR(val, 2, 1, c1, c12, 0) +#define WSYS_ETMRSCTLR13(val) MSR(val, 2, 1, c1, c13, 0) +#define WSYS_ETMRSCTLR14(val) MSR(val, 2, 1, c1, c14, 0) +#define WSYS_ETMRSCTLR15(val) MSR(val, 2, 1, c1, c15, 0) +#define WSYS_ETMRSCTLR2(val) MSR(val, 2, 1, c1, c2, 0) +#define WSYS_ETMRSCTLR3(val) MSR(val, 2, 1, c1, c3, 0) +#define WSYS_ETMRSCTLR4(val) MSR(val, 2, 1, c1, c4, 0) +#define WSYS_ETMRSCTLR5(val) MSR(val, 2, 1, c1, c5, 0) +#define WSYS_ETMRSCTLR6(val) MSR(val, 2, 1, c1, c6, 0) +#define WSYS_ETMRSCTLR7(val) MSR(val, 2, 1, c1, c7, 0) +#define WSYS_ETMRSCTLR8(val) MSR(val, 2, 1, c1, c8, 0) +#define WSYS_ETMRSCTLR9(val) MSR(val, 2, 1, c1, c9, 0) +#define WSYS_ETMRSCTLR16(val) MSR(val, 2, 1, c1, c0, 1) +#define WSYS_ETMRSCTLR17(val) MSR(val, 2, 1, c1, c1, 1) +#define WSYS_ETMRSCTLR18(val) MSR(val, 2, 1, c1, c2, 1) +#define WSYS_ETMRSCTLR19(val) MSR(val, 2, 1, c1, c3, 1) +#define WSYS_ETMRSCTLR20(val) MSR(val, 2, 1, c1, c4, 1) +#define WSYS_ETMRSCTLR21(val) MSR(val, 2, 1, c1, c5, 1) +#define WSYS_ETMRSCTLR22(val) MSR(val, 2, 1, c1, c6, 1) +#define WSYS_ETMRSCTLR23(val) MSR(val, 2, 1, c1, c7, 1) +#define WSYS_ETMRSCTLR24(val) MSR(val, 2, 1, c1, c8, 1) +#define WSYS_ETMRSCTLR25(val) MSR(val, 2, 1, c1, c9, 1) +#define WSYS_ETMRSCTLR26(val) MSR(val, 2, 1, c1, c10, 1) +#define WSYS_ETMRSCTLR27(val) MSR(val, 2, 1, c1, c11, 1) +#define WSYS_ETMRSCTLR28(val) MSR(val, 2, 1, c1, c12, 1) +#define WSYS_ETMRSCTLR29(val) MSR(val, 2, 1, c1, c13, 1) +#define WSYS_ETMRSCTLR30(val) MSR(val, 2, 1, c1, c14, 1) +#define WSYS_ETMRSCTLR31(val) MSR(val, 2, 1, c1, c15, 1) +#define WSYS_ETMSEQEVR0(val) MSR(val, 2, 1, c0, c0, 4) +#define WSYS_ETMSEQEVR1(val) MSR(val, 2, 1, c0, c1, 4) +#define WSYS_ETMSEQEVR2(val) MSR(val, 2, 1, c0, c2, 4) +#define WSYS_ETMSEQRSTEVR(val) MSR(val, 2, 1, c0, c6, 4) +#define WSYS_ETMSEQSTR(val) MSR(val, 2, 1, c0, c7, 4) +#define WSYS_ETMSTALLCTLR(val) MSR(val, 2, 1, c0, c11, 0) +#define WSYS_ETMSYNCPR(val) MSR(val, 2, 1, c0, c13, 0) +#define WSYS_ETMTRACEIDR(val) MSR(val, 2, 1, c0, c0, 1) +#define WSYS_ETMTSCTLR(val) MSR(val, 2, 1, c0, c12, 0) +#define WSYS_ETMVICTLR(val) MSR(val, 2, 1, c0, c0, 2) +#define WSYS_ETMVIIECTLR(val) MSR(val, 2, 1, c0, c1, 2) +#define WSYS_ETMVISSCTLR(val) MSR(val, 2, 1, c0, c2, 2) +#define WSYS_ETMVMIDCVR0(val) MSR(val, 2, 1, c3, c0, 1) +#define WSYS_ETMVMIDCVR1(val) MSR(val, 2, 1, c3, c2, 1) +#define WSYS_ETMVMIDCVR2(val) MSR(val, 2, 1, c3, c4, 1) +#define WSYS_ETMVMIDCVR3(val) MSR(val, 2, 1, c3, c6, 1) +#define WSYS_ETMVMIDCVR4(val) MSR(val, 2, 1, c3, c8, 1) +#define WSYS_ETMVMIDCVR5(val) MSR(val, 2, 1, c3, c10, 1) +#define WSYS_ETMVMIDCVR6(val) MSR(val, 2, 1, c3, c12, 1) +#define WSYS_ETMVMIDCVR7(val) MSR(val, 2, 1, c3, c14, 1) +#define WSYS_ETMDVCVR0(val) MSR(val, 2, 1, c2, c0, 4) +#define WSYS_ETMDVCVR1(val) MSR(val, 2, 1, c2, c4, 4) +#define WSYS_ETMDVCVR2(val) MSR(val, 2, 1, c2, c8, 4) +#define WSYS_ETMDVCVR3(val) MSR(val, 2, 1, c2, c12, 4) +#define WSYS_ETMDVCVR4(val) MSR(val, 2, 1, c2, c0, 5) +#define WSYS_ETMDVCVR5(val) MSR(val, 2, 1, c2, c4, 5) +#define WSYS_ETMDVCVR6(val) MSR(val, 2, 1, c2, c8, 5) +#define WSYS_ETMDVCVR7(val) MSR(val, 2, 1, c2, c12, 5) +#define WSYS_ETMDVCMR0(val) MSR(val, 2, 1, c2, c0, 6) +#define WSYS_ETMDVCMR1(val) MSR(val, 2, 1, c2, c4, 6) +#define WSYS_ETMDVCMR2(val) MSR(val, 2, 1, c2, c8, 6) +#define WSYS_ETMDVCMR3(val) MSR(val, 2, 1, c2, c12, 6) +#define WSYS_ETMDVCMR4(val) MSR(val, 2, 1, c2, c0, 7) +#define WSYS_ETMDVCMR5(val) MSR(val, 2, 1, c2, c4, 7) +#define WSYS_ETMDVCMR6(val) MSR(val, 2, 1, c2, c8, 7) +#define WSYS_ETMDVCMR7(val) MSR(val, 2, 1, c2, c12, 7) +#define WSYS_ETMSSCCR0(val) MSR(val, 2, 1, c1, c0, 2) +#define WSYS_ETMSSCCR1(val) MSR(val, 2, 1, c1, c1, 2) +#define WSYS_ETMSSCCR2(val) MSR(val, 2, 1, c1, c2, 2) +#define WSYS_ETMSSCCR3(val) MSR(val, 2, 1, c1, c3, 2) +#define WSYS_ETMSSCCR4(val) MSR(val, 2, 1, c1, c4, 2) +#define WSYS_ETMSSCCR5(val) MSR(val, 2, 1, c1, c5, 2) +#define WSYS_ETMSSCCR6(val) MSR(val, 2, 1, c1, c6, 2) +#define WSYS_ETMSSCCR7(val) MSR(val, 2, 1, c1, c7, 2) +#define WSYS_ETMSSCSR0(val) MSR(val, 2, 1, c1, c8, 2) +#define WSYS_ETMSSCSR1(val) MSR(val, 2, 1, c1, c9, 2) +#define WSYS_ETMSSCSR2(val) MSR(val, 2, 1, c1, c10, 2) +#define WSYS_ETMSSCSR3(val) MSR(val, 2, 1, c1, c11, 2) +#define WSYS_ETMSSCSR4(val) MSR(val, 2, 1, c1, c12, 2) +#define WSYS_ETMSSCSR5(val) MSR(val, 2, 1, c1, c13, 2) +#define WSYS_ETMSSCSR6(val) MSR(val, 2, 1, c1, c14, 2) +#define WSYS_ETMSSCSR7(val) MSR(val, 2, 1, c1, c15, 2) +#define WSYS_ETMSSPCICR0(val) MSR(val, 2, 1, c1, c0, 3) +#define WSYS_ETMSSPCICR1(val) MSR(val, 2, 1, c1, c1, 3) +#define WSYS_ETMSSPCICR2(val) MSR(val, 2, 1, c1, c2, 3) +#define WSYS_ETMSSPCICR3(val) MSR(val, 2, 1, c1, c3, 3) +#define WSYS_ETMSSPCICR4(val) MSR(val, 2, 1, c1, c4, 3) +#define WSYS_ETMSSPCICR5(val) MSR(val, 2, 1, c1, c5, 3) +#define WSYS_ETMSSPCICR6(val) MSR(val, 2, 1, c1, c6, 3) +#define WSYS_ETMSSPCICR7(val) MSR(val, 2, 1, c1, c7, 3) + +#endif diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index caf86be815ba2cfa26d6cbcab8ee1cd7f6bdf158..d8e58051f32d47ab5e93ec389672c1fbc4bf71c8 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -51,6 +51,12 @@ enum fixed_addresses { FIX_EARLYCON_MEM_BASE, FIX_TEXT_POKE0, + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + FIX_ENTRY_TRAMP_DATA, + FIX_ENTRY_TRAMP_TEXT, +#define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT)) +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ __end_of_permanent_fixed_addresses, /* diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h index 7803343e5881fbd7b2f635b25082d3e91d2583f8..77a27af013710de1d4bed56655ee587c5e6ef349 100644 --- a/arch/arm64/include/asm/kernel-pgtable.h +++ b/arch/arm64/include/asm/kernel-pgtable.h @@ -78,8 +78,16 @@ /* * Initial memory map attributes. */ -#define SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) -#define SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) +#define _SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) +#define _SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define SWAPPER_PTE_FLAGS (_SWAPPER_PTE_FLAGS | PTE_NG) +#define SWAPPER_PMD_FLAGS (_SWAPPER_PMD_FLAGS | PMD_SECT_NG) +#else +#define SWAPPER_PTE_FLAGS _SWAPPER_PTE_FLAGS +#define SWAPPER_PMD_FLAGS _SWAPPER_PMD_FLAGS +#endif #if ARM64_SWAPPER_USES_SECTION_MAPS #define SWAPPER_MM_MMUFLAGS (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 2a2752b5b6aa7a424c956d4dd0ec2642644762de..0dbc1c6ab7dc3ef1f1a761a70e75c340133b6ab2 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -170,8 +170,7 @@ #define VTCR_EL2_FLAGS (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN_FLAGS) #define VTTBR_X (VTTBR_X_TGRAN_MAGIC - VTCR_EL2_T0SZ_IPA) -#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_X) #define VTTBR_VMID_SHIFT (UL(48)) #define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index f5ea0ba70f077479ea9b2f4b1cb2fd077e9e20e3..fe39e6841326f01c9ae2d933b8048459c2e8ef6e 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -240,6 +240,12 @@ static inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu) return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE; } +static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu) +{ + u32 esr = kvm_vcpu_get_hsr(vcpu); + return (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; +} + static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu) { return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 6d22017ebbad4b617d4fc69d71f4a9b82bd70dda..35ea9c1206f0e6c0b4db1d90d850c450a4c89a7a 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -47,7 +47,7 @@ * If the page is in the bottom half, we have to use the top half. If * the page is in the top half, we have to use the bottom half: * - * T = __virt_to_phys(__hyp_idmap_text_start) + * T = __pa_symbol(__hyp_idmap_text_start) * if (T & BIT(VA_BITS - 1)) * HYP_VA_MIN = 0 //idmap in upper half * else @@ -270,7 +270,7 @@ static inline void __kvm_flush_dcache_pud(pud_t pud) kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE); } -#define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x)) +#define kvm_virt_to_phys(x) __pa_symbol(x) void kvm_set_way_flush(struct kvm_vcpu *vcpu); void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled); @@ -313,5 +313,43 @@ static inline unsigned int kvm_get_vmid_bits(void) return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8; } +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +#include + +static inline void *kvm_get_hyp_vector(void) +{ + struct bp_hardening_data *data = arm64_get_bp_hardening_data(); + void *vect = kvm_ksym_ref(__kvm_hyp_vector); + + if (data->fn) { + vect = __bp_harden_hyp_vecs_start + + data->hyp_vectors_slot * SZ_2K; + + if (!has_vhe()) + vect = lm_alias(vect); + } + + return vect; +} + +static inline int kvm_map_vectors(void) +{ + return create_hyp_mappings(kvm_ksym_ref(__bp_harden_hyp_vecs_start), + kvm_ksym_ref(__bp_harden_hyp_vecs_end), + PAGE_HYP_EXEC); +} + +#else +static inline void *kvm_get_hyp_vector(void) +{ + return kvm_ksym_ref(__kvm_hyp_vector); +} + +static inline int kvm_map_vectors(void) +{ + return 0; +} +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 53211a0acf0f071e15cfd3c8f66c7fb7806724ba..8fe5ffc1029775e51ce4ba8a79a40deeea576090 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -25,6 +25,7 @@ #include #include #include +#include #include /* @@ -92,15 +93,26 @@ #define KERNEL_END _end /* - * The size of the KASAN shadow region. This should be 1/8th of the - * size of the entire kernel virtual address space. + * KASAN requires 1/8th of the kernel virtual address space for the shadow + * region. KASAN can bloat the stack significantly, so double the (minimum) + * stack size when KASAN is in use. */ #ifdef CONFIG_KASAN #define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - 3)) +#define KASAN_THREAD_SHIFT 1 #else #define KASAN_SHADOW_SIZE (0) +#define KASAN_THREAD_SHIFT 0 #endif +#define THREAD_SHIFT (14 + KASAN_THREAD_SHIFT) + +#if THREAD_SHIFT >= PAGE_SHIFT +#define THREAD_SIZE_ORDER (THREAD_SHIFT - PAGE_SHIFT) +#endif + +#define THREAD_SIZE (UL(1) << THREAD_SHIFT) + /* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h @@ -165,6 +177,11 @@ extern u64 kimage_vaddr; /* the offset between the kernel virtual and physical mappings */ extern u64 kimage_voffset; +static inline unsigned long kaslr_offset(void) +{ + return kimage_vaddr - KIMAGE_VADDR; +} + /* * Allow all memory at the discovery stage. We will clip it later. */ @@ -204,7 +221,8 @@ static inline void *phys_to_virt(phys_addr_t x) #define __pa(x) __virt_to_phys((unsigned long)(x)) #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) -#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys(x)) +#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys((unsigned long)(x))) +#define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x)) /* * virt_to_page(k) convert a _valid_ virtual address to struct page * diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 8d9fce037b2fccd53e4a4340b1d9b4b3c99dff90..f543df3a5921897b9f55c4f40f8227bf8b30545b 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -16,6 +16,13 @@ #ifndef __ASM_MMU_H #define __ASM_MMU_H +#define USER_ASID_FLAG (UL(1) << 48) +#define TTBR_ASID_MASK (UL(0xffff) << 48) + +#ifndef __ASSEMBLY__ + +#include + typedef struct { atomic64_t id; void *vdso; @@ -28,6 +35,49 @@ typedef struct { */ #define ASID(mm) ((mm)->context.id.counter & 0xffff) +static inline bool arm64_kernel_unmapped_at_el0(void) +{ + return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && + cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); +} + +typedef void (*bp_hardening_cb_t)(void); + +struct bp_hardening_data { + int hyp_vectors_slot; + bp_hardening_cb_t fn; +}; + +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[]; + +DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); + +static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) +{ + return raw_cpu_ptr(&bp_hardening_data); +} + +static inline void arm64_apply_bp_hardening(void) +{ + struct bp_hardening_data *d; + + if (!cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) + return; + + d = arm64_get_bp_hardening_data(); + if (d->fn) + d->fn(); +} +#else +static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) +{ + return NULL; +} + +static inline void arm64_apply_bp_hardening(void) { } +#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ + extern void paging_init(void); extern void bootmem_init(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); @@ -37,4 +87,5 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, pgprot_t prot, bool allow_block_mappings); extern void *fixmap_remap_fdt(phys_addr_t dt_phys); +#endif /* !__ASSEMBLY__ */ #endif diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 0363fe80455ce3b0c306b34aa8671d846bcc95bb..af0215ac4d52aab72c4610847ca16c5f8653c07d 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -30,14 +30,20 @@ #include #include #include +#include static inline void contextidr_thread_switch(struct task_struct *next) { + pid_t pid = task_pid_nr(next); + if (!IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR)) return; - write_sysreg(task_pid_nr(next), contextidr_el1); + write_sysreg(pid, contextidr_el1); isb(); + + uncached_logk(LOGK_CTXID, (void *)(u64)pid); + } /* @@ -45,12 +51,19 @@ static inline void contextidr_thread_switch(struct task_struct *next) */ static inline void cpu_set_reserved_ttbr0(void) { - unsigned long ttbr = virt_to_phys(empty_zero_page); + unsigned long ttbr = __pa_symbol(empty_zero_page); write_sysreg(ttbr, ttbr0_el1); isb(); } +static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm) +{ + BUG_ON(pgd == swapper_pg_dir); + cpu_set_reserved_ttbr0(); + cpu_do_switch_mm(virt_to_phys(pgd),mm); +} + /* * TCR.T0SZ value to use when the ID map is active. Usually equals * TCR_T0SZ(VA_BITS), unless system RAM is positioned very high in @@ -114,7 +127,7 @@ static inline void cpu_install_idmap(void) local_flush_tlb_all(); cpu_set_idmap_tcr_t0sz(); - cpu_switch_mm(idmap_pg_dir, &init_mm); + cpu_switch_mm(lm_alias(idmap_pg_dir), &init_mm); } /* @@ -129,7 +142,7 @@ static inline void cpu_replace_ttbr1(pgd_t *pgd) phys_addr_t pgd_phys = virt_to_phys(pgd); - replace_phys = (void *)virt_to_phys(idmap_cpu_replace_ttbr1); + replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1); cpu_install_idmap(); replace_phys(pgd_phys); @@ -150,29 +163,21 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu); #define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; }) -/* - * This is called when "tsk" is about to enter lazy TLB mode. - * - * mm: describes the currently active mm context - * tsk: task which is entering lazy tlb - * cpu: cpu number which is entering lazy tlb - * - * tsk->mm will be NULL - */ -static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) -{ -} - #ifdef CONFIG_ARM64_SW_TTBR0_PAN static inline void update_saved_ttbr0(struct task_struct *tsk, struct mm_struct *mm) { - if (system_uses_ttbr0_pan()) { - BUG_ON(mm->pgd == swapper_pg_dir); - task_thread_info(tsk)->ttbr0 = - virt_to_phys(mm->pgd) | ASID(mm) << 48; - } + u64 ttbr; + + if (!system_uses_ttbr0_pan()) + return; + + if (mm == &init_mm) + ttbr = __pa_symbol(empty_zero_page); + else + ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48; + + task_thread_info(tsk)->ttbr0 = ttbr; } #else static inline void update_saved_ttbr0(struct task_struct *tsk, @@ -181,6 +186,16 @@ static inline void update_saved_ttbr0(struct task_struct *tsk, } #endif +static inline void +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ + /* + * We don't actually care about the ttbr0 mapping, so point it at the + * zero page. + */ + update_saved_ttbr0(tsk, &init_mm); +} + static inline void __switch_mm(struct mm_struct *next) { unsigned int cpu = smp_processor_id(); @@ -208,11 +223,9 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, * Update the saved TTBR0_EL1 of the scheduled-in task as the previous * value may have not been initialised yet (activate_mm caller) or the * ASID has changed since the last run (following the context switch - * of another thread of the same process). Avoid setting the reserved - * TTBR0_EL1 to swapper_pg_dir (init_mm; e.g. via idle_task_exit). + * of another thread of the same process). */ - if (next != &init_mm) - update_saved_ttbr0(tsk, next); + update_saved_ttbr0(tsk, next); } #define deactivate_mm(tsk,mm) do { } while (0) diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index 06ff7fd9e81feab27bb67f1a4af971ddc0ebf4cc..b6c6fa29fe56a57c0446810583e34b6719ca2fc2 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -22,14 +22,19 @@ #define MODULE_ARCH_VERMAGIC "aarch64" #ifdef CONFIG_ARM64_MODULE_PLTS -struct mod_arch_specific { +struct mod_plt_sec { struct elf64_shdr *plt; int plt_num_entries; int plt_max_entries; }; + +struct mod_arch_specific { + struct mod_plt_sec core; + struct mod_plt_sec init; +}; #endif -u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela, +u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela, Elf64_Sym *sym); #ifdef CONFIG_RANDOMIZE_BASE diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 5394c8405e6604bf612fd0c639c1f15a30d0f7d9..d7a3c6294224141545d04787c27bb4d1be477841 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -16,6 +16,8 @@ #ifndef __ASM_PERCPU_H #define __ASM_PERCPU_H +#include + static inline void set_my_cpu_offset(unsigned long off) { asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 38b6a2b49d6895dbd7904a27792520514d445044..8d5cbec17d803e37556b5f4a7b25e7b4f1391b35 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -17,6 +17,8 @@ #ifndef __ASM_PERF_EVENT_H #define __ASM_PERF_EVENT_H +#include + #define ARMV8_PMU_MAX_COUNTERS 32 #define ARMV8_PMU_COUNTER_MASK (ARMV8_PMU_MAX_COUNTERS - 1) diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index eb0c2bd90de903469790a66c6d7f528af64c9d76..8df4cb6ac6f71e963031268e3c30246f04bf0914 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -272,6 +272,7 @@ #define TCR_TG1_4K (UL(2) << TCR_TG1_SHIFT) #define TCR_TG1_64K (UL(3) << TCR_TG1_SHIFT) +#define TCR_A1 (UL(1) << 22) #define TCR_ASID16 (UL(1) << 36) #define TCR_TBI0 (UL(1) << 37) #define TCR_HA (UL(1) << 39) diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 2142c7726e76d048dd61f4322977832a69da4733..84b5283d2e7feb0392af2a4f168396616e31623b 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -34,8 +34,16 @@ #include -#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) -#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) +#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) +#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define PROT_DEFAULT (_PROT_DEFAULT | PTE_NG) +#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_SECT_NG) +#else +#define PROT_DEFAULT _PROT_DEFAULT +#define PROT_SECT_DEFAULT _PROT_SECT_DEFAULT +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ #define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE)) @@ -48,6 +56,7 @@ #define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) #define _PAGE_DEFAULT (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) +#define _HYP_PAGE_DEFAULT (_PAGE_DEFAULT & ~PTE_NG) #define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY) @@ -55,15 +64,15 @@ #define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT) -#define PAGE_HYP __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN) -#define PAGE_HYP_EXEC __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY) -#define PAGE_HYP_RO __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) +#define PAGE_HYP __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN) +#define PAGE_HYP_EXEC __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY) +#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) #define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP) #define PAGE_S2 __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY) #define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN) -#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_PXN | PTE_UXN) +#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_NG | PTE_PXN | PTE_UXN) #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) #define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) #define PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index ffbb9a52056314225bfe5e119830d3a0170b8ad5..9f1bba6218299cc1433ef3b01b62847d62de3dd4 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -52,7 +53,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val); * for zero-mapped memory areas etc.. */ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) pfn_to_page(PHYS_PFN(__pa(empty_zero_page))) +#define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page)) #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) @@ -71,9 +72,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_young(pte) (!!(pte_val(pte) & PTE_AF)) #define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL)) #define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE)) -#define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) +#define pte_user_exec(pte) (!(pte_val(pte) & PTE_UXN)) #define pte_cont(pte) (!!(pte_val(pte) & PTE_CONT)) -#define pte_ng(pte) (!!(pte_val(pte) & PTE_NG)) #ifdef CONFIG_ARM64_HW_AFDBM #define pte_hw_dirty(pte) (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY)) @@ -84,10 +84,16 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte)) #define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID)) -#define pte_valid_global(pte) \ - ((pte_val(pte) & (PTE_VALID | PTE_NG)) == PTE_VALID) +/* + * Execute-only user mappings do not have the PTE_USER bit set. All valid + * kernel mappings have the PTE_UXN bit set. + */ +#define pte_valid_not_user(pte) \ + ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == (PTE_VALID | PTE_UXN)) #define pte_valid_young(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF)) +#define pte_valid_user(pte) \ + ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) /* * Could the pte be present in the TLB? We must check mm_tlb_flush_pending @@ -97,6 +103,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define pte_accessible(mm, pte) \ (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte)) +/* + * p??_access_permitted() is true for valid user mappings (subject to the + * write permission check) other than user execute-only which do not have the + * PTE_USER bit set. PROT_NONE mappings do not have the PTE_VALID bit set. + */ +#define pte_access_permitted(pte, write) \ + (pte_valid_user(pte) && (!(write) || pte_write(pte))) +#define pmd_access_permitted(pmd, write) \ + (pte_access_permitted(pmd_pte(pmd), (write))) +#define pud_access_permitted(pud, write) \ + (pte_access_permitted(pud_pte(pud), (write))) + static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot) { pte_val(pte) &= ~pgprot_val(prot); @@ -172,13 +190,41 @@ static inline pmd_t pmd_mkcont(pmd_t pmd) static inline void set_pte(pte_t *ptep, pte_t pte) { +#ifdef CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE + pteval_t old = pte_val(*ptep); + pteval_t new = pte_val(pte); + + /* Only problematic if valid -> valid */ + if (!(old & new & PTE_VALID)) + goto pte_ok; + + /* Changing attributes should go via an invalid entry */ + if (WARN_ON((old & PTE_ATTRINDX_MASK) != (new & PTE_ATTRINDX_MASK))) + goto pte_bad; + + /* Change of OA is only an issue if one mapping is writable */ + if (!(old & new & PTE_RDONLY) && + WARN_ON(pte_pfn(*ptep) != pte_pfn(pte))) + goto pte_bad; + + goto pte_ok; + +pte_bad: + *ptep = __pte(0); + dsb(ishst); + asm("tlbi vmalle1is"); + dsb(ish); + isb(); +pte_ok: +#endif + *ptep = pte; /* * Only if the new pte is valid and kernel, otherwise TLB maintenance * or update_mmu_cache() have the necessary barriers. */ - if (pte_valid_global(pte)) { + if (pte_valid_not_user(pte)) { dsb(ishst); isb(); } @@ -212,7 +258,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_val(pte) &= ~PTE_RDONLY; else pte_val(pte) |= PTE_RDONLY; - if (pte_ng(pte) && pte_exec(pte) && !pte_special(pte)) + if (pte_user_exec(pte) && !pte_special(pte)) __sync_icache_dcache(pte, addr); } @@ -675,6 +721,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; +extern pgd_t tramp_pg_dir[PTRS_PER_PGD]; /* * Encode and decode a swap entry: diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h index 220633b791b819b3346d36d0ff0a959c4dfbef02..9da52c2c6c5c355c8fee5a0e5ee29b6794c5e35d 100644 --- a/arch/arm64/include/asm/proc-fns.h +++ b/arch/arm64/include/asm/proc-fns.h @@ -39,12 +39,6 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr); #include -#define cpu_switch_mm(pgd,mm) \ -do { \ - BUG_ON(pgd == swapper_pg_dir); \ - cpu_do_switch_mm(virt_to_phys(pgd),mm); \ -} while (0) - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* __ASM_PROCFNS_H */ diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 022644704a936dce53bb933f9bf6635835e32530..d050d720a1b453785738d80acc5b0af1e2ec39ef 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -29,11 +29,22 @@ #ifndef __ASSEMBLY__ +#include + #include #include #include -#define raw_smp_processor_id() (current_thread_info()->cpu) +DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number); + +/* + * We don't use this_cpu_read(cpu_number) as that has implicit writes to + * preempt_count, and associated (compiler) barriers, that we'd like to avoid + * the expense of. If we're preemptible, the value can be stale at use anyway. + * And we can't use this_cpu_ptr() either, as that winds up recursing back + * here under CONFIG_DEBUG_PREEMPT=y. + */ +#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number)) struct seq_file; @@ -73,6 +84,7 @@ asmlinkage void secondary_start_kernel(void); */ struct secondary_data { void *stack; + struct task_struct *task; long status; }; diff --git a/arch/arm64/include/asm/stack_pointer.h b/arch/arm64/include/asm/stack_pointer.h new file mode 100644 index 0000000000000000000000000000000000000000..ffcdf742cddf931e6ee0b5fcb52c5bd535d2249f --- /dev/null +++ b/arch/arm64/include/asm/stack_pointer.h @@ -0,0 +1,9 @@ +#ifndef __ASM_STACK_POINTER_H +#define __ASM_STACK_POINTER_H + +/* + * how to get the current stack pointer from C + */ +register unsigned long current_stack_pointer asm ("sp"); + +#endif /* __ASM_STACK_POINTER_H */ diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h index fe5e287dc56b7263f40146208956ee203bcd080e..b86a0865ddf16a020ca2e5cf727d92878860d4d9 100644 --- a/arch/arm64/include/asm/stackprotector.h +++ b/arch/arm64/include/asm/stackprotector.h @@ -30,6 +30,7 @@ static __always_inline void boot_init_stack_canary(void) /* Try to get a semi random initial value. */ get_random_bytes(&canary, sizeof(canary)); canary ^= LINUX_VERSION_CODE; + canary &= CANARY_MASK; current->stack_canary = canary; __stack_chk_guard = current->stack_canary; diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h index 2eb714c4639f5669b1012aae0c77ca74fdb72881..d0aa42907569beb95142f205c03bc1f21b9bae88 100644 --- a/arch/arm64/include/asm/string.h +++ b/arch/arm64/include/asm/string.h @@ -63,6 +63,11 @@ extern int memcmp(const void *, const void *, size_t); #define memcpy(dst, src, len) __memcpy(dst, src, len) #define memmove(dst, src, len) __memmove(dst, src, len) #define memset(s, c, n) __memset(s, c, n) + +#ifndef __NO_FORTIFY +#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ +#endif + #endif #endif diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index b8a313fd7a093e7ee874c9e75f5eab9a4c338d91..de5600f40adfcb8185abb56461d4d9f3846a1d88 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h @@ -1,7 +1,7 @@ #ifndef __ASM_SUSPEND_H #define __ASM_SUSPEND_H -#define NR_CTX_REGS 10 +#define NR_CTX_REGS 12 #define NR_CALLEE_SAVED_REGS 12 /* diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 6c80b3699cb8a18c076634f710e031a5b3505647..88bbe364b6ae005cbec57a7394b6198e6c2df19c 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -94,6 +94,10 @@ #define SCTLR_ELx_A (1 << 1) #define SCTLR_ELx_M 1 +#define SCTLR_EL2_RES1 ((1 << 4) | (1 << 5) | (1 << 11) | (1 << 16) | \ + (1 << 16) | (1 << 18) | (1 << 22) | (1 << 23) | \ + (1 << 28) | (1 << 29)) + #define SCTLR_ELx_FLAGS (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | \ SCTLR_ELx_SA | SCTLR_ELx_I) @@ -113,6 +117,9 @@ #define ID_AA64ISAR0_AES_SHIFT 4 /* id_aa64pfr0 */ +#define ID_AA64PFR0_CSV3_SHIFT 60 +#define ID_AA64PFR0_CSV2_SHIFT 56 +#define ID_AA64PFR0_SVE_SHIFT 32 #define ID_AA64PFR0_GIC_SHIFT 24 #define ID_AA64PFR0_ASIMD_SHIFT 20 #define ID_AA64PFR0_FP_SHIFT 16 diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h index b64410c7ddd8a34cc32479e002230ad8f60deddd..96c11e7650755dce3a2b60c775127431463008e5 100644 --- a/arch/arm64/include/asm/system_misc.h +++ b/arch/arm64/include/asm/system_misc.h @@ -46,6 +46,8 @@ extern void __show_regs(struct pt_regs *); extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); extern char* (*arch_read_hardware_id)(void); +const char * __init arch_read_machine_name(void); + #define show_unhandled_signals_ratelimited() \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 4ad25a5245c45dec8772f95e31d2b092aebe25c4..ba3a69acf4177ca618a45f26fec24168a9086a1f 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -23,74 +23,38 @@ #include -#ifdef CONFIG_ARM64_4K_PAGES -#define THREAD_SIZE_ORDER 2 -#elif defined(CONFIG_ARM64_16K_PAGES) -#define THREAD_SIZE_ORDER 0 -#endif - -#define THREAD_SIZE 16384 #define THREAD_START_SP (THREAD_SIZE - 16) #ifndef __ASSEMBLY__ struct task_struct; +#include +#include #include typedef unsigned long mm_segment_t; /* * low level task data that entry.S needs immediate access to. - * __switch_to() assumes cpu_context follows immediately after cpu_domain. */ struct thread_info { unsigned long flags; /* low level flags */ mm_segment_t addr_limit; /* address limit */ - struct task_struct *task; /* main task structure */ #ifdef CONFIG_ARM64_SW_TTBR0_PAN u64 ttbr0; /* saved TTBR0_EL1 */ #endif int preempt_count; /* 0 => preemptable, <0 => bug */ - int cpu; /* cpu */ }; #define INIT_THREAD_INFO(tsk) \ { \ - .task = &tsk, \ - .flags = 0, \ .preempt_count = INIT_PREEMPT_COUNT, \ .addr_limit = KERNEL_DS, \ } -#define init_thread_info (init_thread_union.thread_info) #define init_stack (init_thread_union.stack) -/* - * how to get the current stack pointer from C - */ -register unsigned long current_stack_pointer asm ("sp"); - -/* - * how to get the thread information struct from C - */ -static inline struct thread_info *current_thread_info(void) __attribute_const__; - -/* - * struct thread_info can be accessed directly via sp_el0. - * - * We don't use read_sysreg() as we want the compiler to cache the value where - * possible. - */ -static inline struct thread_info *current_thread_info(void) -{ - unsigned long sp_el0; - - asm ("mrs %0, sp_el0" : "=r" (sp_el0)); - - return (struct thread_info *)sp_el0; -} - #define thread_saved_pc(tsk) \ ((unsigned long)(tsk->thread.cpu_context.pc)) #define thread_saved_sp(tsk) \ diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index deab523741197684dcaac73ae57a8add2d4217b6..ad6bd8b26ada0e42956a7c6496da536f804fc694 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -23,6 +23,7 @@ #include #include +#include /* * Raw TLBI operations. @@ -42,6 +43,11 @@ #define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0) +#define __tlbi_user(op, arg) do { \ + if (arm64_kernel_unmapped_at_el0()) \ + __tlbi(op, (arg) | USER_ASID_FLAG); \ +} while (0) + /* * TLB Management * ============== @@ -103,6 +109,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm) dsb(ishst); __tlbi(aside1is, asid); + __tlbi_user(aside1is, asid); dsb(ish); } @@ -113,6 +120,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, dsb(ishst); __tlbi(vale1is, addr); + __tlbi_user(vale1is, addr); dsb(ish); } @@ -139,10 +147,13 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, dsb(ishst); for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) { - if (last_level) + if (last_level) { __tlbi(vale1is, addr); - else + __tlbi_user(vale1is, addr); + } else { __tlbi(vae1is, addr); + __tlbi_user(vae1is, addr); + } } dsb(ish); } @@ -182,6 +193,7 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm, unsigned long addr = uaddr >> 12 | (ASID(mm) << 48); __tlbi(vae1is, addr); + __tlbi_user(vae1is, addr); dsb(ish); } diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 61e032f22e710c88d44ec42ac5752a2f02313422..b58f4299c6225548303fc46208f6f4b03eb0b437 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -41,6 +41,9 @@ extern unsigned long cpufreq_scale_max_freq_capacity(int cpu); #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); +#define arch_update_cpu_capacity update_cpu_power_capacity +extern void update_cpu_power_capacity(int cpu); + #include #endif /* _ASM_ARM_TOPOLOGY_H */ diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 73fee2c050905dca02c6104dca0d4cac95e3add2..8b38b0de3e8bb02e27f613355e93b82a7aef9fcf 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -20,6 +20,7 @@ #include #include +#include #include #ifndef __ASSEMBLY__ @@ -98,20 +99,21 @@ static inline void set_fs(mm_segment_t fs) */ #define __range_ok(addr, size) \ ({ \ + unsigned long __addr = (unsigned long __force)(addr); \ unsigned long flag, roksum; \ __chk_user_ptr(addr); \ asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \ : "=&r" (flag), "=&r" (roksum) \ - : "1" (addr), "Ir" (size), \ + : "1" (__addr), "Ir" (size), \ "r" (current_thread_info()->addr_limit) \ : "cc"); \ flag; \ }) /* - * When dealing with data aborts or instruction traps we may end up with - * a tagged userland pointer. Clear the tag to get a sane pointer to pass - * on to access_ok(), for instance. + * When dealing with data aborts, watchpoints, or instruction traps we may end + * up with a tagged userland pointer. Clear the tag to get a sane pointer to + * pass on to access_ok(), for instance. */ #define untagged_addr(addr) sign_extend64(addr, 55) @@ -132,15 +134,19 @@ static inline void __uaccess_ttbr0_disable(void) { unsigned long ttbr; + ttbr = read_sysreg(ttbr1_el1); /* reserved_ttbr0 placed at the end of swapper_pg_dir */ - ttbr = read_sysreg(ttbr1_el1) + SWAPPER_DIR_SIZE; - write_sysreg(ttbr, ttbr0_el1); + write_sysreg(ttbr + SWAPPER_DIR_SIZE, ttbr0_el1); + isb(); + /* Set reserved ASID */ + ttbr &= ~TTBR_ASID_MASK; + write_sysreg(ttbr, ttbr1_el1); isb(); } static inline void __uaccess_ttbr0_enable(void) { - unsigned long flags; + unsigned long flags, ttbr0, ttbr1; /* * Disable interrupts to avoid preemption between reading the 'ttbr0' @@ -148,7 +154,16 @@ static inline void __uaccess_ttbr0_enable(void) * roll-over and an update of 'ttbr0'. */ local_irq_save(flags); - write_sysreg(current_thread_info()->ttbr0, ttbr0_el1); + ttbr0 = current_thread_info()->ttbr0; + + /* Restore active ASID */ + ttbr1 = read_sysreg(ttbr1_el1); + ttbr1 |= ttbr0 & TTBR_ASID_MASK; + write_sysreg(ttbr1, ttbr1_el1); + isb(); + + /* Restore user page table */ + write_sysreg(ttbr0, ttbr0_el1); isb(); local_irq_restore(flags); } @@ -382,9 +397,9 @@ static inline unsigned long __must_check copy_from_user(void *to, const void __u { unsigned long res = n; kasan_check_write(to, n); + check_object_size(to, n, false); if (access_ok(VERIFY_READ, from, n)) { - check_object_size(to, n, false); res = __arch_copy_from_user(to, from, n); } if (unlikely(res)) @@ -395,9 +410,9 @@ static inline unsigned long __must_check copy_from_user(void *to, const void __u static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { kasan_check_read(from, n); + check_object_size(from, n, true); if (access_ok(VERIFY_WRITE, to, n)) { - check_object_size(from, n, true); n = __arch_copy_to_user(to, from, n); } return n; @@ -438,11 +453,20 @@ extern __must_check long strnlen_user(const char __user *str, long n); add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1 isb + sub \tmp1, \tmp1, #SWAPPER_DIR_SIZE + bic \tmp1, \tmp1, #TTBR_ASID_MASK + msr ttbr1_el1, \tmp1 // set reserved ASID + isb .endm - .macro __uaccess_ttbr0_enable, tmp1 + .macro __uaccess_ttbr0_enable, tmp1, tmp2 get_thread_info \tmp1 ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1 + mrs \tmp2, ttbr1_el1 + extr \tmp2, \tmp2, \tmp1, #48 + ror \tmp2, \tmp2, #16 + msr ttbr1_el1, \tmp2 // set the active ASID + isb msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1 isb .endm @@ -453,18 +477,18 @@ alternative_if_not ARM64_HAS_PAN alternative_else_nop_endif .endm - .macro uaccess_ttbr0_enable, tmp1, tmp2 + .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3 alternative_if_not ARM64_HAS_PAN - save_and_disable_irq \tmp2 // avoid preemption - __uaccess_ttbr0_enable \tmp1 - restore_irq \tmp2 + save_and_disable_irq \tmp3 // avoid preemption + __uaccess_ttbr0_enable \tmp1, \tmp2 + restore_irq \tmp3 alternative_else_nop_endif .endm #else .macro uaccess_ttbr0_disable, tmp1 .endm - .macro uaccess_ttbr0_enable, tmp1, tmp2 + .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3 .endm #endif @@ -478,8 +502,8 @@ alternative_if ARM64_ALT_PAN_NOT_UAO alternative_else_nop_endif .endm - .macro uaccess_enable_not_uao, tmp1, tmp2 - uaccess_ttbr0_enable \tmp1, \tmp2 + .macro uaccess_enable_not_uao, tmp1, tmp2, tmp3 + uaccess_ttbr0_enable \tmp1, \tmp2, \tmp3 alternative_if ARM64_ALT_PAN_NOT_UAO SET_PSTATE_PAN(0) alternative_else_nop_endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 2c03b01816003b48fb95a519ee90eb16b045e1f5..446eabd3bc2a26fd5dd763cf3a5667b9cefeded3 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -52,6 +52,10 @@ arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ cpu-reset.o +ifeq ($(CONFIG_KVM),y) +arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o +endif + obj-y += $(arm64-obj-y) vdso/ probes/ obj-m += $(arm64-obj-m) head-y := head.o diff --git a/arch/arm64/kernel/acpi_parking_protocol.c b/arch/arm64/kernel/acpi_parking_protocol.c index a32b4011d711c42d033c7675a87686bfa33d867c..1f5655cd9cc93280b92417370be49c808fe3bb1d 100644 --- a/arch/arm64/kernel/acpi_parking_protocol.c +++ b/arch/arm64/kernel/acpi_parking_protocol.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ #include +#include #include #include @@ -109,7 +110,7 @@ static int acpi_parking_protocol_cpu_boot(unsigned int cpu) * that read this address need to convert this address to the * Boot-Loader's endianness before jumping. */ - writeq_relaxed(__pa(secondary_entry), &mailbox->entry_point); + writeq_relaxed(__pa_symbol(secondary_entry), &mailbox->entry_point); writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id); arch_send_wakeup_ipi_mask(cpumask_of(cpu)); diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index bdb35b92003e25af57bbc35f1fede1ae498f1cd9..29d2ad8844a50c99ffb4dd520db89ebd6906dc59 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -306,7 +306,8 @@ do { \ _ASM_EXTABLE(0b, 4b) \ _ASM_EXTABLE(1b, 4b) \ : "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \ - : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT), \ + : "r" ((unsigned long)addr), "i" (-EAGAIN), \ + "i" (-EFAULT), \ "i" (__SWP_LL_SC_LOOPS) \ : "memory"); \ uaccess_disable(); \ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 5cdbc5557b68eee4285d1e358a7f8a82a9c42731..5d2d3560f18694188cf057b376226d408cd3c56d 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -36,17 +37,13 @@ int main(void) { DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); BLANK(); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); + DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); + DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); + DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); #ifdef CONFIG_ARM64_SW_TTBR0_PAN - DEFINE(TI_TTBR0, offsetof(struct thread_info, ttbr0)); -#endif - DEFINE(TI_TASK, offsetof(struct thread_info, task)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); -#ifdef CONFIG_ARM64_SW_TTBR0_PAN - DEFINE(TSK_TI_TTBR0, offsetof(struct thread_info, ttbr0)); + DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0)); #endif + DEFINE(TSK_STACK, offsetof(struct task_struct, stack)); BLANK(); DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context)); BLANK(); @@ -129,6 +126,7 @@ int main(void) DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); BLANK(); DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack)); + DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); BLANK(); #ifdef CONFIG_KVM_ARM_HOST DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt)); @@ -150,11 +148,14 @@ int main(void) DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); - BLANK(); DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address)); DEFINE(HIBERN_PBE_NEXT, offsetof(struct pbe, next)); DEFINE(ARM64_FTR_SYSVAL, offsetof(struct arm64_ftr_reg, sys_val)); + BLANK(); +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + DEFINE(TRAMP_VALIAS, TRAMP_VALIAS); +#endif return 0; } diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S new file mode 100644 index 0000000000000000000000000000000000000000..dec95bd82e319e9fe3e701d602d532f1b2508227 --- /dev/null +++ b/arch/arm64/kernel/bpi.S @@ -0,0 +1,79 @@ +/* + * Contains CPU specific branch predictor invalidation sequences + * + * Copyright (C) 2018 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +.macro ventry target + .rept 31 + nop + .endr + b \target +.endm + +.macro vectors target + ventry \target + 0x000 + ventry \target + 0x080 + ventry \target + 0x100 + ventry \target + 0x180 + + ventry \target + 0x200 + ventry \target + 0x280 + ventry \target + 0x300 + ventry \target + 0x380 + + ventry \target + 0x400 + ventry \target + 0x480 + ventry \target + 0x500 + ventry \target + 0x580 + + ventry \target + 0x600 + ventry \target + 0x680 + ventry \target + 0x700 + ventry \target + 0x780 +.endm + + .align 11 +ENTRY(__bp_harden_hyp_vecs_start) + .rept 4 + vectors __kvm_hyp_vector + .endr +ENTRY(__bp_harden_hyp_vecs_end) +ENTRY(__psci_hyp_bp_inval_start) + sub sp, sp, #(8 * 18) + stp x16, x17, [sp, #(16 * 0)] + stp x14, x15, [sp, #(16 * 1)] + stp x12, x13, [sp, #(16 * 2)] + stp x10, x11, [sp, #(16 * 3)] + stp x8, x9, [sp, #(16 * 4)] + stp x6, x7, [sp, #(16 * 5)] + stp x4, x5, [sp, #(16 * 6)] + stp x2, x3, [sp, #(16 * 7)] + stp x0, x1, [sp, #(16 * 8)] + mov x0, #0x84000000 + smc #0 + ldp x16, x17, [sp, #(16 * 0)] + ldp x14, x15, [sp, #(16 * 1)] + ldp x12, x13, [sp, #(16 * 2)] + ldp x10, x11, [sp, #(16 * 3)] + ldp x8, x9, [sp, #(16 * 4)] + ldp x6, x7, [sp, #(16 * 5)] + ldp x4, x5, [sp, #(16 * 6)] + ldp x2, x3, [sp, #(16 * 7)] + ldp x0, x1, [sp, #(16 * 8)] + add sp, sp, #(8 * 18) +ENTRY(__psci_hyp_bp_inval_end) diff --git a/arch/arm64/kernel/cpu-reset.h b/arch/arm64/kernel/cpu-reset.h index d4e9ecb264f00d6f37bf2ecdb4436fd1a88fed0c..6c2b1b4f57c9a457a75209428647061273014dc1 100644 --- a/arch/arm64/kernel/cpu-reset.h +++ b/arch/arm64/kernel/cpu-reset.h @@ -24,7 +24,7 @@ static inline void __noreturn cpu_soft_restart(unsigned long el2_switch, el2_switch = el2_switch && !is_kernel_in_hyp_mode() && is_hyp_mode_available(); - restart = (void *)virt_to_phys(__cpu_soft_restart); + restart = (void *)__pa_symbol(__cpu_soft_restart); cpu_install_idmap(); restart(el2_switch, entry, arg0, arg1, arg2); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index b75e917aac464290b523e1b3cc8cd7822364eeb7..653359ba55bfe9c7ce7c71897c8c90cc99703cfe 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -46,6 +46,100 @@ static int cpu_enable_trap_ctr_access(void *__unused) return 0; } +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +#include +#include + +DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); + +#ifdef CONFIG_KVM +extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; + +static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K); + int i; + + for (i = 0; i < SZ_2K; i += 0x80) + memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start); + + flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); +} + +static void __install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + static int last_slot = -1; + static DEFINE_SPINLOCK(bp_lock); + int cpu, slot = -1; + + spin_lock(&bp_lock); + for_each_possible_cpu(cpu) { + if (per_cpu(bp_hardening_data.fn, cpu) == fn) { + slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu); + break; + } + } + + if (slot == -1) { + last_slot++; + BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start) + / SZ_2K) <= last_slot); + slot = last_slot; + __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end); + } + + __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot); + __this_cpu_write(bp_hardening_data.fn, fn); + spin_unlock(&bp_lock); +} +#else +#define __psci_hyp_bp_inval_start NULL +#define __psci_hyp_bp_inval_end NULL + +static void __install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + __this_cpu_write(bp_hardening_data.fn, fn); +} +#endif /* CONFIG_KVM */ + +static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, + bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + u64 pfr0; + + if (!entry->matches(entry, SCOPE_LOCAL_CPU)) + return; + + pfr0 = read_cpuid(ID_AA64PFR0_EL1); + if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) + return; + + __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); +} + +#include + +static int enable_psci_bp_hardening(void *data) +{ + const struct arm64_cpu_capabilities *entry = data; + + if (psci_ops.get_version) + install_bp_hardening_cb(entry, + (bp_hardening_cb_t)psci_ops.get_version, + __psci_hyp_bp_inval_start, + __psci_hyp_bp_inval_end); + + return 0; +} +#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ + #define MIDR_RANGE(model, min, max) \ .def_scope = SCOPE_LOCAL_CPU, \ .matches = is_affected_midr_range, \ @@ -53,6 +147,13 @@ static int cpu_enable_trap_ctr_access(void *__unused) .midr_range_min = min, \ .midr_range_max = max +#define MIDR_ALL_VERSIONS(model) \ + .def_scope = SCOPE_LOCAL_CPU, \ + .matches = is_affected_midr_range, \ + .midr_model = model, \ + .midr_range_min = 0, \ + .midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK) + const struct arm64_cpu_capabilities arm64_errata[] = { #if defined(CONFIG_ARM64_ERRATUM_826319) || \ defined(CONFIG_ARM64_ERRATUM_827319) || \ @@ -130,6 +231,33 @@ const struct arm64_cpu_capabilities arm64_errata[] = { .def_scope = SCOPE_LOCAL_CPU, .enable = cpu_enable_trap_ctr_access, }, +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_KRYO3G), + .enable = enable_psci_bp_hardening, + }, +#endif { } }; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index af5a1e34fb07b7aec8fae37068adc461efd6f993..80ff3df5f667f48dedf71495d467c5d7ad93a59a 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,7 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = { ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI), + ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0), /* Linux doesn't care about the EL3 */ ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0), @@ -737,7 +739,7 @@ static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry, int __unused) { - phys_addr_t idmap_addr = virt_to_phys(__hyp_idmap_text_start); + phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start); /* * Activate the lower HYP offset only if: @@ -747,6 +749,44 @@ static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry, return idmap_addr > GENMASK(VA_BITS - 2, 0) && !is_kernel_in_hyp_mode(); } +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ + +static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, + int __unused) +{ + u64 pfr0 = read_system_reg(SYS_ID_AA64PFR0_EL1); + + /* Forced on command line? */ + if (__kpti_forced) { + pr_info_once("kernel page table isolation forced %s by command line option\n", + __kpti_forced > 0 ? "ON" : "OFF"); + return __kpti_forced > 0; + } + + /* Useful for KASLR robustness */ + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) + return true; + + /* Defer to CPU feature registers */ + return !cpuid_feature_extract_unsigned_field(pfr0, + ID_AA64PFR0_CSV3_SHIFT); +} + +static int __init parse_kpti(char *str) +{ + bool enabled; + int ret = strtobool(str, &enabled); + + if (ret) + return ret; + + __kpti_forced = enabled ? 1 : -1; + return 0; +} +__setup("kpti=", parse_kpti); +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -830,6 +870,14 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .def_scope = SCOPE_SYSTEM, .matches = hyp_offset_low, }, +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + { + .desc = "Kernel page table isolation (KPTI)", + .capability = ARM64_UNMAP_KERNEL_AT_EL0, + .def_scope = SCOPE_SYSTEM, + .matches = unmap_kernel_at_el0, + }, +#endif {}, }; @@ -950,7 +998,7 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) * uses an IPI, giving us a PSTATE that disappears when * we return. */ - stop_machine(caps->enable, NULL, cpu_online_mask); + stop_machine(caps->enable, (void *)caps, cpu_online_mask); } /* @@ -1006,7 +1054,7 @@ verify_local_cpu_features(const struct arm64_cpu_capabilities *caps) cpu_die_early(); } if (caps->enable) - caps->enable(NULL); + caps->enable((void *)caps); } } diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 1f0cea724f6e4df20bdf6e3aa7736b61932401d2..80305830e6eacdccb8173d2963d3a86513ea61ad 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -29,9 +29,11 @@ #include #include #include +#include #include #include #include +#include #include /* @@ -69,8 +71,31 @@ #define BAD_FIQ 2 #define BAD_ERROR 3 - .macro kernel_entry, el, regsize = 64 + .macro kernel_ventry, el, label, regsize = 64 + .align 7 +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +alternative_if ARM64_UNMAP_KERNEL_AT_EL0 + .if \el == 0 + .if \regsize == 64 + mrs x30, tpidrro_el0 + msr tpidrro_el0, xzr + .else + mov x30, xzr + .endif + .endif +alternative_else_nop_endif +#endif + sub sp, sp, #S_FRAME_SIZE + b el\()\el\()_\label + .endm + + .macro tramp_alias, dst, sym + mov_q \dst, TRAMP_VALIAS + add \dst, \dst, #(\sym - .entry.tramp.text) + .endm + + .macro kernel_entry, el, regsize = 64 .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0 .endif @@ -92,9 +117,8 @@ .if \el == 0 mrs x21, sp_el0 - mov tsk, sp - and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear, - ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug + ldr_this_cpu tsk, __entry_task, x20 // Ensure MDSCR_EL1.SS is clear, + ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug disable_step_tsk x19, x20 // exceptions when scheduling. mov x29, xzr // fp pointed to user-space @@ -102,10 +126,10 @@ add x21, sp, #S_FRAME_SIZE get_thread_info tsk /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */ - ldr x20, [tsk, #TI_ADDR_LIMIT] + ldr x20, [tsk, #TSK_TI_ADDR_LIMIT] str x20, [sp, #S_ORIG_ADDR_LIMIT] mov x20, #TASK_SIZE_64 - str x20, [tsk, #TI_ADDR_LIMIT] + str x20, [tsk, #TSK_TI_ADDR_LIMIT] /* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */ .endif /* \el == 0 */ mrs x22, elr_el1 @@ -126,8 +150,8 @@ alternative_if ARM64_HAS_PAN alternative_else_nop_endif .if \el != 0 - mrs x21, ttbr0_el1 - tst x21, #0xffff << 48 // Check for the reserved ASID + mrs x21, ttbr1_el1 + tst x21, #TTBR_ASID_MASK // Check for the reserved ASID orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR b.eq 1f // TTBR0 access already disabled and x23, x23, #~PSR_PAN_BIT // Clear the emulated PAN in the saved SPSR @@ -167,7 +191,7 @@ alternative_else_nop_endif .if \el != 0 /* Restore the task's original addr_limit. */ ldr x20, [sp, #S_ORIG_ADDR_LIMIT] - str x20, [tsk, #TI_ADDR_LIMIT] + str x20, [tsk, #TSK_TI_ADDR_LIMIT] /* No need to restore UAO, it will be restored from SPSR_EL1 */ .endif @@ -190,7 +214,7 @@ alternative_else_nop_endif tbnz x22, #22, 1f // Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set .endif - __uaccess_ttbr0_enable x0 + __uaccess_ttbr0_enable x0, x1 .if \el == 0 /* @@ -199,7 +223,7 @@ alternative_else_nop_endif * Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache * corruption). */ - post_ttbr0_update_workaround + bl post_ttbr_update_workaround .endif 1: .if \el != 0 @@ -211,18 +235,20 @@ alternative_else_nop_endif .if \el == 0 ldr x23, [sp, #S_SP] // load return stack pointer msr sp_el0, x23 + tst x22, #PSR_MODE32_BIT // native task? + b.eq 3f + #ifdef CONFIG_ARM64_ERRATUM_845719 alternative_if ARM64_WORKAROUND_845719 - tbz x22, #4, 1f #ifdef CONFIG_PID_IN_CONTEXTIDR mrs x29, contextidr_el1 msr contextidr_el1, x29 #else msr contextidr_el1, xzr #endif -1: alternative_else_nop_endif #endif +3: .endif msr elr_el1, x21 // set up the return data @@ -244,22 +270,37 @@ alternative_else_nop_endif ldp x28, x29, [sp, #16 * 14] ldr lr, [sp, #S_LR] add sp, sp, #S_FRAME_SIZE // restore sp - eret // return to kernel + + .if \el == 0 +alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + bne 4f + msr far_el1, x30 + tramp_alias x30, tramp_exit_native + br x30 +4: + tramp_alias x30, tramp_exit_compat + br x30 +#endif + .else + eret + .endif .endm .macro irq_stack_entry mov x19, sp // preserve the original sp /* - * Compare sp with the current thread_info, if the top - * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and - * should switch to the irq stack. + * Compare sp with the base of the task stack. + * If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack, + * and should switch to the irq stack. */ - and x25, x19, #~(THREAD_SIZE - 1) - cmp x25, tsk - b.ne 9998f + ldr x25, [tsk, TSK_STACK] + eor x25, x25, x19 + and x25, x25, #~(THREAD_SIZE - 1) + cbnz x25, 9998f - this_cpu_ptr irq_stack, x25, x26 + adr_this_cpu x25, irq_stack, x26 mov x26, #IRQ_STACK_START_SP add x26, x25, x26 @@ -315,31 +356,31 @@ tsk .req x28 // current thread_info .align 11 ENTRY(vectors) - ventry el1_sync_invalid // Synchronous EL1t - ventry el1_irq_invalid // IRQ EL1t - ventry el1_fiq_invalid // FIQ EL1t - ventry el1_error_invalid // Error EL1t + kernel_ventry 1, sync_invalid // Synchronous EL1t + kernel_ventry 1, irq_invalid // IRQ EL1t + kernel_ventry 1, fiq_invalid // FIQ EL1t + kernel_ventry 1, error_invalid // Error EL1t - ventry el1_sync // Synchronous EL1h - ventry el1_irq // IRQ EL1h - ventry el1_fiq_invalid // FIQ EL1h - ventry el1_error_invalid // Error EL1h + kernel_ventry 1, sync // Synchronous EL1h + kernel_ventry 1, irq // IRQ EL1h + kernel_ventry 1, fiq_invalid // FIQ EL1h + kernel_ventry 1, error_invalid // Error EL1h - ventry el0_sync // Synchronous 64-bit EL0 - ventry el0_irq // IRQ 64-bit EL0 - ventry el0_fiq_invalid // FIQ 64-bit EL0 - ventry el0_error_invalid // Error 64-bit EL0 + kernel_ventry 0, sync // Synchronous 64-bit EL0 + kernel_ventry 0, irq // IRQ 64-bit EL0 + kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 + kernel_ventry 0, error_invalid // Error 64-bit EL0 #ifdef CONFIG_COMPAT - ventry el0_sync_compat // Synchronous 32-bit EL0 - ventry el0_irq_compat // IRQ 32-bit EL0 - ventry el0_fiq_invalid_compat // FIQ 32-bit EL0 - ventry el0_error_invalid_compat // Error 32-bit EL0 + kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 + kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 + kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 + kernel_ventry 0, error_invalid_compat, 32 // Error 32-bit EL0 #else - ventry el0_sync_invalid // Synchronous 32-bit EL0 - ventry el0_irq_invalid // IRQ 32-bit EL0 - ventry el0_fiq_invalid // FIQ 32-bit EL0 - ventry el0_error_invalid // Error 32-bit EL0 + kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 + kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0 + kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0 + kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0 #endif END(vectors) @@ -428,12 +469,13 @@ el1_da: /* * Data abort handling */ - mrs x0, far_el1 + mrs x3, far_el1 enable_dbg // re-enable interrupts if they were enabled in the aborted context tbnz x23, #7, 1f // PSR_I_BIT enable_irq 1: + clear_address_tag x0, x3 mov x2, sp // struct pt_regs bl do_mem_abort @@ -486,9 +528,9 @@ el1_irq: irq_handler #ifdef CONFIG_PREEMPT - ldr w24, [tsk, #TI_PREEMPT] // get preempt count + ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count cbnz w24, 1f // preempt count != 0 - ldr x0, [tsk, #TI_FLAGS] // get flags + ldr x0, [tsk, #TSK_TI_FLAGS] // get flags tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? bl el1_preempt 1: @@ -503,7 +545,7 @@ ENDPROC(el1_irq) el1_preempt: mov x24, lr 1: bl preempt_schedule_irq // irq en/disable is done inside - ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS + ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling? ret x24 #endif @@ -594,7 +636,7 @@ el0_da: // enable interrupts before calling the main handler enable_dbg_and_irq ct_user_exit - bic x0, x26, #(0xff << 56) + clear_address_tag x0, x26 mov x1, x25 mov x2, sp bl do_mem_abort @@ -606,11 +648,14 @@ el0_ia: mrs x26, far_el1 // enable interrupts before calling the main handler enable_dbg_and_irq +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif ct_user_exit mov x0, x26 mov x1, x25 mov x2, sp - bl do_mem_abort + bl do_el0_ia_bp_hardening b ret_to_user el0_fpsimd_acc: /* @@ -733,8 +778,7 @@ ENTRY(cpu_switch_to) ldp x29, x9, [x8], #16 ldr lr, [x8] mov sp, x9 - and x9, x9, #~(THREAD_SIZE - 1) - msr sp_el0, x9 + msr sp_el0, x1 ret ENDPROC(cpu_switch_to) @@ -745,7 +789,7 @@ ENDPROC(cpu_switch_to) ret_fast_syscall: disable_irq // disable interrupts str x0, [sp, #S_X0] // returned x0 - ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing + ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for syscall tracing and x2, x1, #_TIF_SYSCALL_WORK cbnz x2, ret_fast_syscall_trace and x2, x1, #_TIF_WORK_MASK @@ -765,14 +809,14 @@ work_pending: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_on // enabled while in userspace #endif - ldr x1, [tsk, #TI_FLAGS] // re-check for single-step + ldr x1, [tsk, #TSK_TI_FLAGS] // re-check for single-step b finish_ret_to_user /* * "slow" syscall return path. */ ret_to_user: disable_irq // disable interrupts - ldr x1, [tsk, #TI_FLAGS] + ldr x1, [tsk, #TSK_TI_FLAGS] and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending finish_ret_to_user: @@ -805,7 +849,7 @@ el0_svc_naked: // compat entry point enable_dbg_and_irq ct_user_exit 1 - ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks + ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks tst x16, #_TIF_SYSCALL_WORK b.ne __sys_trace cmp scno, sc_nr // check upper syscall limit @@ -858,6 +902,119 @@ __ni_sys_trace: .popsection // .entry.text +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +/* + * Exception vectors trampoline. + */ + .pushsection ".entry.tramp.text", "ax" + + .macro tramp_map_kernel, tmp + mrs \tmp, ttbr1_el1 + sub \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE) + bic \tmp, \tmp, #USER_ASID_FLAG + msr ttbr1_el1, \tmp +#ifdef CONFIG_ARCH_MSM8996 + /* ASID already in \tmp[63:48] */ + movk \tmp, #:abs_g2_nc:(TRAMP_VALIAS >> 12) + movk \tmp, #:abs_g1_nc:(TRAMP_VALIAS >> 12) + /* 2MB boundary containing the vectors, so we nobble the walk cache */ + movk \tmp, #:abs_g0_nc:((TRAMP_VALIAS & ~(SZ_2M - 1)) >> 12) + isb + tlbi vae1, \tmp + dsb nsh +#endif /* CONFIG_ARCH_MSM8996 */ + .endm + + .macro tramp_unmap_kernel, tmp + mrs \tmp, ttbr1_el1 + add \tmp, \tmp, #(SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE) + orr \tmp, \tmp, #USER_ASID_FLAG + msr ttbr1_el1, \tmp + /* + * We avoid running the post_ttbr_update_workaround here because the + * user and kernel ASIDs don't have conflicting mappings, so any + * "blessing" as described in: + * + * http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com + * + * will not hurt correctness. Whilst this may partially defeat the + * point of using split ASIDs in the first place, it avoids + * the hit of invalidating the entire I-cache on every return to + * userspace. + */ + .endm + + .macro tramp_ventry, regsize = 64 + .align 7 +1: + .if \regsize == 64 + msr tpidrro_el0, x30 // Restored in kernel_ventry + .endif + bl 2f + b . +2: + tramp_map_kernel x30 +#ifdef CONFIG_RANDOMIZE_BASE + adr x30, tramp_vectors + PAGE_SIZE +#ifndef CONFIG_ARCH_MSM8996 + isb +#endif + ldr x30, [x30] +#else + ldr x30, =vectors +#endif + prfm plil1strm, [x30, #(1b - tramp_vectors)] + msr vbar_el1, x30 + add x30, x30, #(1b - tramp_vectors) + isb + ret + .endm + + .macro tramp_exit, regsize = 64 + adr x30, tramp_vectors + msr vbar_el1, x30 + tramp_unmap_kernel x30 + .if \regsize == 64 + mrs x30, far_el1 + .endif + eret + .endm + + .align 11 +ENTRY(tramp_vectors) + .space 0x400 + + tramp_ventry + tramp_ventry + tramp_ventry + tramp_ventry + + tramp_ventry 32 + tramp_ventry 32 + tramp_ventry 32 + tramp_ventry 32 +END(tramp_vectors) + +ENTRY(tramp_exit_native) + tramp_exit +END(tramp_exit_native) + +ENTRY(tramp_exit_compat) + tramp_exit 32 +END(tramp_exit_compat) + + .ltorg + .popsection // .entry.tramp.text +#ifdef CONFIG_RANDOMIZE_BASE + .pushsection ".rodata", "a" + .align PAGE_SHIFT + .globl __entry_tramp_data_start +__entry_tramp_data_start: + .quad vectors + .popsection // .rodata +#endif /* CONFIG_RANDOMIZE_BASE */ +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ + /* * Special system call wrappers. */ diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 394c61db55666d72c1a7f45da4583efbb5b47107..1d5890f19ca32bba1c27b0e1d2c72f8d47e5de1c 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -157,9 +157,11 @@ void fpsimd_thread_switch(struct task_struct *next) void fpsimd_flush_thread(void) { + preempt_disable(); memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state)); fpsimd_flush_task_state(current); set_thread_flag(TIF_FOREIGN_FPSTATE); + preempt_enable(); } /* diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index c7d26bb87a9ab05d07ad470867c13fdea57ad14a..c18658690993610a76f4f74917e1b3007f6bebce 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -428,7 +428,8 @@ ENDPROC(__create_page_tables) __primary_switched: adrp x4, init_thread_union add sp, x4, #THREAD_SIZE - msr sp_el0, x4 // Save thread_info + adr_l x5, init_task + msr sp_el0, x5 // Save thread_info adr_l x8, vectors // load VBAR_EL1 with virtual msr vbar_el1, x8 // vector table address @@ -486,6 +487,7 @@ ENTRY(kimage_vaddr) * booted in EL1 or EL2 respectively. */ ENTRY(el2_setup) + msr SPsel, #1 // We want to use SP_EL{1,2} mrs x0, CurrentEL cmp x0, #CurrentEL_EL2 b.ne 1f @@ -699,10 +701,10 @@ __secondary_switched: isb adr_l x0, secondary_data - ldr x0, [x0, #CPU_BOOT_STACK] // get secondary_data.stack - mov sp, x0 - and x0, x0, #~(THREAD_SIZE - 1) - msr sp_el0, x0 // save thread_info + ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack + mov sp, x1 + ldr x2, [x0, #CPU_BOOT_TASK] + msr sp_el0, x2 mov x29, #0 b secondary_start_kernel ENDPROC(__secondary_switched) diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index d55a7b09959b4d3f725ee6400a21fbc963d31b61..8bed26a2d5588e6309793ffb221aff7b97a1471a 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -50,9 +50,6 @@ */ extern int in_suspend; -/* Find a symbols alias in the linear map */ -#define LMADDR(x) phys_to_virt(virt_to_phys(x)) - /* Do we need to reset el2? */ #define el2_reset_needed() (is_hyp_mode_available() && !is_kernel_in_hyp_mode()) @@ -102,8 +99,8 @@ static inline void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i) int pfn_is_nosave(unsigned long pfn) { - unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin); - unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1); + unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin); + unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1); return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn); } @@ -125,12 +122,12 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) return -EOVERFLOW; arch_hdr_invariants(&hdr->invariants); - hdr->ttbr1_el1 = virt_to_phys(swapper_pg_dir); + hdr->ttbr1_el1 = __pa_symbol(swapper_pg_dir); hdr->reenter_kernel = _cpu_resume; /* We can't use __hyp_get_vectors() because kvm may still be loaded */ if (el2_reset_needed()) - hdr->__hyp_stub_vectors = virt_to_phys(__hyp_stub_vectors); + hdr->__hyp_stub_vectors = __pa_symbol(__hyp_stub_vectors); else hdr->__hyp_stub_vectors = 0; @@ -460,7 +457,6 @@ int swsusp_arch_resume(void) void *zero_page; size_t exit_size; pgd_t *tmp_pg_dir; - void *lm_restore_pblist; phys_addr_t phys_hibernate_exit; void __noreturn (*hibernate_exit)(phys_addr_t, phys_addr_t, void *, void *, phys_addr_t, phys_addr_t); @@ -480,12 +476,6 @@ int swsusp_arch_resume(void) if (rc) goto out; - /* - * Since we only copied the linear map, we need to find restore_pblist's - * linear map address. - */ - lm_restore_pblist = LMADDR(restore_pblist); - /* * We need a zero page that is zero before & after resume in order to * to break before make on the ttbr1 page tables. @@ -537,7 +527,7 @@ int swsusp_arch_resume(void) } hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1, - resume_hdr.reenter_kernel, lm_restore_pblist, + resume_hdr.reenter_kernel, restore_pblist, resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page)); out: diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index 1b3c747fedda51060d30fbd8a337870ca0291d6c..fb0082ab40a7ea5a452c67ad612b33a8dddba76d 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -36,6 +36,7 @@ #include #include #include +#include /* Breakpoint currently in use for each BRP. */ static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 6f2ac4fc66ca27bb3bd9ae29bdf96967e4b4580e..f607b387fcdce579f2ba05eb3c80fab969d67fac 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -97,7 +97,7 @@ static void __kprobes *patch_map(void *addr, int fixmap) if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX)) page = vmalloc_to_page(addr); else if (!module) - page = pfn_to_page(PHYS_PFN(__pa(addr))); + page = phys_to_page(__pa_symbol(addr)); else return addr; diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index 1ce90d8450ae9b64fe24d8ea86503a716b1e7097..d05dbe658409b251c9dd4c18348b77c1797e6973 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2016 Linaro Ltd. + * Copyright (C) 2014-2017 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,34 +26,20 @@ struct plt_entry { __le32 br; /* br x16 */ }; -u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela, +static bool in_init(const struct module *mod, void *loc) +{ + return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size; +} + +u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela, Elf64_Sym *sym) { - struct plt_entry *plt = (struct plt_entry *)mod->arch.plt->sh_addr; - int i = mod->arch.plt_num_entries; + struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : + &mod->arch.init; + struct plt_entry *plt = (struct plt_entry *)pltsec->plt->sh_addr; + int i = pltsec->plt_num_entries; u64 val = sym->st_value + rela->r_addend; - /* - * We only emit PLT entries against undefined (SHN_UNDEF) symbols, - * which are listed in the ELF symtab section, but without a type - * or a size. - * So, similar to how the module loader uses the Elf64_Sym::st_value - * field to store the resolved addresses of undefined symbols, let's - * borrow the Elf64_Sym::st_size field (whose value is never used by - * the module loader, even for symbols that are defined) to record - * the address of a symbol's associated PLT entry as we emit it for a - * zero addend relocation (which is the only kind we have to deal with - * in practice). This allows us to find duplicates without having to - * go through the table every time. - */ - if (rela->r_addend == 0 && sym->st_size != 0) { - BUG_ON(sym->st_size < (u64)plt || sym->st_size >= (u64)&plt[i]); - return sym->st_size; - } - - mod->arch.plt_num_entries++; - BUG_ON(mod->arch.plt_num_entries > mod->arch.plt_max_entries); - /* * MOVK/MOVN/MOVZ opcode: * +--------+------------+--------+-----------+-------------+---------+ @@ -72,8 +58,19 @@ u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela, cpu_to_le32(0xd61f0200) }; - if (rela->r_addend == 0) - sym->st_size = (u64)&plt[i]; + /* + * Check if the entry we just created is a duplicate. Given that the + * relocations are sorted, this will be the last entry we allocated. + * (if one exists). + */ + if (i > 0 && + plt[i].mov0 == plt[i - 1].mov0 && + plt[i].mov1 == plt[i - 1].mov1 && + plt[i].mov2 == plt[i - 1].mov2) + return (u64)&plt[i - 1]; + + pltsec->plt_num_entries++; + BUG_ON(pltsec->plt_num_entries > pltsec->plt_max_entries); return (u64)&plt[i]; } @@ -104,7 +101,8 @@ static bool duplicate_rel(const Elf64_Rela *rela, int num) return num > 0 && cmp_rela(rela + num, rela + num - 1) == 0; } -static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num) +static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num, + Elf64_Word dstidx) { unsigned int ret = 0; Elf64_Sym *s; @@ -116,13 +114,17 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num) case R_AARCH64_CALL26: /* * We only have to consider branch targets that resolve - * to undefined symbols. This is not simply a heuristic, - * it is a fundamental limitation, since the PLT itself - * is part of the module, and needs to be within 128 MB - * as well, so modules can never grow beyond that limit. + * to symbols that are defined in a different section. + * This is not simply a heuristic, it is a fundamental + * limitation, since there is no guaranteed way to emit + * PLT entries sufficiently close to the branch if the + * section size exceeds the range of a branch + * instruction. So ignore relocations against defined + * symbols if they live in the same section as the + * relocation target. */ s = syms + ELF64_R_SYM(rela[i].r_info); - if (s->st_shndx != SHN_UNDEF) + if (s->st_shndx == dstidx) break; /* @@ -149,7 +151,8 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num) int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { - unsigned long plt_max_entries = 0; + unsigned long core_plts = 0; + unsigned long init_plts = 0; Elf64_Sym *syms = NULL; int i; @@ -158,14 +161,16 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, * entries. Record the symtab address as well. */ for (i = 0; i < ehdr->e_shnum; i++) { - if (strcmp(".plt", secstrings + sechdrs[i].sh_name) == 0) - mod->arch.plt = sechdrs + i; + if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt")) + mod->arch.core.plt = sechdrs + i; + else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt")) + mod->arch.init.plt = sechdrs + i; else if (sechdrs[i].sh_type == SHT_SYMTAB) syms = (Elf64_Sym *)sechdrs[i].sh_addr; } - if (!mod->arch.plt) { - pr_err("%s: module PLT section missing\n", mod->name); + if (!mod->arch.core.plt || !mod->arch.init.plt) { + pr_err("%s: module PLT section(s) missing\n", mod->name); return -ENOEXEC; } if (!syms) { @@ -188,14 +193,27 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, /* sort by type, symbol index and addend */ sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL); - plt_max_entries += count_plts(syms, rels, numrels); + if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0) + core_plts += count_plts(syms, rels, numrels, + sechdrs[i].sh_info); + else + init_plts += count_plts(syms, rels, numrels, + sechdrs[i].sh_info); } - mod->arch.plt->sh_type = SHT_NOBITS; - mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; - mod->arch.plt->sh_addralign = L1_CACHE_BYTES; - mod->arch.plt->sh_size = plt_max_entries * sizeof(struct plt_entry); - mod->arch.plt_num_entries = 0; - mod->arch.plt_max_entries = plt_max_entries; + mod->arch.core.plt->sh_type = SHT_NOBITS; + mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES; + mod->arch.core.plt->sh_size = (core_plts + 1) * sizeof(struct plt_entry); + mod->arch.core.plt_num_entries = 0; + mod->arch.core.plt_max_entries = core_plts; + + mod->arch.init.plt->sh_type = SHT_NOBITS; + mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES; + mod->arch.init.plt->sh_size = (init_plts + 1) * sizeof(struct plt_entry); + mod->arch.init.plt_num_entries = 0; + mod->arch.init.plt_max_entries = init_plts; + return 0; } diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 7f316982ce00186262728518f3a03f7871fb7dd7..c9a2ab446dc6fceb4a141fce131937048432da56 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -380,7 +380,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && ovf == -ERANGE) { - val = module_emit_plt_entry(me, &rel[i], sym); + val = module_emit_plt_entry(me, loc, &rel[i], sym); ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, AARCH64_INSN_IMM_26); } diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds index 8949f6c6f729d6014f3e0a6d054ca1992ea7d115..f7c9781a9d48b48396e61375da2e10f31c0b6296 100644 --- a/arch/arm64/kernel/module.lds +++ b/arch/arm64/kernel/module.lds @@ -1,3 +1,4 @@ SECTIONS { .plt (NOLOAD) : { BYTE(0) } + .init.plt (NOLOAD) : { BYTE(0) } } diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 852548cb31dc015c6341c1da1d814c7e81334ace..52710f11d473ad0d4c5924c959ab2a48c4bca506 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -29,6 +29,8 @@ #include #include +static DEFINE_PER_CPU(bool, is_hotplugging); + /* * ARMv8 PMUv3 Performance Events handling code. * Common event types (some are defined in asm/perf_event.h). @@ -777,8 +779,8 @@ static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev) struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; - /* Ignore if we don't have an event. */ - if (!event) + /* Ignore if we don't have an event or if it's a zombie event */ + if (!event || event->state == PERF_EVENT_STATE_ZOMBIE) continue; /* @@ -982,6 +984,9 @@ static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) if (!cpu_pmu) return; + if (__this_cpu_read(is_hotplugging)) + return; + hw_events = this_cpu_ptr(cpu_pmu->hw_events); if (!hw_events) @@ -1031,14 +1036,13 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) pmu_idle_nb->cpu_pmu = cpu_pmu; pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier; - idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); ret = smp_call_function_any(&cpu_pmu->supported_cpus, __armv8pmu_probe_pmu, cpu_pmu, 1); - if (ret) - idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb); + if (!ret) + idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); return ret; } @@ -1140,6 +1144,37 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = { {}, }; +#ifdef CONFIG_HOTPLUG_CPU +static int perf_event_hotplug_coming_up(unsigned int cpu) +{ + per_cpu(is_hotplugging, cpu) = false; + return 0; +} + +static int perf_event_hotplug_going_down(unsigned int cpu) +{ + per_cpu(is_hotplugging, cpu) = true; + return 0; +} + +static int perf_event_cpu_hp_init(void) +{ + int ret; + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_NOTIFY_PERF_ONLINE, + "PERF_EVENT/CPUHP_AP_NOTIFY_PERF_ONLINE", + perf_event_hotplug_coming_up, + perf_event_hotplug_going_down); + if (ret) + pr_err("CPU hotplug notifier for perf_event.c could not be registered: %d\n", + ret); + + return ret; +} +#else +static int perf_event_cpu_hp_init(void) { return 0; } +#endif + /* * Non DT systems have their micro/arch events probed at run-time. * A fairly complete list of generic events are provided and ones that @@ -1152,12 +1187,26 @@ static const struct pmu_probe_info armv8_pmu_probe_table[] = { static int armv8_pmu_device_probe(struct platform_device *pdev) { - if (acpi_disabled) - return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, - NULL); + int ret, cpu; + + /* set to true so armv8pmu_idle_update doesn't try to load + * hw_events before arm_pmu_device_probe has initialized it. + */ + for_each_possible_cpu(cpu) { + per_cpu(is_hotplugging, cpu) = true; + } + + ret = arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, + (acpi_disabled ? NULL : armv8_pmu_probe_table)); + + if (!ret) { + for_each_possible_cpu(cpu) + per_cpu(is_hotplugging, cpu) = false; - return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, - armv8_pmu_probe_table); + ret = perf_event_cpu_hp_init(); + } + + return ret; } static struct platform_driver armv8_pmu_driver = { diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c index 1f0b74a53945b19be23a4fe734c47401a1cebc9d..d87106d41a8d9a4d1e8a91b5d68309eedb557743 100644 --- a/arch/arm64/kernel/perf_trace_counters.c +++ b/arch/arm64/kernel/perf_trace_counters.c @@ -59,7 +59,7 @@ void tracectr_notifier(void *ignore, bool preempt, { u32 cnten_val; int current_pid; - u32 cpu = task_thread_info(next)->cpu; + u32 cpu = task_cpu(next); if (tp_pid_state != 1) return; diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 0c4a5ee9c9831e0e73fa223de259a0c3e23d701e..ee0ea179df1dbbf7b6daf273b572a358f4fbc3ce 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -189,7 +190,7 @@ static void show_data(unsigned long addr, int nbytes, const char *name) * don't attempt to dump non-kernel addresses or * values that are probably just small negative numbers */ - if (addr < PAGE_OFFSET || addr > -256UL) + if (addr < KIMAGE_VADDR || addr > -256UL) return; printk("\n%s: %#lx:\n", name, addr); @@ -225,18 +226,12 @@ static void show_data(unsigned long addr, int nbytes, const char *name) static void show_extra_register_data(struct pt_regs *regs, int nbytes) { mm_segment_t fs; - unsigned int i; fs = get_fs(); set_fs(KERNEL_DS); show_data(regs->pc - nbytes, nbytes * 2, "PC"); show_data(regs->regs[30] - nbytes, nbytes * 2, "LR"); show_data(regs->sp - nbytes, nbytes * 2, "SP"); - for (i = 0; i < 30; i++) { - char name[4]; - snprintf(name, sizeof(name), "X%u", i); - show_data(regs->regs[i] - nbytes, nbytes * 2, name); - } set_fs(fs); } @@ -277,12 +272,10 @@ void __show_regs(struct pt_regs *regs) } if (!user_mode(regs)) show_extra_register_data(regs, 64); - printk("\n"); } void show_regs(struct pt_regs * regs) { - printk("\n"); __show_regs(regs); } @@ -331,6 +324,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); + /* + * In case p was allocated the same task_struct pointer as some + * other recently-exited task, make sure p is disassociated from + * any cpu that may have run that now-exited task recently. + * Otherwise we could erroneously skip reloading the FPSIMD + * registers for p. + */ + fpsimd_flush_task_state(p); + if (likely(!(p->flags & PF_KTHREAD))) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; @@ -373,17 +375,17 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, static void tls_thread_switch(struct task_struct *next) { - unsigned long tpidr, tpidrro; + unsigned long tpidr; tpidr = read_sysreg(tpidr_el0); *task_user_tls(current) = tpidr; - tpidr = *task_user_tls(next); - tpidrro = is_compat_thread(task_thread_info(next)) ? - next->thread.tp_value : 0; + if (is_compat_thread(task_thread_info(next))) + write_sysreg(next->thread.tp_value, tpidrro_el0); + else if (!arm64_kernel_unmapped_at_el0()) + write_sysreg(0, tpidrro_el0); - write_sysreg(tpidr, tpidr_el0); - write_sysreg(tpidrro, tpidrro_el0); + write_sysreg(*task_user_tls(next), tpidr_el0); } /* Restore the UAO state depending on next's addr_limit */ @@ -397,6 +399,20 @@ void uao_thread_switch(struct task_struct *next) } } +/* + * We store our current task in sp_el0, which is clobbered by userspace. Keep a + * shadow copy so that we can restore this upon entry from userspace. + * + * This is *only* for exception entry from EL0, and is not valid until we + * __switch_to() a user task. + */ +DEFINE_PER_CPU(struct task_struct *, __entry_task); + +static void entry_task_switch(struct task_struct *next) +{ + __this_cpu_write(__entry_task, next); +} + /* * Thread switching. */ @@ -409,6 +425,7 @@ struct task_struct *__switch_to(struct task_struct *prev, tls_thread_switch(next); hw_breakpoint_thread_switch(next); contextidr_thread_switch(next); + entry_task_switch(next); uao_thread_switch(next); /* @@ -426,27 +443,35 @@ struct task_struct *__switch_to(struct task_struct *prev, unsigned long get_wchan(struct task_struct *p) { struct stackframe frame; - unsigned long stack_page; + unsigned long stack_page, ret = 0; int count = 0; if (!p || p == current || p->state == TASK_RUNNING) return 0; + stack_page = (unsigned long)try_get_task_stack(p); + if (!stack_page) + return 0; + frame.fp = thread_saved_fp(p); frame.sp = thread_saved_sp(p); frame.pc = thread_saved_pc(p); #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = p->curr_ret_stack; #endif - stack_page = (unsigned long)task_stack_page(p); do { if (frame.sp < stack_page || frame.sp >= stack_page + THREAD_SIZE || unwind_frame(p, &frame)) - return 0; - if (!in_sched_functions(frame.pc)) - return frame.pc; + goto out; + if (!in_sched_functions(frame.pc)) { + ret = frame.pc; + goto out; + } } while (count ++ < 16); - return 0; + +out: + put_task_stack(p); + return ret; } unsigned long arch_align_stack(unsigned long sp) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 81762dd5006fb3d6c6a728f6f7eadde7458fdd0f..716a5c2439e83158604a06c34dec67d1e361c295 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -45,7 +46,7 @@ static int __init cpu_psci_cpu_prepare(unsigned int cpu) static int cpu_psci_cpu_boot(unsigned int cpu) { - int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry)); + int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry)); if (err) pr_err("failed to boot CPU%d (%d)\n", cpu, err); diff --git a/arch/arm64/kernel/return_address.c b/arch/arm64/kernel/return_address.c index 1718706fde83604f78d81d850bf8827705338f1a..12a87f2600f2f65d03799a44402eabda5024277e 100644 --- a/arch/arm64/kernel/return_address.c +++ b/arch/arm64/kernel/return_address.c @@ -12,6 +12,7 @@ #include #include +#include #include struct return_address_data { diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 49f3ae062df84def1c1f94334bc9c88f869d123d..f58539ffe467779498d13d727363f82728308e1c 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ #include #include #include +#include phys_addr_t __fdt_pointer __initdata; @@ -185,6 +187,11 @@ static void __init smp_build_mpidr_hash(void) pr_warn("Large number of MPIDR hash buckets detected\n"); } +const char * __init __weak arch_read_machine_name(void) +{ + return of_flat_dt_get_machine_name(); +} + static void __init setup_machine_fdt(phys_addr_t dt_phys) { void *dt_virt = fixmap_remap_fdt(dt_phys); @@ -200,7 +207,7 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) cpu_relax(); } - machine_name = of_flat_dt_get_machine_name(); + machine_name = arch_read_machine_name(); if (machine_name) { dump_stack_set_arch_desc("%s (DT)", machine_name); pr_info("Machine: %s\n", machine_name); @@ -212,10 +219,10 @@ static void __init request_standard_resources(void) struct memblock_region *region; struct resource *res; - kernel_code.start = virt_to_phys(_text); - kernel_code.end = virt_to_phys(__init_begin - 1); - kernel_data.start = virt_to_phys(_sdata); - kernel_data.end = virt_to_phys(_end - 1); + kernel_code.start = __pa_symbol(_text); + kernel_code.end = __pa_symbol(__init_begin - 1); + kernel_data.start = __pa_symbol(_sdata); + kernel_data.end = __pa_symbol(_end - 1); for_each_memblock(memory, region) { res = alloc_bootmem_low(sizeof(*res)); @@ -312,7 +319,7 @@ void __init setup_arch(char **cmdline_p) * faults in case uaccess_enable() is inadvertently called by the init * thread. */ - init_thread_info.ttbr0 = virt_to_phys(empty_zero_page); + init_task.thread_info.ttbr0 = virt_to_phys(empty_zero_page); #endif #ifdef CONFIG_VT @@ -355,11 +362,11 @@ postcore_initcall(topology_init); static int dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p) { - u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR; + const unsigned long offset = kaslr_offset(); - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) { - pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n", - kaslr_offset, KIMAGE_VADDR); + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && offset > 0) { + pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n", + offset, KIMAGE_VADDR); } else { pr_emerg("Kernel Offset: disabled\n"); } diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 1bec41b5fda3917b2ed7583663a239f25c6126bf..df67652e46f0de3fcfcfa18dbf5d69c7a97815a1 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -125,9 +125,6 @@ ENTRY(_cpu_resume) /* load sp from context */ ldr x2, [x0, #CPU_CTX_SP] mov sp, x2 - /* save thread_info */ - and x2, x2, #~(THREAD_SIZE - 1) - msr sp_el0, x2 /* * cpu_do_resume expects x0 to contain context address pointer */ diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 0f627090bedfb4d57ae7291e6b87426b37e87d8c..623dd48fd6a774a1396d46c4bc4064c5237c2429 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -54,10 +54,14 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include +DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); +EXPORT_PER_CPU_SYMBOL(cpu_number); + /* * as from 2.5, kernels no longer have an init_tasks structure * so we need some other way of telling a new secondary core @@ -147,6 +151,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) * We need to tell the secondary core where to find its stack and the * page tables. */ + secondary_data.task = idle; secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; update_cpu_boot_status(CPU_MMU_OFF); __flush_dcache_area(&secondary_data, sizeof(secondary_data)); @@ -171,6 +176,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) pr_err("CPU%u: failed to boot: %d\n", cpu, ret); } + secondary_data.task = NULL; secondary_data.stack = NULL; status = READ_ONCE(secondary_data.status); if (ret && status) { @@ -209,7 +215,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) asmlinkage void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + cpu = task_cpu(current); + set_my_cpu_offset(per_cpu_offset(cpu)); /* * All kernel threads share the same mm context; grab a @@ -218,8 +227,6 @@ asmlinkage void secondary_start_kernel(void) atomic_inc(&mm->mm_count); current->active_mm = mm; - set_my_cpu_offset(per_cpu_offset(smp_processor_id())); - pr_debug("CPU%u: Booted secondary processor\n", cpu); /* @@ -733,6 +740,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ for_each_possible_cpu(cpu) { + per_cpu(cpu_number, cpu) = cpu; + if (cpu == smp_processor_id()) continue; @@ -836,6 +845,7 @@ static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs) pr_crit("CPU%u: stopping\n", cpu); show_regs(regs); dump_stack(); + dump_stack_minidump(regs->sp); raw_spin_unlock(&stop_lock); } @@ -1035,7 +1045,7 @@ static bool have_cpu_die(void) #ifdef CONFIG_HOTPLUG_CPU int any_cpu = raw_smp_processor_id(); - if (cpu_ops[any_cpu]->cpu_die) + if (cpu_ops[any_cpu] && cpu_ops[any_cpu]->cpu_die) return true; #endif return false; diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c index 9a00eee9acc842993b9114b09f69998901a9cc06..93034651c87ea37517cc1db519ab4e097eee45d8 100644 --- a/arch/arm64/kernel/smp_spin_table.c +++ b/arch/arm64/kernel/smp_spin_table.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -98,7 +99,7 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu) * boot-loader's endianess before jumping. This is mandated by * the boot protocol. */ - writeq_relaxed(__pa(secondary_holding_pen), release_addr); + writeq_relaxed(__pa_symbol(secondary_holding_pen), release_addr); __flush_dcache_area((__force void *)release_addr, sizeof(*release_addr)); diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index c2efddfca18cd476a98b46e445bf9fe1592beea5..f7ce3d25ced2a50c12bb6e8aef78e4f87f664fa7 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -22,6 +22,7 @@ #include #include +#include #include /* @@ -128,7 +129,6 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, break; } } -EXPORT_SYMBOL(walk_stackframe); #ifdef CONFIG_STACKTRACE struct stack_trace_data { @@ -176,24 +176,29 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) trace->entries[trace->nr_entries++] = ULONG_MAX; } -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +static noinline void __save_stack_trace(struct task_struct *tsk, + struct stack_trace *trace, unsigned int nosched) { struct stack_trace_data data; struct stackframe frame; + if (!try_get_task_stack(tsk)) + return; + data.trace = trace; data.skip = trace->skip; + data.no_sched_functions = nosched; if (tsk != current) { - data.no_sched_functions = 1; frame.fp = thread_saved_fp(tsk); frame.sp = thread_saved_sp(tsk); frame.pc = thread_saved_pc(tsk); } else { - data.no_sched_functions = 0; + /* We don't want this function nor the caller */ + data.skip += 2; frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_stack_pointer; - frame.pc = (unsigned long)save_stack_trace_tsk; + frame.pc = (unsigned long)__save_stack_trace; } #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = tsk->curr_ret_stack; @@ -202,11 +207,20 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) walk_stackframe(tsk, &frame, save_trace, &data); if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; + + put_task_stack(tsk); +} +EXPORT_SYMBOL(save_stack_trace_tsk); + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + __save_stack_trace(tsk, trace, 1); } void save_stack_trace(struct stack_trace *trace) { - save_stack_trace_tsk(current, trace); + __save_stack_trace(current, trace, 0); } + EXPORT_SYMBOL_GPL(save_stack_trace); #endif diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index bb0cd787a9d31dc4762d3a98257b3e11d8afe6f0..1e3be9064cfa0424ba6443d97f786917ed89782f 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -46,12 +46,6 @@ void notrace __cpu_suspend_exit(void) */ cpu_uninstall_idmap(); - /* - * Restore per-cpu offset before any kernel - * subsystem relying on it has a chance to run. - */ - set_my_cpu_offset(per_cpu_offset(cpu)); - /* * PSTATE was not saved over suspend/resume, re-enable any detected * features that might not have been set correctly. diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index aaf4bd7748f60f01527c437be9c5fd84d141df0a..f2fe96fd8feaf00c8367a7a67189b50a732db58b 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -420,6 +420,11 @@ const struct cpumask *cpu_coregroup_mask(int cpu) return &cpu_topology[cpu].core_sibling; } +static int cpu_cpu_flags(void) +{ + return SD_ASYM_CPUCAPACITY; +} + static inline int cpu_corepower_flags(void) { return SD_SHARE_PKG_RESOURCES | SD_SHARE_POWERDOMAIN | \ @@ -430,7 +435,7 @@ static struct sched_domain_topology_level arm64_topology[] = { #ifdef CONFIG_SCHED_MC { cpu_coregroup_mask, cpu_corepower_flags, cpu_core_energy, SD_INIT_NAME(MC) }, #endif - { cpu_cpu_mask, NULL, cpu_cluster_energy, SD_INIT_NAME(DIE) }, + { cpu_cpu_mask, cpu_cpu_flags, cpu_cluster_energy, SD_INIT_NAME(DIE) }, { NULL, }, }; @@ -449,6 +454,12 @@ static void update_cpu_capacity(unsigned int cpu) cpu, arch_scale_cpu_capacity(NULL, cpu)); } +void update_cpu_power_capacity(int cpu) +{ + update_cpu_power(cpu); + update_cpu_capacity(cpu); +} + static void update_siblings_masks(unsigned int cpuid) { struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; @@ -510,8 +521,6 @@ void store_cpu_topology(unsigned int cpuid) topology_populated: update_siblings_masks(cpuid); - update_cpu_power(cpuid); - update_cpu_capacity(cpuid); } static void __init reset_cpu_topology(void) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index d84c7d098a38fdb4c59a84526498bab547baaf24..cd538361b988b6130fd872a9f66a88837a27779e 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -33,15 +33,18 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include #include +#include static const char *handler[]= { "Synchronous Abort", @@ -112,7 +115,7 @@ static void __dump_instr(const char *lvl, struct pt_regs *regs) for (i = -4; i < 1; i++) { unsigned int val, bad; - bad = __get_user(val, &((u32 *)addr)[i]); + bad = get_user(val, &((u32 *)addr)[i]); if (!bad) p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val); @@ -147,6 +150,9 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) if (!tsk) tsk = current; + if (!try_get_task_stack(tsk)) + return; + /* * Switching between stacks is valid when tracing current and in * non-preemptible context. @@ -212,6 +218,8 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) stack + sizeof(struct pt_regs)); } } + + put_task_stack(tsk); } void show_stack(struct task_struct *tsk, unsigned long *sp) @@ -227,10 +235,9 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) #endif #define S_SMP " SMP" -static int __die(const char *str, int err, struct thread_info *thread, - struct pt_regs *regs) +static int __die(const char *str, int err, struct pt_regs *regs) { - struct task_struct *tsk = thread->task; + struct task_struct *tsk = current; static int die_counter; int ret; @@ -245,7 +252,8 @@ static int __die(const char *str, int err, struct thread_info *thread, print_modules(); __show_regs(regs); pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n", - TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1); + TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), + end_of_stack(tsk)); if (!user_mode(regs)) { dump_backtrace(regs, tsk); @@ -310,7 +318,6 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, int notify) */ void die(const char *str, struct pt_regs *regs, int err) { - struct thread_info *thread = current_thread_info(); enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE; unsigned long flags = oops_begin(); int ret; @@ -320,7 +327,7 @@ void die(const char *str, struct pt_regs *regs, int err) if (bug_type != BUG_TRAP_TYPE_NONE && !strlen(str)) str = "Oops - BUG"; - ret = __die(str, err, thread, regs); + ret = __die(str, err, regs); oops_end(flags, regs, ret); } @@ -453,6 +460,8 @@ void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr) asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { + void __user *pc = (void __user *)instruction_pointer(regs); + /* check for AArch32 breakpoint instructions */ if (!aarch32_break_handler(regs)) return; @@ -460,6 +469,8 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) if (call_undef_hook(regs) == 0) return; + trace_undef_instr(regs, pc); + force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); } @@ -470,7 +481,7 @@ int cpu_enable_cache_maint_trap(void *__unused) } #define __user_cache_maint(insn, address, res) \ - if (untagged_addr(address) >= user_addr_max()) { \ + if (address >= user_addr_max()) { \ res = -EFAULT; \ } else { \ uaccess_ttbr0_enable(); \ @@ -496,7 +507,7 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT; int ret = 0; - address = (rt == 31) ? 0 : regs->regs[rt]; + address = (rt == 31) ? 0 : untagged_addr(regs->regs[rt]); switch (crm) { case ESR_ELx_SYS64_ISS_CRM_DC_CVAU: /* DC CVAU, gets promoted */ @@ -530,6 +541,25 @@ static void ctr_read_handler(unsigned int esr, struct pt_regs *regs) regs->pc += 4; } +static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs) +{ + int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; + + isb(); + if (rt != 31) + regs->regs[rt] = arch_counter_get_cntvct(); + regs->pc += 4; +} + +static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs) +{ + int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT; + + if (rt != 31) + regs->regs[rt] = read_sysreg(cntfrq_el0); + regs->pc += 4; +} + struct sys64_hook { unsigned int esr_mask; unsigned int esr_val; @@ -548,6 +578,18 @@ static struct sys64_hook sys64_hooks[] = { .esr_val = ESR_ELx_SYS64_ISS_SYS_CTR_READ, .handler = ctr_read_handler, }, + { + /* Trap read access to CNTVCT_EL0 */ + .esr_mask = ESR_ELx_SYS64_ISS_SYS_OP_MASK, + .esr_val = ESR_ELx_SYS64_ISS_SYS_CNTVCT, + .handler = cntvct_read_handler, + }, + { + /* Trap read access to CNTFRQ_EL0 */ + .esr_mask = ESR_ELx_SYS64_ISS_SYS_OP_MASK, + .esr_val = ESR_ELx_SYS64_ISS_SYS_CNTFRQ, + .handler = cntfrq_read_handler, + }, {}, }; diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index a2c2478e7d7896d568e7b9a04849f4adacb61fdf..ef3bdfd6be181cbb9800c0b2c9f38ae82a056e76 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -37,7 +37,7 @@ #include #include -extern char vdso_start, vdso_end; +extern char vdso_start[], vdso_end[]; static unsigned long vdso_pages __ro_after_init; /* @@ -123,15 +123,16 @@ static int __init vdso_init(void) { int i; struct page **vdso_pagelist; + unsigned long pfn; - if (memcmp(&vdso_start, "\177ELF", 4)) { + if (memcmp(vdso_start, "\177ELF", 4)) { pr_err("vDSO is not a valid ELF object!\n"); return -EINVAL; } - vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; + vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n", - vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data); + vdso_pages + 1, vdso_pages, vdso_start, 1L, vdso_data); /* Allocate the vDSO pagelist, plus a page for the data. */ vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *), @@ -140,11 +141,14 @@ static int __init vdso_init(void) return -ENOMEM; /* Grab the vDSO data page. */ - vdso_pagelist[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data))); + vdso_pagelist[0] = phys_to_page(__pa_symbol(vdso_data)); + /* Grab the vDSO code pages. */ + pfn = sym_to_pfn(vdso_start); + for (i = 0; i < vdso_pages; i++) - vdso_pagelist[i + 1] = pfn_to_page(PHYS_PFN(__pa(&vdso_start)) + i); + vdso_pagelist[i + 1] = pfn_to_page(pfn + i); vdso_spec[0].pages = &vdso_pagelist[0]; vdso_spec[1].pages = &vdso_pagelist[1]; @@ -217,10 +221,11 @@ void update_vsyscall(struct timekeeper *tk) /* tkr_mono.cycle_last == tkr_raw.cycle_last */ vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; vdso_data->raw_time_sec = tk->raw_time.tv_sec; - vdso_data->raw_time_nsec = tk->raw_time.tv_nsec; + vdso_data->raw_time_nsec = (tk->raw_time.tv_nsec << + tk->tkr_raw.shift) + + tk->tkr_raw.xtime_nsec; vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; - /* tkr_raw.xtime_nsec == 0 */ vdso_data->cs_mono_mult = tk->tkr_mono.mult; vdso_data->cs_raw_mult = tk->tkr_raw.mult; /* tkr_mono.shift == tkr_raw.shift */ diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S index e00b4671bd7c4af5516b95da00409c7296df1963..76320e9209651fd307659dcbab8092ff7c1c09e2 100644 --- a/arch/arm64/kernel/vdso/gettimeofday.S +++ b/arch/arm64/kernel/vdso/gettimeofday.S @@ -256,7 +256,6 @@ monotonic_raw: seqcnt_check fail=monotonic_raw /* All computations are done with left-shifted nsecs. */ - lsl x14, x14, x12 get_nsec_per_sec res=x9 lsl x9, x9, x12 diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index b8deffa9e1bf3ec06d9411afb7849695df27d6d2..34d3ed64fe8ed91a5e2955c7d404e9e170089bac 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -56,6 +56,17 @@ jiffies = jiffies_64; #define HIBERNATE_TEXT #endif +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define TRAMP_TEXT \ + . = ALIGN(PAGE_SIZE); \ + VMLINUX_SYMBOL(__entry_tramp_text_start) = .; \ + *(.entry.tramp.text) \ + . = ALIGN(PAGE_SIZE); \ + VMLINUX_SYMBOL(__entry_tramp_text_end) = .; +#else +#define TRAMP_TEXT +#endif + /* * The size of the PE/COFF section that covers the kernel image, which * runs from stext to _edata, must be a round multiple of the PE/COFF @@ -128,6 +139,7 @@ SECTIONS HYPERVISOR_TEXT IDMAP_TEXT HIBERNATE_TEXT + TRAMP_TEXT *(.fixup) *(.gnu.warning) . = ALIGN(16); @@ -221,6 +233,11 @@ SECTIONS . += RESERVED_TTBR0_SIZE; #endif +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + tramp_pg_dir = .; + . += PAGE_SIZE; +#endif + _end = .; STABS_DEBUG @@ -240,7 +257,10 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K, ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1)) <= SZ_4K, "Hibernate exit text too big or misaligned") #endif - +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE, + "Entry trampoline text too big") +#endif /* * If padding is applied before .head.text, virt<->phys conversions will fail. */ diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index a204adf29f0a6dedd1c47485564086ef9682f82b..85baadab02d3d88cd612a8e21b422ccb790c7890 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -125,7 +125,19 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) return ret; } +static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + + kvm_pr_unimpl("Unknown exception class: hsr: %#08x -- %s\n", + hsr, esr_get_class_string(hsr)); + + kvm_inject_undefined(vcpu); + return 1; +} + static exit_handle_fn arm_exit_handlers[] = { + [0 ... ESR_ELx_EC_MAX] = kvm_handle_unknown_ec, [ESR_ELx_EC_WFx] = kvm_handle_wfx, [ESR_ELx_EC_CP15_32] = kvm_handle_cp15_32, [ESR_ELx_EC_CP15_64] = kvm_handle_cp15_64, @@ -151,13 +163,6 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) u32 hsr = kvm_vcpu_get_hsr(vcpu); u8 hsr_ec = ESR_ELx_EC(hsr); - if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) || - !arm_exit_handlers[hsr_ec]) { - kvm_err("Unknown exception class: hsr: %#08x -- %s\n", - hsr, esr_get_class_string(hsr)); - BUG(); - } - return arm_exit_handlers[hsr_ec]; } diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S index 6b29d3d9e1f285c0f1e61c3509cfbaf99402ea86..4bbff904169d79ff63433d75f2ca486173285cff 100644 --- a/arch/arm64/kvm/hyp-init.S +++ b/arch/arm64/kvm/hyp-init.S @@ -102,10 +102,13 @@ __do_hyp_init: tlbi alle2 dsb sy - mrs x4, sctlr_el2 - and x4, x4, #SCTLR_ELx_EE // preserve endianness of EL2 - ldr x5, =SCTLR_ELx_FLAGS - orr x4, x4, x5 + /* + * Preserve all the RES1 bits while setting the default flags, + * as well as the EE bit on BE. Drop the A flag since the compiler + * is allowed to generate unaligned accesses. + */ + ldr x4, =(SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A)) +CPU_BE( orr x4, x4, #SCTLR_ELx_EE) msr sctlr_el2, x4 isb diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index aaf42ae8d8c31395d63590289e55798073bc99a4..48b03547a9693614d58f3e1575d69330c80763fd 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile @@ -2,6 +2,8 @@ # Makefile for Kernel-based Virtual Machine module, HYP part # +ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING + KVM=../../../../virt/kvm obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 0c848c18ca44706aad457c7b3a4b77a8d379eb33..3eab6ac18d7d33c1f841fa8474391bf46db5e904 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -50,7 +51,7 @@ static void __hyp_text __activate_traps_vhe(void) val &= ~CPACR_EL1_FPEN; write_sysreg(val, cpacr_el1); - write_sysreg(__kvm_hyp_vector, vbar_el1); + write_sysreg(kvm_get_hyp_vector(), vbar_el1); } static void __hyp_text __activate_traps_nvhe(void) @@ -308,6 +309,18 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu)) goto again; + if (exit_code == ARM_EXCEPTION_TRAP && + (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 || + kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) && + vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) { + u64 val = PSCI_RET_NOT_SUPPORTED; + if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) + val = 2; + + vcpu_set_reg(vcpu, 0, val); + goto again; + } + if (static_branch_unlikely(&vgic_v2_cpuif_trap) && exit_code == ARM_EXCEPTION_TRAP) { bool valid; diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index da6a8cfa54a08f11874863bc643f84e103027768..3556715a774ec8f2dcc82e7b370c6827c639af37 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -33,12 +33,26 @@ #define LOWER_EL_AArch64_VECTOR 0x400 #define LOWER_EL_AArch32_VECTOR 0x600 +/* + * Table taken from ARMv8 ARM DDI0487B-B, table G1-10. + */ +static const u8 return_offsets[8][2] = { + [0] = { 0, 0 }, /* Reset, unused */ + [1] = { 4, 2 }, /* Undefined */ + [2] = { 0, 0 }, /* SVC, unused */ + [3] = { 4, 4 }, /* Prefetch abort */ + [4] = { 8, 8 }, /* Data abort */ + [5] = { 0, 0 }, /* HVC, unused */ + [6] = { 4, 4 }, /* IRQ, unused */ + [7] = { 4, 4 }, /* FIQ, unused */ +}; + static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset) { unsigned long cpsr; unsigned long new_spsr_value = *vcpu_cpsr(vcpu); bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT); - u32 return_offset = (is_thumb) ? 4 : 0; + u32 return_offset = return_offsets[vect_offset >> 2][is_thumb]; u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR); cpsr = mode | COMPAT_PSR_I_BIT; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 87e7e6608cd8a31e6913be8134b90e443df314cb..7cee552ce0bf025759fb75a4c13850fa641878c8 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1573,8 +1573,8 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, { struct sys_reg_params params; u32 hsr = kvm_vcpu_get_hsr(vcpu); - int Rt = (hsr >> 5) & 0xf; - int Rt2 = (hsr >> 10) & 0xf; + int Rt = kvm_vcpu_sys_get_rt(vcpu); + int Rt2 = (hsr >> 10) & 0x1f; params.is_aarch32 = true; params.is_32bit = false; @@ -1625,7 +1625,7 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, { struct sys_reg_params params; u32 hsr = kvm_vcpu_get_hsr(vcpu); - int Rt = (hsr >> 5) & 0xf; + int Rt = kvm_vcpu_sys_get_rt(vcpu); params.is_aarch32 = true; params.is_32bit = true; @@ -1740,7 +1740,7 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) { struct sys_reg_params params; unsigned long esr = kvm_vcpu_get_hsr(vcpu); - int Rt = (esr >> 5) & 0x1f; + int Rt = kvm_vcpu_sys_get_rt(vcpu); int ret; trace_kvm_handle_sys_reg(esr); diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index d7150e30438aef3bb3f29a8a41a73fbd4c5d4157..dd65ca253eb4e9b60ae3a244b59e00e5ddb79256 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -30,7 +30,7 @@ * Alignment fixed up by hardware. */ ENTRY(__clear_user) - uaccess_enable_not_uao x2, x3 + uaccess_enable_not_uao x2, x3, x4 mov x2, x1 // save the size for fixup return subs x1, x1, #8 b.mi 2f diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index cfe13396085bef6e5dabbf6c0837735228ed1446..7e7e687c17ac3bf3fba8de735ec3743430ea335a 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -64,7 +64,7 @@ end .req x5 ENTRY(__arch_copy_from_user) - uaccess_enable_not_uao x3, x4 + uaccess_enable_not_uao x3, x4, x5 add end, x0, x2 #include "copy_template.S" uaccess_disable_not_uao x3 diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index 718b1c4e2f85a7aa44be720815ba1c9dc9909c4a..074d52fcd75ba16dfcd5c81e6386e661a6c30f8a 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -65,7 +65,7 @@ end .req x5 ENTRY(__copy_in_user) - uaccess_enable_not_uao x3, x4 + uaccess_enable_not_uao x3, x4, x5 add end, x0, x2 #include "copy_template.S" uaccess_disable_not_uao x3 diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index e99e31c9acac81a26a762524471bec471735b541..67118444cde0ccfb6828a63df4bb9b65408ca666 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -63,7 +63,7 @@ end .req x5 ENTRY(__arch_copy_to_user) - uaccess_enable_not_uao x3, x4 + uaccess_enable_not_uao x3, x4, x5 add end, x0, x2 #include "copy_template.S" uaccess_disable_not_uao x3 diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 97de0eb50e98445a00caf3061cd09de019538ada..9dd6d3282d2e3040095df9f6d9b3adef105a513b 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -122,7 +122,7 @@ ENTRY(flush_icache_range) * - end - virtual end address of region */ ENTRY(__flush_cache_user_range) - uaccess_ttbr0_enable x2, x3 + uaccess_ttbr0_enable x2, x3, x4 dcache_line_size x2, x3 sub x3, x2, #1 bic x4, x0, x3 diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index 4c63cb1548598283085811f44bea3bd7d65af0a5..da5add9d36d2a446b8cbae336c60d9a8ed45774f 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -39,7 +39,16 @@ static cpumask_t tlb_flush_pending; #define ASID_MASK (~GENMASK(asid_bits - 1, 0)) #define ASID_FIRST_VERSION (1UL << asid_bits) -#define NUM_USER_ASIDS ASID_FIRST_VERSION + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define NUM_USER_ASIDS (ASID_FIRST_VERSION >> 1) +#define asid2idx(asid) (((asid) & ~ASID_MASK) >> 1) +#define idx2asid(idx) (((idx) << 1) & ~ASID_MASK) +#else +#define NUM_USER_ASIDS (ASID_FIRST_VERSION) +#define asid2idx(asid) ((asid) & ~ASID_MASK) +#define idx2asid(idx) asid2idx(idx) +#endif /* Get the ASIDBits supported by the current CPU */ static u32 get_cpu_asid_bits(void) @@ -104,7 +113,7 @@ static void flush_context(unsigned int cpu) */ if (asid == 0) asid = per_cpu(reserved_asids, i); - __set_bit(asid & ~ASID_MASK, asid_map); + __set_bit(asid2idx(asid), asid_map); per_cpu(reserved_asids, i) = asid; } @@ -159,16 +168,16 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) * We had a valid ASID in a previous life, so try to re-use * it if possible. */ - asid &= ~ASID_MASK; - if (!__test_and_set_bit(asid, asid_map)) + if (!__test_and_set_bit(asid2idx(asid), asid_map)) return newasid; } /* * Allocate a free ASID. If we can't find one, take a note of the - * currently active ASIDs and mark the TLBs as requiring flushes. - * We always count from ASID #1, as we use ASID #0 when setting a - * reserved TTBR0 for the init_mm. + * currently active ASIDs and mark the TLBs as requiring flushes. We + * always count from ASID #2 (index 1), as we use ASID #0 when setting + * a reserved TTBR0 for the init_mm and we allocate ASIDs in even/odd + * pairs. */ asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx); if (asid != NUM_USER_ASIDS) @@ -185,7 +194,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) set_asid: __set_bit(asid, asid_map); cur_idx = asid; - return asid | generation; + return idx2asid(asid) | generation; } void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) @@ -229,6 +238,17 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) cpu_switch_mm(mm->pgd, mm); } +/* Errata workaround post TTBRx_EL1 update. */ +asmlinkage void post_ttbr_update_workaround(void) +{ + asm(ALTERNATIVE("nop; nop; nop", + "ic iallu; dsb nsh; isb", + ARM64_WORKAROUND_CAVIUM_27456, + CONFIG_CAVIUM_ERRATUM_27456)); + + arm64_apply_bp_hardening(); +} + static int asids_init(void) { asid_bits = get_cpu_asid_bits(); diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 40e775a331c6d40e30b0cdd368b3641dbd5f4fae..31d468415cc3d4d290b5c4aeba9e0465ecc6e9a0 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -31,13 +31,15 @@ #include #include #include +#include #include #include #include #include #include - +#include +#include static int swiotlb __ro_after_init; @@ -157,17 +159,13 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) { - if (dev == NULL) { - WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); - return NULL; - } + void *addr; if (IS_ENABLED(CONFIG_ZONE_DMA) && dev->coherent_dma_mask <= DMA_BIT_MASK(32)) flags |= GFP_DMA; if (dev_get_cma_area(dev) && gfpflags_allow_blocking(flags)) { struct page *page; - void *addr; page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, get_order(size)); @@ -177,20 +175,20 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size, *dma_handle = phys_to_dma(dev, page_to_phys(page)); addr = page_address(page); memset(addr, 0, size); - - if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) || - (attrs & DMA_ATTR_STRONGLY_ORDERED)) { - /* - * flush the caches here because we can't later - */ - __dma_flush_area(addr, size); - __dma_remap(page, size, __pgprot(0), true); - } - - return addr; } else { - return swiotlb_alloc_coherent(dev, size, dma_handle, flags); + addr = swiotlb_alloc_coherent(dev, size, dma_handle, flags); } + + if (addr && ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) || + (attrs & DMA_ATTR_STRONGLY_ORDERED))) { + /* + * flush the caches here because we can't later + */ + __dma_flush_area(addr, size); + __dma_remap(virt_to_page(addr), size, __pgprot(0), true); + } + + return addr; } static void __dma_free_coherent(struct device *dev, size_t size, @@ -201,10 +199,6 @@ static void __dma_free_coherent(struct device *dev, size_t size, phys_addr_t paddr = dma_to_phys(dev, dma_handle); size = PAGE_ALIGN(size); - if (dev == NULL) { - WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); - return; - } if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) || (attrs & DMA_ATTR_STRONGLY_ORDERED)) @@ -943,6 +937,8 @@ static struct dma_map_ops iommu_dma_ops = { .sync_single_for_device = __iommu_sync_single_for_device, .sync_sg_for_cpu = __iommu_sync_sg_for_cpu, .sync_sg_for_device = __iommu_sync_sg_for_device, + .map_resource = iommu_dma_map_resource, + .unmap_resource = iommu_dma_unmap_resource, .dma_supported = iommu_dma_supported, .mapping_error = iommu_dma_mapping_error, }; @@ -975,14 +971,21 @@ static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops, * then the IOMMU core will have already configured a group for this * device, and allocated the default domain for that group. */ - if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) { - pr_debug("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", - dev_name(dev)); - return false; + if (!domain) + goto out_err; + + if (domain->type == IOMMU_DOMAIN_DMA) { + if (iommu_dma_init_domain(domain, dma_base, size, dev)) + goto out_err; + + dev->archdata.dma_ops = &iommu_dma_ops; } - dev->archdata.dma_ops = &iommu_dma_ops; return true; +out_err: + pr_debug("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", + dev_name(dev)); + return false; } static void queue_iommu_attach(struct device *dev, const struct iommu_ops *ops, @@ -1151,16 +1154,6 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off, set_bit(PG_dcache_clean, &page->flags); } -static int arm_dma_set_mask(struct device *dev, u64 dma_mask) -{ - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - - *dev->dma_mask = dma_mask; - - return 0; -} - /* IOMMU */ static void __dma_clear_buffer(struct page *page, size_t size, @@ -1181,15 +1174,24 @@ static void __dma_clear_buffer(struct page *page, size_t size, static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, size_t size) { - unsigned int order = get_order(size); + unsigned int order; unsigned int align = 0; unsigned int count, start; unsigned long flags; + dma_addr_t iova; + size_t guard_len; + + size = PAGE_ALIGN(size); + if (mapping->min_iova_align) + guard_len = ALIGN(size, mapping->min_iova_align) - size; + else + guard_len = 0; + order = get_order(size + guard_len); if (order > CONFIG_ARM64_DMA_IOMMU_ALIGNMENT) order = CONFIG_ARM64_DMA_IOMMU_ALIGNMENT; - count = PAGE_ALIGN(size) >> PAGE_SHIFT; + count = PAGE_ALIGN(size + guard_len) >> PAGE_SHIFT; align = (1 << order) - 1; spin_lock_irqsave(&mapping->lock, flags); @@ -1203,16 +1205,41 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, bitmap_set(mapping->bitmap, start, count); spin_unlock_irqrestore(&mapping->lock, flags); - return mapping->base + (start << PAGE_SHIFT); + iova = mapping->base + (start << PAGE_SHIFT); + + if (guard_len && + iommu_map(mapping->domain, iova + size, + page_to_phys(mapping->guard_page), + guard_len, ARM_SMMU_GUARD_PROT)) { + + spin_lock_irqsave(&mapping->lock, flags); + bitmap_clear(mapping->bitmap, start, count); + spin_unlock_irqrestore(&mapping->lock, flags); + return DMA_ERROR_CODE; + } + + return iova; } static inline void __free_iova(struct dma_iommu_mapping *mapping, dma_addr_t addr, size_t size) { - unsigned int start = (addr - mapping->base) >> PAGE_SHIFT; - unsigned int count = size >> PAGE_SHIFT; + unsigned int start; + unsigned int count; unsigned long flags; + size_t guard_len; + + addr = addr & PAGE_MASK; + size = PAGE_ALIGN(size); + if (mapping->min_iova_align) { + guard_len = ALIGN(size, mapping->min_iova_align) - size; + iommu_unmap(mapping->domain, addr + size, guard_len); + } else { + guard_len = 0; + } + start = (addr - mapping->base) >> PAGE_SHIFT; + count = (size + guard_len) >> PAGE_SHIFT; spin_lock_irqsave(&mapping->lock, flags); bitmap_clear(mapping->bitmap, start, count); spin_unlock_irqrestore(&mapping->lock, flags); @@ -1808,10 +1835,8 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, mapping->domain, iova)); int offset = handle & ~PAGE_MASK; int len = PAGE_ALIGN(size + offset); - bool iova_coherent = iommu_is_iova_coherent(mapping->domain, - handle); - if (!(iova_coherent || + if (!(is_dma_coherent(dev, attrs) || (attrs & DMA_ATTR_SKIP_CPU_SYNC))) __dma_page_dev_to_cpu(page, offset, size, dir); @@ -1847,6 +1872,45 @@ static void arm_iommu_sync_single_for_device(struct device *dev, __dma_page_cpu_to_dev(page, offset, size, dir); } +static dma_addr_t arm_iommu_dma_map_resource( + struct device *dev, phys_addr_t phys_addr, + size_t size, enum dma_data_direction dir, + unsigned long attrs) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + size_t offset = phys_addr & ~PAGE_MASK; + size_t len = PAGE_ALIGN(size + offset); + dma_addr_t dma_addr; + int prot; + + dma_addr = __alloc_iova(mapping, len); + if (dma_addr == DMA_ERROR_CODE) + return dma_addr; + + prot = __dma_direction_to_prot(dir); + prot |= IOMMU_MMIO; + + if (iommu_map(mapping->domain, dma_addr, phys_addr - offset, + len, prot)) { + __free_iova(mapping, dma_addr, len); + return DMA_ERROR_CODE; + } + return dma_addr + offset; +} + +static void arm_iommu_dma_unmap_resource( + struct device *dev, dma_addr_t addr, + size_t size, enum dma_data_direction dir, + unsigned long attrs) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + size_t offset = addr & ~PAGE_MASK; + size_t len = PAGE_ALIGN(size + offset); + + iommu_unmap(mapping->domain, addr - offset, len); + __free_iova(mapping, addr - offset, len); +} + static int arm_iommu_mapping_error(struct device *dev, dma_addr_t dma_addr) { @@ -1869,7 +1933,9 @@ const struct dma_map_ops iommu_ops = { .sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu, .sync_sg_for_device = arm_iommu_sync_sg_for_device, - .set_dma_mask = arm_dma_set_mask, + .map_resource = arm_iommu_dma_map_resource, + .unmap_resource = arm_iommu_dma_unmap_resource, + .mapping_error = arm_iommu_mapping_error, }; @@ -1883,23 +1949,59 @@ const struct dma_map_ops iommu_ops = { * IO address ranges, which is required to perform memory allocation and * mapping with IOMMU aware functions. * - * The client device need to be attached to the mapping with - * arm_iommu_attach_device function. + * Clients may use iommu_domain_set_attr() to set additional flags prior + * to calling arm_iommu_attach_device() to complete initialization. */ struct dma_iommu_mapping * arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) { unsigned int bits = size >> PAGE_SHIFT; - unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); struct dma_iommu_mapping *mapping; - int err = -ENOMEM; - if (!bitmap_size) + if (!bits) return ERR_PTR(-EINVAL); mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL); if (!mapping) - goto err; + return ERR_PTR(-ENOMEM); + + mapping->base = base; + mapping->bits = bits; + + mapping->domain = iommu_domain_alloc(bus); + if (!mapping->domain) + goto err_domain_alloc; + + mapping->init = false; + return mapping; + +err_domain_alloc: + kfree(mapping); + return ERR_PTR(-ENOMEM); +} +EXPORT_SYMBOL(arm_iommu_create_mapping); + +static int +bitmap_iommu_init_mapping(struct device *dev, struct dma_iommu_mapping *mapping) +{ + unsigned int bitmap_size = BITS_TO_LONGS(mapping->bits) * sizeof(long); + int vmid = VMID_HLOS; + int min_iova_align = 0; + + iommu_domain_get_attr(mapping->domain, + DOMAIN_ATTR_MMU500_ERRATA_MIN_ALIGN, + &min_iova_align); + iommu_domain_get_attr(mapping->domain, + DOMAIN_ATTR_SECURE_VMID, &vmid); + if (vmid >= VMID_LAST || vmid < 0) + vmid = VMID_HLOS; + + if (min_iova_align) { + mapping->min_iova_align = ARM_SMMU_MIN_IOVA_ALIGN; + mapping->guard_page = arm_smmu_errata_get_guard_page(vmid); + if (!mapping->guard_page) + return -ENOMEM; + } mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); @@ -1907,44 +2009,147 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) mapping->bitmap = vzalloc(bitmap_size); if (!mapping->bitmap) - goto err2; + return -ENOMEM; - mapping->base = base; - mapping->bits = bits; spin_lock_init(&mapping->lock); + mapping->ops = &iommu_ops; + return 0; +} - mapping->domain = iommu_domain_alloc(bus); - if (!mapping->domain) - goto err3; +static void bitmap_iommu_release_mapping(struct kref *kref) +{ + struct dma_iommu_mapping *mapping = + container_of(kref, struct dma_iommu_mapping, kref); - kref_init(&mapping->kref); - return mapping; -err3: - kvfree(mapping->bitmap); -err2: + kfree(mapping->bitmap); + iommu_domain_free(mapping->domain); kfree(mapping); -err: - return ERR_PTR(err); } -EXPORT_SYMBOL(arm_iommu_create_mapping); -static void release_iommu_mapping(struct kref *kref) +static void bypass_iommu_release_mapping(struct kref *kref) { struct dma_iommu_mapping *mapping = container_of(kref, struct dma_iommu_mapping, kref); iommu_domain_free(mapping->domain); - kvfree(mapping->bitmap); kfree(mapping); } +static int upstream_iommu_init_mapping(struct device *dev, + struct dma_iommu_mapping *mapping) +{ + struct iommu_domain *domain = mapping->domain; + dma_addr_t base = mapping->base; + u64 size = mapping->bits << PAGE_SHIFT; + + if (iommu_get_dma_cookie(domain)) + return -EINVAL; + + if (iommu_dma_init_domain(domain, base, size, dev)) + goto out_put_cookie; + + mapping->ops = &iommu_dma_ops; + return 0; + +out_put_cookie: + iommu_put_dma_cookie(domain); + return -EINVAL; +} + +static void upstream_iommu_release_mapping(struct kref *kref) +{ + struct dma_iommu_mapping *mapping = + container_of(kref, struct dma_iommu_mapping, kref); + + iommu_put_dma_cookie(mapping->domain); + iommu_domain_free(mapping->domain); + kfree(mapping); +} + +/* + * arm_iommu_release_mapping + * @mapping: allocted via arm_iommu_create_mapping() + * + * Frees all resources associated with the iommu mapping. + * The device associated with this mapping must be in the 'detached' state + */ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping) { - if (mapping) - kref_put(&mapping->kref, release_iommu_mapping); + int s1_bypass = 0, is_fast = 0, is_upstream = 0; + void (*release)(struct kref *kref); + + if (!mapping) + return; + + if (!mapping->init) { + iommu_domain_free(mapping->domain); + kfree(mapping); + return; + } + + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); + iommu_domain_get_attr(mapping->domain, + DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR, + &is_upstream); + + if (s1_bypass) + release = bypass_iommu_release_mapping; + else if (is_fast) + release = fast_smmu_release_mapping; + else if (is_upstream) + release = upstream_iommu_release_mapping; + else + release = bitmap_iommu_release_mapping; + + kref_put(&mapping->kref, release); } EXPORT_SYMBOL(arm_iommu_release_mapping); +static int arm_iommu_init_mapping(struct device *dev, + struct dma_iommu_mapping *mapping) +{ + int err = -EINVAL; + int s1_bypass = 0, is_fast = 0, is_upstream = 0; + dma_addr_t iova_end; + + if (mapping->init) { + kref_get(&mapping->kref); + return 0; + } + + iova_end = mapping->base + (mapping->bits << PAGE_SHIFT) - 1; + if (iova_end > dma_get_mask(dev)) { + dev_err(dev, "dma mask %llx too small for requested iova range %pad to %pad\n", + dma_get_mask(dev), &mapping->base, &iova_end); + return -EINVAL; + } + + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); + iommu_domain_get_attr(mapping->domain, + DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR, + &is_upstream); + + if (s1_bypass) { + mapping->ops = &swiotlb_dma_ops; + err = 0; + } else if (is_fast) { + err = fast_smmu_init_mapping(dev, mapping); + } else if (is_upstream) { + err = upstream_iommu_init_mapping(dev, mapping); + } else { + err = bitmap_iommu_init_mapping(dev, mapping); + } + if (!err) { + kref_init(&mapping->kref); + mapping->init = true; + } + return err; +} + /** * arm_iommu_attach_device * @dev: valid struct device pointer @@ -1953,30 +2158,41 @@ EXPORT_SYMBOL(arm_iommu_release_mapping); * * Attaches specified io address space mapping to the provided device, * this replaces the dma operations (dma_map_ops pointer) with the - * IOMMU aware version. More than one client might be attached to - * the same io address space mapping. + * IOMMU aware version. + * + * Clients are expected to call arm_iommu_attach_device() prior to sharing + * the dma_iommu_mapping structure with another device. This ensures + * initialization is complete. */ int arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping) { int err; - int s1_bypass = 0, is_fast = 0; + struct iommu_domain *domain = mapping->domain; + struct iommu_group *group = dev->iommu_group; - iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); - if (is_fast) - return fast_smmu_attach_device(dev, mapping); + if (!group) { + dev_err(dev, "No iommu associated with device\n"); + return -EINVAL; + } + + if (iommu_get_domain_for_dev(dev)) { + dev_err(dev, "Device already attached to other iommu_domain\n"); + return -EINVAL; + } - err = iommu_attach_device(mapping->domain, dev); + err = iommu_attach_group(domain, group); if (err) return err; - iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, - &s1_bypass); + err = arm_iommu_init_mapping(dev, mapping); + if (err) { + iommu_detach_group(domain, group); + return err; + } - kref_get(&mapping->kref); dev->archdata.mapping = mapping; - if (!s1_bypass) - set_dma_ops(dev, &iommu_ops); + set_dma_ops(dev, mapping->ops); pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); return 0; @@ -1993,7 +2209,7 @@ EXPORT_SYMBOL(arm_iommu_attach_device); void arm_iommu_detach_device(struct device *dev) { struct dma_iommu_mapping *mapping; - int is_fast, s1_bypass = 0; + int s1_bypass = 0; mapping = to_dma_iommu_mapping(dev); if (!mapping) { @@ -2001,20 +2217,22 @@ void arm_iommu_detach_device(struct device *dev) return; } - iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast); - if (is_fast) { - fast_smmu_detach_device(dev, mapping); + if (!dev->iommu_group) { + dev_err(dev, "No iommu associated with device\n"); return; } iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, &s1_bypass); + /* + * ION defers dma_unmap calls. Ensure they have all completed prior to + * setting dma_ops to NULL. + */ if (msm_dma_unmap_all_for_dev(dev)) dev_warn(dev, "IOMMU detach with outstanding mappings\n"); - iommu_detach_device(mapping->domain, dev); - kref_put(&mapping->kref, release_iommu_mapping); + iommu_detach_group(mapping->domain, dev->iommu_group); dev->archdata.mapping = NULL; if (!s1_bypass) set_dma_ops(dev, NULL); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 0a34644b7db28555bfca1afbb88a1777b4701603..2b8950ed5e720c8efc26ac5eba11979894b48eda 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -40,8 +40,8 @@ #include #include #include -#include #include +#include struct fault_info { int (*fn)(unsigned long addr, unsigned int esr, @@ -103,21 +103,21 @@ void show_pte(struct mm_struct *mm, unsigned long addr) break; pud = pud_offset(pgd, addr); - printk(", *pud=%016llx", pud_val(*pud)); + pr_cont(", *pud=%016llx", pud_val(*pud)); if (pud_none(*pud) || pud_bad(*pud)) break; pmd = pmd_offset(pud, addr); - printk(", *pmd=%016llx", pmd_val(*pmd)); + pr_cont(", *pmd=%016llx", pmd_val(*pmd)); if (pmd_none(*pmd) || pmd_bad(*pmd)) break; pte = pte_offset_map(pmd, addr); - printk(", *pte=%016llx", pte_val(*pte)); + pr_cont(", *pte=%016llx", pte_val(*pte)); pte_unmap(pte); } while(0); - printk("\n"); + pr_cont("\n"); } #ifdef CONFIG_ARM64_HW_AFDBM @@ -213,6 +213,8 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr, struct siginfo si; const struct fault_info *inf; + trace_user_fault(tsk, addr, esr); + if (unhandled_signal(tsk, sig) && show_unhandled_signals_ratelimited()) { inf = esr_to_fault_info(esr); pr_info("%s[%d]: unhandled %s (%d) at 0x%08lx, esr 0x%03x\n", @@ -382,8 +384,11 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, * signal first. We do not need to release the mmap_sem because it * would already be released in __lock_page_or_retry in mm/filemap.c. */ - if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) { + if (!user_mode(regs)) + goto no_context; return 0; + } /* * Major/minor page fault accounting is only done on the initial @@ -468,7 +473,7 @@ static int do_tlb_conf_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) { -#define SCM_TLB_CONFLICT_CMD 0x1B +#define SCM_TLB_CONFLICT_CMD 0x1F struct scm_desc desc = { .args[0] = addr, .arginfo = SCM_ARGS(1), @@ -521,7 +526,6 @@ static int do_alignment_fault(unsigned long addr, unsigned int esr, */ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) { - kryo3xx_poll_cache_errors(NULL); return 1; } @@ -533,7 +537,7 @@ static const struct fault_info fault_info[] = { { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, - { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, { do_bad, SIGBUS, 0, "unknown 8" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, @@ -614,6 +618,22 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, arm64_notify_die("", regs, &info, esr); } +asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) +{ + /* + * We've taken an instruction abort from userspace and not yet + * re-enabled IRQs. If the address is a kernel address, apply + * BP hardening prior to enabling IRQs and pre-emption. + */ + if (addr > TASK_SIZE) + arm64_apply_bp_hardening(); + + local_irq_enable(); + do_mem_abort(addr, esr, regs); +} + /* * Handle stack alignment exceptions. */ diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 0b9492e85ffce4add905f89957ceb09b53bcf832..2b35b67540b9c8c03ea97a893f3d8fdbaa691afe 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -211,8 +212,8 @@ void __init arm64_memblock_init(void) * linear mapping. Take care not to clip the kernel which may be * high in memory. */ - memblock_remove(max_t(u64, memstart_addr + linear_region_size, __pa(_end)), - ULLONG_MAX); + memblock_remove(max_t(u64, memstart_addr + linear_region_size, + __pa_symbol(_end)), ULLONG_MAX); if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) { /* ensure that memstart_addr remains sufficiently aligned */ memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size, @@ -227,7 +228,7 @@ void __init arm64_memblock_init(void) */ if (memory_limit != (phys_addr_t)ULLONG_MAX) { memblock_mem_limit_remove_map(memory_limit); - memblock_add(__pa(_text), (u64)(_end - _text)); + memblock_add(__pa_symbol(_text), (u64)(_end - _text)); } if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && initrd_start) { @@ -280,7 +281,7 @@ void __init arm64_memblock_init(void) * Register the kernel text, kernel data, initrd, and initial * pagetables with memblock. */ - memblock_reserve(__pa(_text), _end - _text); + memblock_reserve(__pa_symbol(_text), _end - _text); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { memblock_reserve(initrd_start, initrd_end - initrd_start); @@ -298,6 +299,7 @@ void __init arm64_memblock_init(void) arm64_dma_phys_limit = max_zone_dma_phys(); else arm64_dma_phys_limit = PHYS_MASK + 1; + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; dma_contiguous_reserve(arm64_dma_phys_limit); memblock_allow_resize(); @@ -324,7 +326,6 @@ void __init bootmem_init(void) sparse_init(); zone_sizes_init(min, max); - high_memory = __va((max << PAGE_SHIFT) - 1) + 1; memblock_dump_all(); } @@ -488,7 +489,8 @@ void __init mem_init(void) void free_initmem(void) { - free_reserved_area(__va(__pa(__init_begin)), __va(__pa(__init_end)), + free_reserved_area(lm_alias(__init_begin), + lm_alias(__init_end), 0, "unused kernel"); /* * Unmap the __init region but leave the VM area in place. This diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c index 757009daa9ede454abccbcab6b3a0421a355b49c..201d918e75759d4938e62575083ede5b7775aff5 100644 --- a/arch/arm64/mm/kasan_init.c +++ b/arch/arm64/mm/kasan_init.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,13 @@ static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE); +/* + * The p*d_populate functions call virt_to_phys implicitly so they can't be used + * directly on kernel symbols (bm_p*d). All the early functions are called too + * early to use lm_alias so __p*d_populate functions must be used to populate + * with the physical address from __pa_symbol. + */ + static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long end) { @@ -33,12 +41,12 @@ static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long next; if (pmd_none(*pmd)) - pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte); + __pmd_populate(pmd, __pa_symbol(kasan_zero_pte), PMD_TYPE_TABLE); pte = pte_offset_kimg(pmd, addr); do { next = addr + PAGE_SIZE; - set_pte(pte, pfn_pte(virt_to_pfn(kasan_zero_page), + set_pte(pte, pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL)); } while (pte++, addr = next, addr != end && pte_none(*pte)); } @@ -51,7 +59,7 @@ static void __init kasan_early_pmd_populate(pud_t *pud, unsigned long next; if (pud_none(*pud)) - pud_populate(&init_mm, pud, kasan_zero_pmd); + __pud_populate(pud, __pa_symbol(kasan_zero_pmd), PMD_TYPE_TABLE); pmd = pmd_offset_kimg(pud, addr); do { @@ -68,7 +76,7 @@ static void __init kasan_early_pud_populate(pgd_t *pgd, unsigned long next; if (pgd_none(*pgd)) - pgd_populate(&init_mm, pgd, kasan_zero_pud); + __pgd_populate(pgd, __pa_symbol(kasan_zero_pud), PUD_TYPE_TABLE); pud = pud_offset_kimg(pgd, addr); do { @@ -148,7 +156,7 @@ void __init kasan_init(void) */ memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir)); dsb(ishst); - cpu_replace_ttbr1(tmp_pg_dir); + cpu_replace_ttbr1(lm_alias(tmp_pg_dir)); clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); @@ -199,10 +207,10 @@ void __init kasan_init(void) */ for (i = 0; i < PTRS_PER_PTE; i++) set_pte(&kasan_zero_pte[i], - pfn_pte(virt_to_pfn(kasan_zero_page), PAGE_KERNEL_RO)); + pfn_pte(sym_to_pfn(kasan_zero_page), PAGE_KERNEL_RO)); memset(kasan_zero_page, 0, PAGE_SIZE); - cpu_replace_ttbr1(swapper_pg_dir); + cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); /* At this point kasan is fully initialized. Enable error messages */ init_task.kasan_depth = 0; diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index f70b433ed06739f65d750004392b7b026e80efda..c66fa93c907e47fa54b2b03a6046bb11a730eaab 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -357,8 +358,8 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt, static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end) { - unsigned long kernel_start = __pa(_text); - unsigned long kernel_end = __pa(__init_begin); + unsigned long kernel_start = __pa_symbol(_text); + unsigned long kernel_end = __pa_symbol(__init_begin); /* * Take care not to create a writable alias for the @@ -425,21 +426,21 @@ void mark_rodata_ro(void) unsigned long section_size; section_size = (unsigned long)_etext - (unsigned long)_text; - create_mapping_late(__pa(_text), (unsigned long)_text, + create_mapping_late(__pa_symbol(_text), (unsigned long)_text, section_size, PAGE_KERNEL_ROX); /* * mark .rodata as read only. Use __init_begin rather than __end_rodata * to cover NOTES and EXCEPTION_TABLE. */ section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata; - create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata, + create_mapping_late(__pa_symbol(__start_rodata), (unsigned long)__start_rodata, section_size, PAGE_KERNEL_RO); } static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end, pgprot_t prot, struct vm_struct *vma) { - phys_addr_t pa_start = __pa(va_start); + phys_addr_t pa_start = __pa_symbol(va_start); unsigned long size = va_end - va_start; BUG_ON(!PAGE_ALIGNED(pa_start)); @@ -457,6 +458,37 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end, vm_area_add_early(vma); } +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +static int __init map_entry_trampoline(void) +{ + extern char __entry_tramp_text_start[]; + + pgprot_t prot = PAGE_KERNEL_EXEC; + phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start); + + /* The trampoline is always mapped and can therefore be global */ + pgprot_val(prot) &= ~PTE_NG; + + /* Map only the text into the trampoline page table */ + memset(tramp_pg_dir, 0, PGD_SIZE); + __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE, + prot, pgd_pgtable_alloc, 0); + + /* Map both the text and data into the kernel page table */ + __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot); + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { + extern char __entry_tramp_data_start[]; + + __set_fixmap(FIX_ENTRY_TRAMP_DATA, + __pa_symbol(__entry_tramp_data_start), + PAGE_KERNEL_RO); + } + + return 0; +} +core_initcall(map_entry_trampoline); +#endif + /* * Create fine-grained mappings for the kernel. */ @@ -487,7 +519,7 @@ static void __init map_kernel(pgd_t *pgd) */ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START), - __pud(__pa(bm_pmd) | PUD_TYPE_TABLE)); + __pud(__pa_symbol(bm_pmd) | PUD_TYPE_TABLE)); pud_clear_fixmap(); } else { BUG(); @@ -518,7 +550,7 @@ void __init paging_init(void) */ cpu_replace_ttbr1(__va(pgd_phys)); memcpy(swapper_pg_dir, pgd, PAGE_SIZE); - cpu_replace_ttbr1(swapper_pg_dir); + cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); pgd_clear_fixmap(); memblock_free(pgd_phys, PAGE_SIZE); @@ -527,7 +559,7 @@ void __init paging_init(void) * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd * allocated with it. */ - memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE, + memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE, SWAPPER_DIR_SIZE - PAGE_SIZE); } @@ -638,6 +670,12 @@ static inline pte_t * fixmap_pte(unsigned long addr) return &bm_pte[pte_index(addr)]; } +/* + * The p*d_populate functions call virt_to_phys implicitly so they can't be used + * directly on kernel symbols (bm_p*d). This function is called too early to use + * lm_alias so __p*d_populate functions must be used to populate with the + * physical address from __pa_symbol. + */ void __init early_fixmap_init(void) { pgd_t *pgd; @@ -647,7 +685,7 @@ void __init early_fixmap_init(void) pgd = pgd_offset_k(addr); if (CONFIG_PGTABLE_LEVELS > 3 && - !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa(bm_pud))) { + !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) { /* * We only end up here if the kernel mapping and the fixmap * share the top level pgd entry, which should only happen on @@ -656,12 +694,14 @@ void __init early_fixmap_init(void) BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); pud = pud_offset_kimg(pgd, addr); } else { - pgd_populate(&init_mm, pgd, bm_pud); + if (pgd_none(*pgd)) + __pgd_populate(pgd, __pa_symbol(bm_pud), PUD_TYPE_TABLE); pud = fixmap_pud(addr); } - pud_populate(&init_mm, pud, bm_pmd); + if (pud_none(*pud)) + __pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE); pmd = fixmap_pmd(addr); - pmd_populate_kernel(&init_mm, pmd, bm_pte); + __pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE); /* * The boot-ioremap range spans multiple pmds, for which diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 61330c90f6a35da9a319790ab73581f7ec08133e..fa20d134f2d1e5764066953db8701ddee269063f 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -116,11 +116,14 @@ ENTRY(cpu_do_suspend) mrs x8, mdscr_el1 mrs x9, oslsr_el1 mrs x10, sctlr_el1 + mrs x11, tpidr_el1 + mrs x12, sp_el0 stp x2, x3, [x0] stp x4, xzr, [x0, #16] stp x5, x6, [x0, #32] stp x7, x8, [x0, #48] stp x9, x10, [x0, #64] + stp x11, x12, [x0, #80] ret ENDPROC(cpu_do_suspend) @@ -136,6 +139,7 @@ ENTRY(cpu_do_resume) ldp x6, x8, [x0, #32] ldp x9, x10, [x0, #48] ldp x11, x12, [x0, #64] + ldp x13, x14, [x0, #80] msr tpidr_el0, x2 msr tpidrro_el0, x3 msr contextidr_el1, x4 @@ -158,6 +162,8 @@ ENTRY(cpu_do_resume) msr mdscr_el1, x10 msr sctlr_el1, x12 + msr tpidr_el1, x13 + msr sp_el0, x14 /* * Restore oslsr_el1 by writing oslar_el1 */ @@ -178,12 +184,14 @@ ENDPROC(cpu_do_resume) * - pgd_phys - physical address of new TTB */ ENTRY(cpu_do_switch_mm) + mrs x2, ttbr1_el1 mmid x1, x1 // get mm->context.id - bfi x0, x1, #48, #16 // set the ASID - msr ttbr0_el1, x0 // set TTBR0 + bfi x2, x1, #48, #16 // set the ASID + msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set) isb - post_ttbr0_update_workaround - ret + msr ttbr0_el1, x0 // now update TTBR0 + isb + b post_ttbr_update_workaround // Back to C code... ENDPROC(cpu_do_switch_mm) .pushsection ".idmap.text", "ax" @@ -264,7 +272,7 @@ ENTRY(__cpu_setup) * both user and kernel. */ ldr x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ - TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 + TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | TCR_A1 tcr_set_idmap_t0sz x10, x9 /* diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index b2fc97a2c56c80fe633777bbb18322c980949953..d8199e12fb6ef906087a0c071c8669553b3ee6fa 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -252,8 +252,9 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) */ off = offsetof(struct bpf_array, ptrs); emit_a64_mov_i64(tmp, off, ctx); - emit(A64_LDR64(tmp, r2, tmp), ctx); - emit(A64_LDR64(prg, tmp, r3), ctx); + emit(A64_ADD(1, tmp, r2, tmp), ctx); + emit(A64_LSL(1, prg, r3, 3), ctx); + emit(A64_LDR64(prg, tmp, prg), ctx); emit(A64_CBZ(1, prg, jmp_offset), ctx); /* goto *(prog->bpf_func + prologue_size); */ @@ -779,14 +780,14 @@ static int build_body(struct jit_ctx *ctx) int ret; ret = build_insn(insn, ctx); - - if (ctx->image == NULL) - ctx->offset[i] = ctx->idx; - if (ret > 0) { i++; + if (ctx->image == NULL) + ctx->offset[i] = ctx->idx; continue; } + if (ctx->image == NULL) + ctx->offset[i] = ctx->idx; if (ret) return ret; } diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S index b41aff25426d6b360b24cf69300a51419a58eada..f5422520cb01c6c27dced8c0dc64982d93ff65b9 100644 --- a/arch/arm64/xen/hypercall.S +++ b/arch/arm64/xen/hypercall.S @@ -100,7 +100,7 @@ ENTRY(privcmd_call) * need the explicit uaccess_enable/disable if the TTBR0 PAN emulation * is enabled (it implies that hardware UAO and PAN disabled). */ - uaccess_ttbr0_enable x6, x7 + uaccess_ttbr0_enable x6, x7, x8 hvc XEN_IMM /* diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h index 1fd147f09a3805d75f1e8150a825250a6e38121b..5f10f9bcd417068202b91175cea30d2302f17e6b 100644 --- a/arch/avr32/include/uapi/asm/socket.h +++ b/arch/avr32/include/uapi/asm/socket.h @@ -90,4 +90,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _UAPI__ASM_AVR32_SOCKET_H */ diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 3c1bd640042a0dc9f0c0866c8c93c7346cf1171a..88c4b77ec8d2d231c11a3f0cb06bef87706db101 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -319,11 +319,14 @@ config BF53x config GPIO_ADI def_bool y + depends on !PINCTRL depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561) -config PINCTRL +config PINCTRL_BLACKFIN_ADI2 def_bool y - depends on BF54x || BF60x + depends on (BF54x || BF60x) + select PINCTRL + select PINCTRL_ADI2 config MEM_MT48LC64M4A2FB_7E bool diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index f3337ee03621d5f79a31af217bbd4bdf99dee79b..a93cf06a4d6fde552a284c6d48377e9636d41160 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -17,6 +17,7 @@ config DEBUG_VERBOSE config DEBUG_MMRS tristate "Generate Blackfin MMR tree" + depends on !PINCTRL select DEBUG_FS help Create a tree of Blackfin MMRs via the debugfs tree. If diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 1c2a5e264fc71cfd52f2acb0b24ddb1aff792be7..e93c9494503ac8fc3cfaa8167ea3523abb3e2925 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -139,7 +139,7 @@ static inline void atomic64_dec(atomic64_t *v) #define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_and_test(v) (atomic64_inc_return((v)) == 0) - +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) #define atomic_cmpxchg(v, old, new) (cmpxchg(&(v)->counter, old, new)) #define atomic_xchg(v, new) (xchg(&(v)->counter, new)) @@ -161,6 +161,39 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return c; } +static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u) +{ + long long c, old; + + c = atomic64_read(v); + for (;;) { + if (unlikely(c == u)) + break; + old = atomic64_cmpxchg(v, c, c + i); + if (likely(old == c)) + break; + c = old; + } + return c != u; +} + +static inline long long atomic64_dec_if_positive(atomic64_t *v) +{ + long long c, old, dec; + + c = atomic64_read(v); + for (;;) { + dec = c - 1; + if (unlikely(dec < 0)) + break; + old = atomic64_cmpxchg((v), c, dec); + if (likely(old == c)) + break; + c = old; + } + return dec; +} + #define ATOMIC_OP(op) \ static inline int atomic_fetch_##op(int i, atomic_t *v) \ { \ diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h index afbc98f02d278d097d31add71104f5e4fe4040ea..ed960d3af35df547cc7f53a8c32c1af80445a396 100644 --- a/arch/frv/include/uapi/asm/socket.h +++ b/arch/frv/include/uapi/asm/socket.h @@ -90,5 +90,7 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c index 836f14707a627f156343154f359ac1f7758e9fd4..efa59f1f80226e6c951182ad0124aeccd38c7787 100644 --- a/arch/frv/mm/elf-fdpic.c +++ b/arch/frv/mm/elf-fdpic.c @@ -74,7 +74,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi addr = PAGE_ALIGN(addr); vma = find_vma(current->mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) goto success; } diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h index 0018fad9039f4bd9435d2b6a5976093e56d38db7..9790d139f1c904fbbbf4d33304073dcc1dd6637b 100644 --- a/arch/ia64/include/uapi/asm/socket.h +++ b/arch/ia64/include/uapi/asm/socket.h @@ -99,4 +99,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h index 5fe42fc7b6c5dd29e15edbcfbb8ea4cb370ea25c..ad2567655e658402ec8dc74d4ba9388e63c63c32 100644 --- a/arch/m32r/include/uapi/asm/socket.h +++ b/arch/m32r/include/uapi/asm/socket.h @@ -90,4 +90,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/mm/mcfmmu.c b/arch/m68k/mm/mcfmmu.c index 87131cd3bc8f8686ed65ad98e345b3e4648f5705..6d3a50446b2155adbaa66f29236a43c2e8542ace 100644 --- a/arch/m68k/mm/mcfmmu.c +++ b/arch/m68k/mm/mcfmmu.c @@ -169,7 +169,7 @@ void __init cf_bootmem_alloc(void) max_pfn = max_low_pfn = PFN_DOWN(_ramend); high_memory = (void *)_ramend; - m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6; + m68k_virt_to_node_shift = fls(_ramend - 1) - 6; module_fixup(NULL, __start_fixup, __stop_fixup); /* setup bootmem data */ diff --git a/arch/metag/include/asm/uaccess.h b/arch/metag/include/asm/uaccess.h index 07238b39638cd2c933219bb957bff1d80212d8bc..3db38120592822c82918178bbef3872f244d3c48 100644 --- a/arch/metag/include/asm/uaccess.h +++ b/arch/metag/include/asm/uaccess.h @@ -28,24 +28,32 @@ #define segment_eq(a, b) ((a).seg == (b).seg) -#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS)) -/* - * Explicitly allow NULL pointers here. Parts of the kernel such - * as readv/writev use access_ok to validate pointers, but want - * to allow NULL pointers for various reasons. NULL pointers are - * safe to allow through because the first page is not mappable on - * Meta. - * - * We also wish to avoid letting user code access the system area - * and the kernel half of the address space. - */ -#define __user_bad(addr, size) (((addr) > 0 && (addr) < META_MEMORY_BASE) || \ - ((addr) > PAGE_OFFSET && \ - (addr) < LINCORE_BASE)) - static inline int __access_ok(unsigned long addr, unsigned long size) { - return __kernel_ok || !__user_bad(addr, size); + /* + * Allow access to the user mapped memory area, but not the system area + * before it. The check extends to the top of the address space when + * kernel access is allowed (there's no real reason to user copy to the + * system area in any case). + */ + if (likely(addr >= META_MEMORY_BASE && addr < get_fs().seg && + size <= get_fs().seg - addr)) + return true; + /* + * Explicitly allow NULL pointers here. Parts of the kernel such + * as readv/writev use access_ok to validate pointers, but want + * to allow NULL pointers for various reasons. NULL pointers are + * safe to allow through because the first page is not mappable on + * Meta. + */ + if (!addr) + return true; + /* Allow access to core code memory area... */ + if (addr >= LINCORE_CODE_BASE && addr <= LINCORE_CODE_LIMIT && + size <= LINCORE_CODE_LIMIT + 1 - addr) + return true; + /* ... but no other areas. */ + return false; } #define access_ok(type, addr, size) __access_ok((unsigned long)(addr), \ @@ -186,8 +194,13 @@ do { \ extern long __must_check __strncpy_from_user(char *dst, const char __user *src, long count); -#define strncpy_from_user(dst, src, count) __strncpy_from_user(dst, src, count) - +static inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + if (!access_ok(VERIFY_READ, src, 1)) + return -EFAULT; + return __strncpy_from_user(dst, src, count); +} /* * Return the size of a string (including the ending 0) * diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5a4f2eb9d0d5782aa0f0f15a0d04823c397e9021..5e844f68e847976ffcaf295855851debf787188b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1368,6 +1368,7 @@ config CPU_LOONGSON3 select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC select MIPS_PGD_C0_CONTEXT + select MIPS_L1_CACHE_SHIFT_6 select GPIOLIB help The Loongson 3 processor implements the MIPS64R2 instruction diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 58fca9ad5fcc1650b432afb57743c3476b6b50e1..3446b6fb3acb196140b4611f5d2f2bb0d7d11cd6 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -576,6 +576,7 @@ static int __init ar7_register_uarts(void) uart_port.type = PORT_AR7; uart_port.uartclk = clk_get_rate(bus_clk) / 2; uart_port.iotype = UPIO_MEM32; + uart_port.flags = UPF_FIXED_TYPE; uart_port.regshift = 2; uart_port.line = 0; @@ -654,6 +655,10 @@ static int __init ar7_register_devices(void) u32 val; int res; + res = ar7_gpio_init(); + if (res) + pr_warn("unable to register gpios: %d\n", res); + res = ar7_register_uarts(); if (res) pr_err("unable to setup uart(s): %d\n", res); diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c index a23adc49d50fa2348ac4788d4feb38211318989d..36aabee9cba4a3126cb43aa5313a5c870ac15aef 100644 --- a/arch/mips/ar7/prom.c +++ b/arch/mips/ar7/prom.c @@ -246,8 +246,6 @@ void __init prom_init(void) ar7_init_cmdline(fw_arg0, (char **)fw_arg1); ar7_init_env((struct env_var *)fw_arg2); console_config(); - - ar7_gpio_init(); } #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4))) diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c index cc3a1e33a600ec7a8dd6f73ca12354955065d44d..7e2bb12b64ead47aa658b97a4e6265f8f82a5ce7 100644 --- a/arch/mips/ath79/clock.c +++ b/arch/mips/ath79/clock.c @@ -508,16 +508,19 @@ static void __init ath79_clocks_init_dt_ng(struct device_node *np) ar9330_clk_init(ref_clk, pll_base); else { pr_err("%s: could not find any appropriate clk_init()\n", dnfn); - goto err_clk; + goto err_iounmap; } if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) { pr_err("%s: could not register clk provider\n", dnfn); - goto err_clk; + goto err_iounmap; } return; +err_iounmap: + iounmap(pll_base); + err_clk: clk_put(ref_clk); diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c index d20ae63eb3c2e051579f60cac8eab4360c331b33..46abe9e4e0e0c632921cae5ae9abd6ab3b015ff6 100644 --- a/arch/mips/bcm47xx/leds.c +++ b/arch/mips/bcm47xx/leds.c @@ -330,7 +330,7 @@ bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = { /* Verified on: WRT54GS V1.0 */ static const struct gpio_led bcm47xx_leds_linksys_wrt54g_type_0101[] __initconst = { - BCM47XX_GPIO_LED(0, "green", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), + BCM47XX_GPIO_LED(0, "green", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF), BCM47XX_GPIO_LED(1, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON), BCM47XX_GPIO_LED(7, "green", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF), }; diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index 2728a9a9c7c5bc4f822ab6788e1f889cb39c0a51..145b5ce8eb7e660dda67f6a53aa472f74a413af0 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -128,19 +128,19 @@ quiet_cmd_cpp_its_S = ITS $@ -DADDR_BITS=$(ADDR_BITS) \ -DADDR_CELLS=$(itb_addr_cells) -$(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE +$(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S $(VMLINUX) FORCE $(call if_changed_dep,cpp_its_S,none,vmlinux.bin) -$(obj)/vmlinux.gz.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE +$(obj)/vmlinux.gz.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S $(VMLINUX) FORCE $(call if_changed_dep,cpp_its_S,gzip,vmlinux.bin.gz) -$(obj)/vmlinux.bz2.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE +$(obj)/vmlinux.bz2.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S $(VMLINUX) FORCE $(call if_changed_dep,cpp_its_S,bzip2,vmlinux.bin.bz2) -$(obj)/vmlinux.lzma.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE +$(obj)/vmlinux.lzma.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S $(VMLINUX) FORCE $(call if_changed_dep,cpp_its_S,lzma,vmlinux.bin.lzma) -$(obj)/vmlinux.lzo.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE +$(obj)/vmlinux.lzo.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S $(VMLINUX) FORCE $(call if_changed_dep,cpp_its_S,lzo,vmlinux.bin.lzo) quiet_cmd_itb-image = ITB $@ diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index d61bc2aebf69b423ba65fe1d02284fb2feed0814..7d90a8710425e31e796618bfea94782492bcad0d 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -22,7 +22,6 @@ dtb-$(CONFIG_DT_NONE) += \ bcm63268-comtrend-vr-3032u.dtb \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ - bcm96358nb4ser.dtb \ bcm96368mvwg.dtb \ bcm9ejtagprb.dtb \ bcm97125cbmb.dtb \ diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 1910223a9c02ba1474929905b235e43a07501aaa..cea2bb1621e68b211d5dc99fdad78f208b1ad8a3 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -147,23 +147,12 @@ * Find irq with highest priority */ # open coded PTR_LA t1, cpu_mask_nr_tbl -#if (_MIPS_SZPTR == 32) +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) # open coded la t1, cpu_mask_nr_tbl lui t1, %hi(cpu_mask_nr_tbl) addiu t1, %lo(cpu_mask_nr_tbl) - -#endif -#if (_MIPS_SZPTR == 64) - # open coded dla t1, cpu_mask_nr_tbl - .set push - .set noat - lui t1, %highest(cpu_mask_nr_tbl) - lui AT, %hi(cpu_mask_nr_tbl) - daddiu t1, t1, %higher(cpu_mask_nr_tbl) - daddiu AT, AT, %lo(cpu_mask_nr_tbl) - dsll t1, 32 - daddu t1, t1, AT - .set pop +#else +#error GCC `-msym32' option required for 64-bit DECstation builds #endif 1: lw t2,(t1) nop @@ -214,23 +203,12 @@ * Find irq with highest priority */ # open coded PTR_LA t1,asic_mask_nr_tbl -#if (_MIPS_SZPTR == 32) +#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) # open coded la t1, asic_mask_nr_tbl lui t1, %hi(asic_mask_nr_tbl) addiu t1, %lo(asic_mask_nr_tbl) - -#endif -#if (_MIPS_SZPTR == 64) - # open coded dla t1, asic_mask_nr_tbl - .set push - .set noat - lui t1, %highest(asic_mask_nr_tbl) - lui AT, %hi(asic_mask_nr_tbl) - daddiu t1, t1, %higher(asic_mask_nr_tbl) - daddiu AT, AT, %lo(asic_mask_nr_tbl) - dsll t1, 32 - daddu t1, t1, AT - .set pop +#else +#error GCC `-msym32' option required for 64-bit DECstation builds #endif 2: lw t2,(t1) nop diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 7c26b28bf2526856f7a96e1a2c39c61b78bf4e59..859cf7048347bf4b0ebad1f619507202976f74b3 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -54,7 +54,8 @@ .align 2; \ .type symbol, @function; \ .ent symbol, 0; \ -symbol: .frame sp, 0, ra +symbol: .frame sp, 0, ra; \ + .insn /* * NESTED - declare nested routine entry point @@ -63,8 +64,9 @@ symbol: .frame sp, 0, ra .globl symbol; \ .align 2; \ .type symbol, @function; \ - .ent symbol, 0; \ -symbol: .frame sp, framesize, rpc + .ent symbol, 0; \ +symbol: .frame sp, framesize, rpc; \ + .insn /* * END - mark end of function @@ -86,7 +88,7 @@ symbol: .frame sp, framesize, rpc #define FEXPORT(symbol) \ .globl symbol; \ .type symbol, @function; \ -symbol: +symbol: .insn /* * ABS - export absolute symbol diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 83054f79f72aa62595923ca017936f6cd60075fd..8333ce90b1726e41f5054041b8917191ef7950d0 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -19,6 +19,9 @@ #include #endif +/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */ +#undef fp + /* * Helper macros for generating raw instruction encodings. */ @@ -105,6 +108,7 @@ .macro fpu_save_16odd thread .set push .set mips64r2 + .set fp=64 SET_HARDFLOAT sdc1 $f1, THREAD_FPR1(\thread) sdc1 $f3, THREAD_FPR3(\thread) @@ -163,6 +167,7 @@ .macro fpu_restore_16odd thread .set push .set mips64r2 + .set fp=64 SET_HARDFLOAT ldc1 $f1, THREAD_FPR1(\thread) ldc1 $f3, THREAD_FPR3(\thread) @@ -234,9 +239,6 @@ .endm #ifdef TOOLCHAIN_SUPPORTS_MSA -/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */ -#undef fp - .macro _cfcmsa rd, cs .set push .set mips32r2 diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index de781cf54bc7a22b4ae81f506ff1a869c6b1cc32..da80878f2c0dcdda24a0c7348585f831fd4f68a4 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h @@ -74,10 +74,7 @@ static inline int compute_return_epc(struct pt_regs *regs) return __microMIPS_compute_return_epc(regs); if (cpu_has_mips16) return __MIPS16e_compute_return_epc(regs); - return regs->cp0_epc; - } - - if (!delay_slot(regs)) { + } else if (!delay_slot(regs)) { regs->cp0_epc += 4; return 0; } diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 956db6e201d1877ca6f6b3f8d48fc9ecd6799396..c5d35178641622a6e9a2d6815055cc61ac92c7ae 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -18,9 +18,24 @@ #include #define IRQ_STACK_SIZE THREAD_SIZE +#define IRQ_STACK_START (IRQ_STACK_SIZE - 16) extern void *irq_stack[NR_CPUS]; +/* + * The highest address on the IRQ stack contains a dummy frame put down in + * genex.S (handle_int & except_vec_vi_handler) which is structured as follows: + * + * top ------------ + * | task sp | <- irq_stack[cpu] + IRQ_STACK_START + * ------------ + * | | <- First frame of IRQ context + * ------------ + * + * task sp holds a copy of the task stack pointer where the struct pt_regs + * from exception entry can be found. + */ + static inline bool on_irq_stack(int cpu, unsigned long sp) { unsigned long low = (unsigned long)irq_stack[cpu]; diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 2e4180797b21828c3bc93a76d214b51f94f1392e..163317fd3d7e9f58feb5070883831267dd1de439 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -187,6 +187,7 @@ BUILD_CM_R_(config, MIPS_CM_GCB_OFS + 0x00) BUILD_CM_RW(base, MIPS_CM_GCB_OFS + 0x08) BUILD_CM_RW(access, MIPS_CM_GCB_OFS + 0x20) BUILD_CM_R_(rev, MIPS_CM_GCB_OFS + 0x30) +BUILD_CM_RW(err_control, MIPS_CM_GCB_OFS + 0x38) BUILD_CM_RW(error_mask, MIPS_CM_GCB_OFS + 0x40) BUILD_CM_RW(error_cause, MIPS_CM_GCB_OFS + 0x48) BUILD_CM_RW(error_addr, MIPS_CM_GCB_OFS + 0x50) @@ -239,8 +240,8 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_BASE_GCRBASE_MSK (_ULCAST_(0x1ffff) << 15) #define CM_GCR_BASE_CMDEFTGT_SHF 0 #define CM_GCR_BASE_CMDEFTGT_MSK (_ULCAST_(0x3) << 0) -#define CM_GCR_BASE_CMDEFTGT_DISABLED 0 -#define CM_GCR_BASE_CMDEFTGT_MEM 1 +#define CM_GCR_BASE_CMDEFTGT_MEM 0 +#define CM_GCR_BASE_CMDEFTGT_RESERVED 1 #define CM_GCR_BASE_CMDEFTGT_IOCU0 2 #define CM_GCR_BASE_CMDEFTGT_IOCU1 3 @@ -266,6 +267,12 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_REV_CM2_5 CM_ENCODE_REV(7, 0) #define CM_REV_CM3 CM_ENCODE_REV(8, 0) +/* GCR_ERR_CONTROL register fields */ +#define CM_GCR_ERR_CONTROL_L2_ECC_EN_SHF 1 +#define CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK (_ULCAST_(0x1) << 1) +#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_SHF 0 +#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK (_ULCAST_(0x1) << 0) + /* GCR_ERROR_CAUSE register fields */ #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index 2027240aafbb8432f0cc67148b70ae57f48ed2a6..2f106d0357f42bcae5a945a732acc0fd524bebea 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -108,4 +108,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 4be2763f835d1247b165e01ff3661b941c26121b..bfff6ea45d510a5b0879a1eed5c53dd8207ec4b6 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -103,6 +103,7 @@ void output_thread_info_defines(void) DEFINE(_THREAD_SIZE, THREAD_SIZE); DEFINE(_THREAD_MASK, THREAD_MASK); DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE); + DEFINE(_IRQ_STACK_START, IRQ_STACK_START); BLANK(); } diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 12c718181e5e3ee5e5cc51cca92bc16f408fbe0a..c3f2fb34751e85a5fe4fdb46545262a45622bee5 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -399,7 +399,7 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs) * * @regs: Pointer to pt_regs * @insn: branch instruction to decode - * @returns: -EFAULT on error and forces SIGBUS, and on success + * @returns: -EFAULT on error and forces SIGILL, and on success * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after * evaluating the branch. * @@ -431,7 +431,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, /* Fall through */ case jr_op: if (NO_R6EMU && insn.r_format.func == jr_op) - goto sigill_r6; + goto sigill_r2r6; regs->cp0_epc = regs->regs[insn.r_format.rs]; break; } @@ -446,7 +446,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, switch (insn.i_format.rt) { case bltzl_op: if (NO_R6EMU) - goto sigill_r6; + goto sigill_r2r6; case bltz_op: if ((long)regs->regs[insn.i_format.rs] < 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); @@ -459,7 +459,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case bgezl_op: if (NO_R6EMU) - goto sigill_r6; + goto sigill_r2r6; case bgez_op: if ((long)regs->regs[insn.i_format.rs] >= 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); @@ -473,10 +473,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case bltzal_op: case bltzall_op: if (NO_R6EMU && (insn.i_format.rs || - insn.i_format.rt == bltzall_op)) { - ret = -SIGILL; - break; - } + insn.i_format.rt == bltzall_op)) + goto sigill_r2r6; regs->regs[31] = epc + 8; /* * OK we are here either because we hit a NAL @@ -507,10 +505,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case bgezal_op: case bgezall_op: if (NO_R6EMU && (insn.i_format.rs || - insn.i_format.rt == bgezall_op)) { - ret = -SIGILL; - break; - } + insn.i_format.rt == bgezall_op)) + goto sigill_r2r6; regs->regs[31] = epc + 8; /* * OK we are here either because we hit a BAL @@ -556,6 +552,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, /* * These are unconditional and in j_format. */ + case jalx_op: case jal_op: regs->regs[31] = regs->cp0_epc + 8; case j_op: @@ -573,7 +570,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, */ case beql_op: if (NO_R6EMU) - goto sigill_r6; + goto sigill_r2r6; case beq_op: if (regs->regs[insn.i_format.rs] == regs->regs[insn.i_format.rt]) { @@ -587,7 +584,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case bnel_op: if (NO_R6EMU) - goto sigill_r6; + goto sigill_r2r6; case bne_op: if (regs->regs[insn.i_format.rs] != regs->regs[insn.i_format.rt]) { @@ -601,7 +598,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case blezl_op: /* not really i_format */ if (!insn.i_format.rt && NO_R6EMU) - goto sigill_r6; + goto sigill_r2r6; case blez_op: /* * Compact branches for R6 for the @@ -636,7 +633,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case bgtzl_op: if (!insn.i_format.rt && NO_R6EMU) - goto sigill_r6; + goto sigill_r2r6; case bgtz_op: /* * Compact branches for R6 for the @@ -774,48 +771,40 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, #else case bc6_op: /* Only valid for MIPS R6 */ - if (!cpu_has_mips_r6) { - ret = -SIGILL; - break; - } + if (!cpu_has_mips_r6) + goto sigill_r6; regs->cp0_epc += 8; break; case balc6_op: - if (!cpu_has_mips_r6) { - ret = -SIGILL; - break; - } + if (!cpu_has_mips_r6) + goto sigill_r6; /* Compact branch: BALC */ regs->regs[31] = epc + 4; epc += 4 + (insn.i_format.simmediate << 2); regs->cp0_epc = epc; break; case pop66_op: - if (!cpu_has_mips_r6) { - ret = -SIGILL; - break; - } + if (!cpu_has_mips_r6) + goto sigill_r6; /* Compact branch: BEQZC || JIC */ regs->cp0_epc += 8; break; case pop76_op: - if (!cpu_has_mips_r6) { - ret = -SIGILL; - break; - } + if (!cpu_has_mips_r6) + goto sigill_r6; /* Compact branch: BNEZC || JIALC */ - if (insn.i_format.rs) + if (!insn.i_format.rs) { + /* JIALC: set $31/ra */ regs->regs[31] = epc + 4; + } regs->cp0_epc += 8; break; #endif case pop10_op: case pop30_op: /* Only valid for MIPS R6 */ - if (!cpu_has_mips_r6) { - ret = -SIGILL; - break; - } + if (!cpu_has_mips_r6) + goto sigill_r6; /* * Compact branches: * bovc, beqc, beqzalc, bnvc, bnec, bnezlac @@ -829,11 +818,17 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, return ret; sigill_dsp: - printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); - force_sig(SIGBUS, current); + pr_info("%s: DSP branch but not DSP ASE - sending SIGILL.\n", + current->comm); + force_sig(SIGILL, current); + return -EFAULT; +sigill_r2r6: + pr_info("%s: R2 branch but r2-to-r6 emulator is not present - sending SIGILL.\n", + current->comm); + force_sig(SIGILL, current); return -EFAULT; sigill_r6: - pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n", + pr_info("%s: R6 branch but no MIPSr6 ISA support - sending SIGILL.\n", current->comm); force_sig(SIGILL, current); return -EFAULT; diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 804d2a2a19fe03175aa6ad6fa56f91238591f493..dd6a18bc10abd0c34a6717fe12bb7169a4589231 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -80,7 +80,7 @@ static unsigned int calculate_min_delta(void) } /* Sorted insert of 75th percentile into buf2 */ - for (k = 0; k < i; ++k) { + for (k = 0; k < i && k < ARRAY_SIZE(buf2); ++k) { if (buf1[ARRAY_SIZE(buf1) - 1] < buf2[k]) { l = min_t(unsigned int, i, ARRAY_SIZE(buf2) - 1); diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 59476a607adda07c5be321b8f21653668c1555b8..a00e87b0256d3d2a031ac1300239804edfcc8604 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -361,7 +361,7 @@ LEAF(mips_cps_get_bootcfg) END(mips_cps_get_bootcfg) LEAF(mips_cps_boot_vpes) - PTR_L ta2, COREBOOTCFG_VPEMASK(a0) + lw ta2, COREBOOTCFG_VPEMASK(a0) PTR_L ta3, COREBOOTCFG_VPECONFIG(a0) #if defined(CONFIG_CPU_MIPSR6) diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 6430bff21fff80a7bb6647c6af0198364cac7bdd..5c429d70e17f6f24cbcfd0fa912c67eccd11f28f 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -257,7 +257,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, else if ((prog_req.fr1 && prog_req.frdefault) || (prog_req.single && !prog_req.frdefault)) /* Make sure 64-bit MIPS III/IV/64R1 will not pick FR1 */ - state->overall_fp_mode = ((current_cpu_data.fpu_id & MIPS_FPIR_F64) && + state->overall_fp_mode = ((raw_current_cpu_data.fpu_id & MIPS_FPIR_F64) && cpu_has_mips_r2_r6) ? FP_FR1 : FP_FR0; else if (prog_req.fr1) diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 7791840cf22c0f7c058d32f3abb722eb132f90f8..db07793f7b43c1e350403ad135733d70465a6c7e 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +138,7 @@ work_pending: andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS beqz t0, work_notifysig work_resched: + TRACE_IRQS_OFF jal schedule local_irq_disable # make sure need_resched and @@ -173,6 +175,7 @@ syscall_exit_work: beqz t0, work_pending # trace bit set? local_irq_enable # could let syscall_trace_leave() # call schedule() instead + TRACE_IRQS_ON move a0, sp jal syscall_trace_leave b resume_userspace diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 2ac6c2625c13d452f9925dabdec44cd0818254d0..ae810da4d499e6282638d8edadb722078b5f04cb 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -215,9 +215,11 @@ NESTED(handle_int, PT_SIZE, sp) beq t0, t1, 2f /* Switch to IRQ stack */ - li t1, _IRQ_STACK_SIZE + li t1, _IRQ_STACK_START PTR_ADD sp, t0, t1 + /* Save task's sp on IRQ stack so that unwinding can follow it */ + LONG_S s1, 0(sp) 2: jal plat_irq_dispatch @@ -325,9 +327,11 @@ NESTED(except_vec_vi_handler, 0, sp) beq t0, t1, 2f /* Switch to IRQ stack */ - li t1, _IRQ_STACK_SIZE + li t1, _IRQ_STACK_START PTR_ADD sp, t0, t1 + /* Save task's sp on IRQ stack so that unwinding can follow it */ + LONG_S s1, 0(sp) 2: jalr v0 diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index cf052204eb0ae50460de00055994cc229694d854..d1bb506adc1044d6b72585ae5972fd200e224a89 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -106,8 +106,8 @@ NESTED(kernel_entry, 16, sp) # kernel entry point beq t0, t1, dtb_found #endif li t1, -2 - beq a0, t1, dtb_found move t2, a1 + beq a0, t1, dtb_found li t2, 0 dtb_found: diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index de63d36af895aaa3aa5e1c0469f9a70a00064bf0..732d6171ac6aeb40e835a45b050d0a3a973116b9 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -244,9 +244,6 @@ static int compute_signal(int tt) void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { int reg; - struct thread_info *ti = task_thread_info(p); - unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32; - struct pt_regs *regs = (struct pt_regs *)ksp - 1; #if (KGDB_GDB_REG_SIZE == 32) u32 *ptr = (u32 *)gdb_regs; #else @@ -254,25 +251,46 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) #endif for (reg = 0; reg < 16; reg++) - *(ptr++) = regs->regs[reg]; + *(ptr++) = 0; /* S0 - S7 */ - for (reg = 16; reg < 24; reg++) - *(ptr++) = regs->regs[reg]; + *(ptr++) = p->thread.reg16; + *(ptr++) = p->thread.reg17; + *(ptr++) = p->thread.reg18; + *(ptr++) = p->thread.reg19; + *(ptr++) = p->thread.reg20; + *(ptr++) = p->thread.reg21; + *(ptr++) = p->thread.reg22; + *(ptr++) = p->thread.reg23; for (reg = 24; reg < 28; reg++) *(ptr++) = 0; /* GP, SP, FP, RA */ - for (reg = 28; reg < 32; reg++) - *(ptr++) = regs->regs[reg]; - - *(ptr++) = regs->cp0_status; - *(ptr++) = regs->lo; - *(ptr++) = regs->hi; - *(ptr++) = regs->cp0_badvaddr; - *(ptr++) = regs->cp0_cause; - *(ptr++) = regs->cp0_epc; + *(ptr++) = (long)p; + *(ptr++) = p->thread.reg29; + *(ptr++) = p->thread.reg30; + *(ptr++) = p->thread.reg31; + + *(ptr++) = p->thread.cp0_status; + + /* lo, hi */ + *(ptr++) = 0; + *(ptr++) = 0; + + /* + * BadVAddr, Cause + * Ideally these would come from the last exception frame up the stack + * but that requires unwinding, otherwise we can't know much for sure. + */ + *(ptr++) = 0; + *(ptr++) = 0; + + /* + * PC + * use return address (RA), i.e. the moment after return from resume() + */ + *(ptr++) = p->thread.reg31; } void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index bd09853aecdfa1e567717cc35a9d19e786468391..d8227f289d7f64cfaf117f0ce6bb3af52b6f02c4 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -433,8 +433,8 @@ static int multu_func(struct pt_regs *regs, u32 ir) rs = regs->regs[MIPSInst_RS(ir)]; res = (u64)rt * (u64)rs; rt = res; - regs->lo = (s64)rt; - regs->hi = (s64)(res >> 32); + regs->lo = (s64)(s32)rt; + regs->hi = (s64)(s32)(res >> 32); MIPS_R2_STATS(muls); @@ -670,9 +670,9 @@ static int maddu_func(struct pt_regs *regs, u32 ir) res += ((((s64)rt) << 32) | (u32)rs); rt = res; - regs->lo = (s64)rt; + regs->lo = (s64)(s32)rt; rs = res >> 32; - regs->hi = (s64)rs; + regs->hi = (s64)(s32)rs; MIPS_R2_STATS(dsps); @@ -728,9 +728,9 @@ static int msubu_func(struct pt_regs *regs, u32 ir) res = ((((s64)rt) << 32) | (u32)rs) - res; rt = res; - regs->lo = (s64)rt; + regs->lo = (s64)(s32)rt; rs = res >> 32; - regs->hi = (s64)rs; + regs->hi = (s64)(s32)rs; MIPS_R2_STATS(dsps); diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 7cf653e214237f75b22200c94f0e47c696be14ae..60c4d4599639cc01fdfbf0210041be6ba093a8e7 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -56,7 +56,6 @@ DECLARE_BITMAP(state_support, CPS_PM_STATE_COUNT); * state. Actually per-core rather than per-CPU. */ static DEFINE_PER_CPU_ALIGNED(u32*, ready_count); -static DEFINE_PER_CPU_ALIGNED(void*, ready_count_alloc); /* Indicates online CPUs coupled with the current CPU */ static DEFINE_PER_CPU_ALIGNED(cpumask_t, online_coupled); @@ -642,7 +641,6 @@ static int cps_pm_online_cpu(unsigned int cpu) { enum cps_pm_state state; unsigned core = cpu_data[cpu].core; - unsigned dlinesz = cpu_data[cpu].dcache.linesz; void *entry_fn, *core_rc; for (state = CPS_PM_NC_WAIT; state < CPS_PM_STATE_COUNT; state++) { @@ -662,16 +660,11 @@ static int cps_pm_online_cpu(unsigned int cpu) } if (!per_cpu(ready_count, core)) { - core_rc = kmalloc(dlinesz * 2, GFP_KERNEL); + core_rc = kmalloc(sizeof(u32), GFP_KERNEL); if (!core_rc) { pr_err("Failed allocate core %u ready_count\n", core); return -ENOMEM; } - per_cpu(ready_count_alloc, core) = core_rc; - - /* Ensure ready_count is aligned to a cacheline boundary */ - core_rc += dlinesz - 1; - core_rc = (void *)((unsigned long)core_rc & ~(dlinesz - 1)); per_cpu(ready_count, core) = core_rc; } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 4eff2aed736019d6f071b00487d46bfdc76a7308..4c01ee5b88c999ac3a99fa64358034ec15f73e03 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -83,7 +83,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) } seq_printf(m, "isa\t\t\t:"); - if (cpu_has_mips_r1) + if (cpu_has_mips_1) seq_printf(m, " mips1"); if (cpu_has_mips_2) seq_printf(m, "%s", " mips2"); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index fbbf5fcc695a56a33ba971642fb16f6b3aedc46d..6e716a5f117374fff602b6cad95f823c1d56d375 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -50,9 +50,7 @@ #ifdef CONFIG_HOTPLUG_CPU void arch_cpu_idle_dead(void) { - /* What the heck is this check doing ? */ - if (!cpumask_test_cpu(smp_processor_id(), &cpu_callin_map)) - play_dead(); + play_dead(); } #endif @@ -487,31 +485,52 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page, unsigned long pc, unsigned long *ra) { + unsigned long low, high, irq_stack_high; struct mips_frame_info info; unsigned long size, ofs; + struct pt_regs *regs; int leaf; - extern void ret_from_irq(void); - extern void ret_from_exception(void); if (!stack_page) return 0; /* - * If we reached the bottom of interrupt context, - * return saved pc in pt_regs. + * IRQ stacks start at IRQ_STACK_START + * task stacks at THREAD_SIZE - 32 */ - if (pc == (unsigned long)ret_from_irq || - pc == (unsigned long)ret_from_exception) { - struct pt_regs *regs; - if (*sp >= stack_page && - *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) { - regs = (struct pt_regs *)*sp; - pc = regs->cp0_epc; - if (!user_mode(regs) && __kernel_text_address(pc)) { - *sp = regs->regs[29]; - *ra = regs->regs[31]; - return pc; - } + low = stack_page; + if (!preemptible() && on_irq_stack(raw_smp_processor_id(), *sp)) { + high = stack_page + IRQ_STACK_START; + irq_stack_high = high; + } else { + high = stack_page + THREAD_SIZE - 32; + irq_stack_high = 0; + } + + /* + * If we reached the top of the interrupt stack, start unwinding + * the interrupted task stack. + */ + if (unlikely(*sp == irq_stack_high)) { + unsigned long task_sp = *(unsigned long *)*sp; + + /* + * Check that the pointer saved in the IRQ stack head points to + * something within the stack of the current task + */ + if (!object_is_on_stack((void *)task_sp)) + return 0; + + /* + * Follow pointer to tasks kernel stack frame where interrupted + * state was saved. + */ + regs = (struct pt_regs *)task_sp; + pc = regs->cp0_epc; + if (!user_mode(regs) && __kernel_text_address(pc)) { + *sp = regs->regs[29]; + *ra = regs->regs[31]; + return pc; } return 0; } @@ -532,8 +551,7 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page, if (leaf < 0) return 0; - if (*sp < stack_page || - *sp + info.frame_size > stack_page + THREAD_SIZE - 32) + if (*sp < low || *sp + info.frame_size > high) return 0; if (leaf) @@ -665,6 +683,18 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) struct task_struct *t; int max_users; + /* If nothing to change, return right away, successfully. */ + if (value == mips_get_process_fp_mode(task)) + return 0; + + /* Only accept a mode change if 64-bit FP enabled for o32. */ + if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT)) + return -EOPNOTSUPP; + + /* And only for o32 tasks. */ + if (IS_ENABLED(CONFIG_64BIT) && !test_thread_flag(TIF_32BIT_REGS)) + return -EOPNOTSUPP; + /* Check the value is valid */ if (value & ~known_bits) return -EOPNOTSUPP; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index bf83dc1eecfbb4b6ebafc7f58b278787d5dfae49..0c8ae2cc6380724e58ed4c566c7c82925da3178c 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -439,63 +439,160 @@ static int gpr64_set(struct task_struct *target, #endif /* CONFIG_64BIT */ +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * !CONFIG_CPU_HAS_MSA variant. FP context's general register slots + * correspond 1:1 to buffer slots. Only general registers are copied. + */ +static int fpr_get_fpa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + void **kbuf, void __user **ubuf) +{ + return user_regset_copyout(pos, count, kbuf, ubuf, + &target->thread.fpu, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's + * general register slots are copied to buffer slots. Only general + * registers are copied. + */ +static int fpr_get_msa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + void **kbuf, void __user **ubuf) +{ + unsigned int i; + u64 fpr_val; + int err; + + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); + for (i = 0; i < NUM_FPU_REGS; i++) { + fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); + err = user_regset_copyout(pos, count, kbuf, ubuf, + &fpr_val, i * sizeof(elf_fpreg_t), + (i + 1) * sizeof(elf_fpreg_t)); + if (err) + return err; + } + + return 0; +} + +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. + */ static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { - unsigned i; + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); int err; - u64 fpr_val; - /* XXX fcr31 */ + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); + else + err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; - if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu, - 0, sizeof(elf_fpregset_t)); + err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpu.fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); - for (i = 0; i < NUM_FPU_REGS; i++) { - fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); - err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &fpr_val, i * sizeof(elf_fpreg_t), - (i + 1) * sizeof(elf_fpreg_t)); + return err; +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP + * context's general register slots. Only general registers are copied. + */ +static int fpr_set_fpa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + return user_regset_copyin(pos, count, kbuf, ubuf, + &target->thread.fpu, + 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64 + * bits only of FP context's general register slots. Only general + * registers are copied. + */ +static int fpr_set_msa(struct task_struct *target, + unsigned int *pos, unsigned int *count, + const void **kbuf, const void __user **ubuf) +{ + unsigned int i; + u64 fpr_val; + int err; + + BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); + for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { + err = user_regset_copyin(pos, count, kbuf, ubuf, + &fpr_val, i * sizeof(elf_fpreg_t), + (i + 1) * sizeof(elf_fpreg_t)); if (err) return err; + set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); } return 0; } +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. + * + * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', + * which is supposed to have been guaranteed by the kernel before + * calling us, e.g. in `ptrace_regset'. We enforce that requirement, + * so that we can safely avoid preinitializing temporaries for + * partial register writes. + */ static int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - unsigned i; + const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); + u32 fcr31; int err; - u64 fpr_val; - /* XXX fcr31 */ + BUG_ON(count % sizeof(elf_fpreg_t)); + + if (pos + count > sizeof(elf_fpregset_t)) + return -EIO; init_fp_ctx(target); - if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) - return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpu, - 0, sizeof(elf_fpregset_t)); + if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) + err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf); + else + err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf); + if (err) + return err; - BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); - for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) { + if (count > 0) { err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpr_val, i * sizeof(elf_fpreg_t), - (i + 1) * sizeof(elf_fpreg_t)); + &fcr31, + fcr31_pos, fcr31_pos + sizeof(u32)); if (err) return err; - set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); + + ptrace_setfcr31(target, fcr31); } - return 0; + return err; } enum mips_regset { @@ -647,6 +744,19 @@ static const struct user_regset_view user_mips64_view = { .n = ARRAY_SIZE(mips64_regsets), }; +#ifdef CONFIG_MIPS32_N32 + +static const struct user_regset_view user_mipsn32_view = { + .name = "mipsn32", + .e_flags = EF_MIPS_ABI2, + .e_machine = ELF_ARCH, + .ei_osabi = ELF_OSABI, + .regsets = mips64_regsets, + .n = ARRAY_SIZE(mips64_regsets), +}; + +#endif /* CONFIG_MIPS32_N32 */ + #endif /* CONFIG_64BIT */ const struct user_regset_view *task_user_regset_view(struct task_struct *task) @@ -657,6 +767,10 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #ifdef CONFIG_MIPS32_O32 if (test_tsk_thread_flag(task, TIF_32BIT_REGS)) return &user_mips_view; +#endif +#ifdef CONFIG_MIPS32_N32 + if (test_tsk_thread_flag(task, TIF_32BIT_ADDR)) + return &user_mipsn32_view; #endif return &user_mips64_view; #endif @@ -924,7 +1038,7 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs) audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_sys_exit(regs, regs->regs[2]); + trace_sys_exit(regs, regs_return_value(regs)); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index c29d397eee86cf48a05d7945efe3cdf4a38a7273..e6be1f6210ba45fae39e1a95224e280087a0668f 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -371,7 +371,7 @@ EXPORT(sys_call_table) PTR sys_writev PTR sys_cacheflush PTR sys_cachectl - PTR sys_sysmips + PTR __sys_sysmips PTR sys_ni_syscall /* 4150 */ PTR sys_getsid PTR sys_fdatasync diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 0687f96ee912698285a92abde87a7376897f076b..aa27dafa1c7817b92cbfdc9a0a2112f7e0c0aa79 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -311,7 +311,7 @@ EXPORT(sys_call_table) PTR sys_sched_getaffinity PTR sys_cacheflush PTR sys_cachectl - PTR sys_sysmips + PTR __sys_sysmips PTR sys_io_setup /* 5200 */ PTR sys_io_destroy PTR sys_io_getevents diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 0331ba39a065b8530818093d7b707921242a3672..37f608f2a76f235857ffc6f15b73847b97f01e4a 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -302,7 +302,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_sched_getaffinity PTR sys_cacheflush PTR sys_cachectl - PTR sys_sysmips + PTR __sys_sysmips PTR compat_sys_io_setup /* 6200 */ PTR sys_io_destroy PTR compat_sys_io_getevents diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 5a47042dd25f7ae7f93cee8a596f311bf17a9382..7913a5cf68060f416e96928e3f241f1c697d99bc 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -371,7 +371,7 @@ EXPORT(sys32_call_table) PTR compat_sys_writev PTR sys_cacheflush PTR sys_cachectl - PTR sys_sysmips + PTR __sys_sysmips PTR sys_ni_syscall /* 4150 */ PTR sys_getsid PTR sys_fdatasync diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f66e5ce505b23db0e666adb727653df71104c5d1..695950361d2a734289d6554318e106ec1ed15675 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add add_memory_region(start, size, BOOT_MEM_RAM); } +bool __init memory_region_available(phys_addr_t start, phys_addr_t size) +{ + int i; + bool in_ram = false, free = true; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + phys_addr_t start_, end_; + + start_ = boot_mem_map.map[i].addr; + end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size; + + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + if (start >= start_ && start + size <= end_) + in_ram = true; + break; + case BOOT_MEM_RESERVED: + if ((start >= start_ && start < end_) || + (start < start_ && start + size >= start_)) + free = false; + break; + default: + continue; + } + } + + return in_ram && free; +} + static void __init print_memory_map(void) { int i; @@ -332,11 +361,19 @@ static void __init bootmem_init(void) #else /* !CONFIG_SGI_IP27 */ +static unsigned long __init bootmap_bytes(unsigned long pages) +{ + unsigned long bytes = DIV_ROUND_UP(pages, 8); + + return ALIGN(bytes, sizeof(long)); +} + static void __init bootmem_init(void) { unsigned long reserved_end; unsigned long mapstart = ~0UL; unsigned long bootmap_size; + bool bootmap_valid = false; int i; /* @@ -430,11 +467,42 @@ static void __init bootmem_init(void) #endif /* - * Initialize the boot-time allocator with low memory only. + * check that mapstart doesn't overlap with any of + * memory regions that have been reserved through eg. DTB */ - bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart, - min_low_pfn, max_low_pfn); + bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn); + + bootmap_valid = memory_region_available(PFN_PHYS(mapstart), + bootmap_size); + for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) { + unsigned long mapstart_addr; + + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RESERVED: + mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + if (PHYS_PFN(mapstart_addr) < mapstart) + break; + + bootmap_valid = memory_region_available(mapstart_addr, + bootmap_size); + if (bootmap_valid) + mapstart = PHYS_PFN(mapstart_addr); + break; + default: + break; + } + } + if (!bootmap_valid) + panic("No memory area to place a bootmap bitmap"); + + /* + * Initialize the boot-time allocator with low memory only. + */ + if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart, + min_low_pfn, max_low_pfn)) + panic("Unexpected memory size required for bootmap"); for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long start, end; @@ -483,6 +551,10 @@ static void __init bootmem_init(void) continue; default: /* Not usable memory */ + if (start > min_low_pfn && end < max_low_pfn) + reserve_bootmem(boot_mem_map.map[i].addr, + boot_mem_map.map[i].size, + BOOTMEM_DEFAULT); continue; } diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 6d0f1321e0841077531787e07380088b8d6468f0..47c9646f93b32049093e49e41c21537a9455c78d 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -587,11 +587,11 @@ void __init bmips_cpu_setup(void) /* Flush and enable RAC */ cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); - __raw_writel(cfg | 0x100, BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG); __raw_readl(cbr + BMIPS_RAC_CONFIG); cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); - __raw_writel(cfg | 0xf, BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0xf, cbr + BMIPS_RAC_CONFIG); __raw_readl(cbr + BMIPS_RAC_CONFIG); cfg = __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 7ebb1918e2ac8abb5a2f8bff3b7d0f51cd126ee8..95ba4271af6a8c05640dda49649df48cf64c0aef 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -68,6 +68,9 @@ EXPORT_SYMBOL(cpu_sibling_map); cpumask_t cpu_core_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_core_map); +static DECLARE_COMPLETION(cpu_starting); +static DECLARE_COMPLETION(cpu_running); + /* * A logcal cpu mask containing only one VPE per core to * reduce the number of IPIs on large MT systems. @@ -369,9 +372,12 @@ asmlinkage void start_secondary(void) cpumask_set_cpu(cpu, &cpu_coherent_mask); notify_cpu_starting(cpu); - cpumask_set_cpu(cpu, &cpu_callin_map); + /* Notify boot CPU that we're starting & ready to sync counters */ + complete(&cpu_starting); + synchronise_count_slave(cpu); + /* The CPU is running and counters synchronised, now mark it online */ set_cpu_online(cpu, true); set_cpu_sibling_map(cpu); @@ -379,6 +385,12 @@ asmlinkage void start_secondary(void) calculate_cpu_foreign_map(); + /* + * Notify boot CPU that we're up & online and it can safely return + * from __cpu_up + */ + complete(&cpu_running); + /* * irq will be enabled in ->smp_finish(), enabling it too early * is dangerous. @@ -430,22 +442,23 @@ void smp_prepare_boot_cpu(void) { set_cpu_possible(0, true); set_cpu_online(0, true); - cpumask_set_cpu(0, &cpu_callin_map); } int __cpu_up(unsigned int cpu, struct task_struct *tidle) { mp_ops->boot_secondary(cpu, tidle); - /* - * Trust is futile. We should really have timeouts ... - */ - while (!cpumask_test_cpu(cpu, &cpu_callin_map)) { - udelay(100); - schedule(); + /* Wait for CPU to start and be ready to sync counters */ + if (!wait_for_completion_timeout(&cpu_starting, + msecs_to_jiffies(1000))) { + pr_crit("CPU%u: failed to start\n", cpu); + return -EIO; } synchronise_count_master(cpu); + + /* Wait for CPU to finish startup & mark itself online before return */ + wait_for_completion(&cpu_running); return 0; } diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 53a7ef9a8f320c5b14c5abb2d3e1518c0ad7f756..4234b2d726c55d60bd08e18d46d3d51a6a6694da 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -138,10 +139,12 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) __asm__ __volatile__ ( " .set "MIPS_ISA_ARCH_LEVEL" \n" " li %[err], 0 \n" - "1: ll %[old], (%[addr]) \n" + "1: \n" + user_ll("%[old]", "(%[addr])") " move %[tmp], %[new] \n" - "2: sc %[tmp], (%[addr]) \n" - " bnez %[tmp], 4f \n" + "2: \n" + user_sc("%[tmp]", "(%[addr])") + " beqz %[tmp], 4f \n" "3: \n" " .insn \n" " .subsection 2 \n" @@ -199,6 +202,12 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) unreachable(); } +/* + * mips_atomic_set() normally returns directly via syscall_exit potentially + * clobbering static registers, so be sure to preserve them. + */ +save_static_function(sys_sysmips); + SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2) { switch (cmd) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ec87ef93267b5131701ce52815a95aa8f9d76925..bb1d9ff1be5ccc48f0950114d509753b88f511db 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -199,6 +200,8 @@ void show_stack(struct task_struct *task, unsigned long *sp) { struct pt_regs regs; mm_segment_t old_fs = get_fs(); + + regs.cp0_status = KSU_KERNEL; if (sp) { regs.regs[29] = (unsigned long)sp; regs.regs[31] = 0; @@ -1644,6 +1647,65 @@ __setup("nol2par", nol2parity); */ static inline void parity_protection_init(void) { +#define ERRCTL_PE 0x80000000 +#define ERRCTL_L2P 0x00800000 + + if (mips_cm_revision() >= CM_REV_CM3) { + ulong gcr_ectl, cp0_ectl; + + /* + * With CM3 systems we need to ensure that the L1 & L2 + * parity enables are set to the same value, since this + * is presumed by the hardware engineers. + * + * If the user disabled either of L1 or L2 ECC checking, + * disable both. + */ + l1parity &= l2parity; + l2parity &= l1parity; + + /* Probe L1 ECC support */ + cp0_ectl = read_c0_ecc(); + write_c0_ecc(cp0_ectl | ERRCTL_PE); + back_to_back_c0_hazard(); + cp0_ectl = read_c0_ecc(); + + /* Probe L2 ECC support */ + gcr_ectl = read_gcr_err_control(); + + if (!(gcr_ectl & CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK) || + !(cp0_ectl & ERRCTL_PE)) { + /* + * One of L1 or L2 ECC checking isn't supported, + * so we cannot enable either. + */ + l1parity = l2parity = 0; + } + + /* Configure L1 ECC checking */ + if (l1parity) + cp0_ectl |= ERRCTL_PE; + else + cp0_ectl &= ~ERRCTL_PE; + write_c0_ecc(cp0_ectl); + back_to_back_c0_hazard(); + WARN_ON(!!(read_c0_ecc() & ERRCTL_PE) != l1parity); + + /* Configure L2 ECC checking */ + if (l2parity) + gcr_ectl |= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK; + else + gcr_ectl &= ~CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK; + write_gcr_err_control(gcr_ectl); + gcr_ectl = read_gcr_err_control(); + gcr_ectl &= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK; + WARN_ON(!!gcr_ectl != l2parity); + + pr_info("Cache parity protection %sabled\n", + l1parity ? "en" : "dis"); + return; + } + switch (current_cpu_type()) { case CPU_24K: case CPU_34K: @@ -1654,11 +1716,8 @@ static inline void parity_protection_init(void) case CPU_PROAPTIV: case CPU_P5600: case CPU_QEMU_GENERIC: - case CPU_I6400: case CPU_P6600: { -#define ERRCTL_PE 0x80000000 -#define ERRCTL_L2P 0x00800000 unsigned long errctl; unsigned int l1parity_present, l2parity_present; diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index d5de67591735940c86f5e3b8ba2e186a3e94fbaa..f0a0e6d62be38e5bcdb6f8c044f4b026ca940851 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -182,7 +182,7 @@ SECTIONS * Force .bss to 64K alignment so that .bss..swapper_pg_dir * gets that alignment. .sbss should be empty, so there will be * no holes after __init_end. */ - BSS_SECTION(0, 0x10000, 0) + BSS_SECTION(0, 0x10000, 8) _end = . ; diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 90565477dfbd29d40d4b29b1d0ba84d2faa1748e..95bec460b651fd1cdad1b1e262463408742c7795 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -469,8 +469,8 @@ void __init ltq_soc_init(void) panic("Failed to load xbar nodes from devicetree"); if (of_address_to_resource(np_xbar, 0, &res_xbar)) panic("Failed to get xbar resources"); - if (request_mem_region(res_xbar.start, resource_size(&res_xbar), - res_xbar.name) < 0) + if (!request_mem_region(res_xbar.start, resource_size(&res_xbar), + res_xbar.name)) panic("Failed to get xbar resources"); ltq_xbar_membase = ioremap_nocache(res_xbar.start, diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index f8b7bf836437708b414548625e1c4451cf747020..7f2519cfb5d2e0f8bd5e88a3c5927efa8e47c37f 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1781,7 +1781,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(fd, MIPSInst_FD(ir)); rv.s = ieee754sp_maddf(fd, fs, ft); - break; + goto copcsr; } case fmsubf_op: { @@ -1794,7 +1794,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(fs, MIPSInst_FS(ir)); SPFROMREG(fd, MIPSInst_FD(ir)); rv.s = ieee754sp_msubf(fd, fs, ft); - break; + goto copcsr; } case frint_op: { @@ -1818,7 +1818,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754sp_2008class(fs); rfmt = w_fmt; - break; + goto copcsr; } case fmin_op: { @@ -1830,7 +1830,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmin(fs, ft); - break; + goto copcsr; } case fmina_op: { @@ -1842,7 +1842,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmina(fs, ft); - break; + goto copcsr; } case fmax_op: { @@ -1854,7 +1854,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmax(fs, ft); - break; + goto copcsr; } case fmaxa_op: { @@ -1866,7 +1866,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(ft, MIPSInst_FT(ir)); SPFROMREG(fs, MIPSInst_FS(ir)); rv.s = ieee754sp_fmaxa(fs, ft); - break; + goto copcsr; } case fabs_op: @@ -2110,7 +2110,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(fd, MIPSInst_FD(ir)); rv.d = ieee754dp_maddf(fd, fs, ft); - break; + goto copcsr; } case fmsubf_op: { @@ -2123,7 +2123,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(fs, MIPSInst_FS(ir)); DPFROMREG(fd, MIPSInst_FD(ir)); rv.d = ieee754dp_msubf(fd, fs, ft); - break; + goto copcsr; } case frint_op: { @@ -2147,7 +2147,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(fs, MIPSInst_FS(ir)); rv.w = ieee754dp_2008class(fs); rfmt = w_fmt; - break; + goto copcsr; } case fmin_op: { @@ -2159,7 +2159,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmin(fs, ft); - break; + goto copcsr; } case fmina_op: { @@ -2171,7 +2171,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmina(fs, ft); - break; + goto copcsr; } case fmax_op: { @@ -2183,7 +2183,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmax(fs, ft); - break; + goto copcsr; } case fmaxa_op: { @@ -2195,7 +2195,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(ft, MIPSInst_FT(ir)); DPFROMREG(fs, MIPSInst_FS(ir)); rv.d = ieee754dp_fmaxa(fs, ft); - break; + goto copcsr; } case fabs_op: @@ -2386,7 +2386,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; default: /* Reserved R6 ops */ - pr_err("Reserved MIPS R6 CMP.condn.S operation\n"); return SIGILL; } } @@ -2460,7 +2459,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; default: /* Reserved R6 ops */ - pr_err("Reserved MIPS R6 CMP.condn.D operation\n"); return SIGILL; } } @@ -2522,6 +2520,35 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return 0; } +/* + * Emulate FPU instructions. + * + * If we use FPU hardware, then we have been typically called to handle + * an unimplemented operation, such as where an operand is a NaN or + * denormalized. In that case exit the emulation loop after a single + * iteration so as to let hardware execute any subsequent instructions. + * + * If we have no FPU hardware or it has been disabled, then continue + * emulating floating-point instructions until one of these conditions + * has occurred: + * + * - a non-FPU instruction has been encountered, + * + * - an attempt to emulate has ended with a signal, + * + * - the ISA mode has been switched. + * + * We need to terminate the emulation loop if we got switched to the + * MIPS16 mode, whether supported or not, so that we do not attempt + * to emulate a MIPS16 instruction as a regular MIPS FPU instruction. + * Similarly if we got switched to the microMIPS mode and only the + * regular MIPS mode is supported, so that we do not attempt to emulate + * a microMIPS instruction as a regular MIPS FPU instruction. Or if + * we got switched to the regular MIPS mode and only the microMIPS mode + * is supported, so that we do not attempt to emulate a regular MIPS + * instruction that should cause an Address Error exception instead. + * For simplicity we always terminate upon an ISA mode switch. + */ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, int has_fpu, void *__user *fault_addr) { @@ -2607,6 +2634,15 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; if (sig) break; + /* + * We have to check for the ISA bit explicitly here, + * because `get_isa16_mode' may return 0 if support + * for code compression has been globally disabled, + * or otherwise we may produce the wrong signal or + * even proceed successfully where we must not. + */ + if ((xcp->cp0_epc ^ prevepc) & 0x1) + break; cond_resched(); } while (xcp->cp0_epc > prevepc); diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c index fd71b8daaaf20525abfb4470f6892fc1dddc5cd1..5bec64f2884eb14103e53726e42a6e29563ff6b5 100644 --- a/arch/mips/math-emu/dp_fmax.c +++ b/arch/mips/math-emu/dp_fmax.c @@ -47,14 +47,26 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754dp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -80,9 +92,7 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) return ys ? x : y; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754dp_zero(1); + return ieee754dp_zero(xs & ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; @@ -106,16 +116,32 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) else if (xs < ys) return x; - /* Compare exponent */ - if (xe > ye) - return x; - else if (xe < ye) - return y; + /* Signs of inputs are equal, let's compare exponents */ + if (xs == 0) { + /* Inputs are both positive */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + } else { + /* Inputs are both negative */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + } - /* Compare mantissa */ + /* Signs and exponents of inputs are equal, let's compare mantissas */ + if (xs == 0) { + /* Inputs are both positive, with equal signs and exponents */ + if (xm <= ym) + return y; + return x; + } + /* Inputs are both negative, with equal signs and exponents */ if (xm <= ym) - return y; - return x; + return x; + return y; } union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) @@ -147,14 +173,26 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754dp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -164,6 +202,9 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) /* * Infinity and zero handling */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754dp_inf(xs & ys); + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): @@ -171,7 +212,6 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): return x; - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): @@ -180,9 +220,7 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) return y; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754dp_zero(1); + return ieee754dp_zero(xs & ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; @@ -207,7 +245,11 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) return y; /* Compare mantissa */ - if (xm <= ym) + if (xm < ym) return y; - return x; + else if (xm > ym) + return x; + else if (xs == 0) + return x; + return y; } diff --git a/arch/mips/math-emu/dp_fmin.c b/arch/mips/math-emu/dp_fmin.c index c1072b0dfb9519dad2b5e0d8b79d2199012d1213..a287b23818d82ed0cf59f9066032619dea8f991a 100644 --- a/arch/mips/math-emu/dp_fmin.c +++ b/arch/mips/math-emu/dp_fmin.c @@ -47,14 +47,26 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754dp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -80,9 +92,7 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) return ys ? y : x; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754dp_zero(1); + return ieee754dp_zero(xs | ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; @@ -106,16 +116,32 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) else if (xs < ys) return y; - /* Compare exponent */ - if (xe > ye) - return y; - else if (xe < ye) - return x; + /* Signs of inputs are the same, let's compare exponents */ + if (xs == 0) { + /* Inputs are both positive */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + } else { + /* Inputs are both negative */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + } - /* Compare mantissa */ + /* Signs and exponents of inputs are equal, let's compare mantissas */ + if (xs == 0) { + /* Inputs are both positive, with equal signs and exponents */ + if (xm <= ym) + return x; + return y; + } + /* Inputs are both negative, with equal signs and exponents */ if (xm <= ym) - return x; - return y; + return y; + return x; } union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) @@ -147,14 +173,26 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754dp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -164,25 +202,25 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) /* * Infinity and zero handling */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754dp_inf(xs | ys); + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - return x; + return y; - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - return y; + return x; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754dp_zero(1); + return ieee754dp_zero(xs | ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; @@ -207,7 +245,11 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) return x; /* Compare mantissa */ - if (xm <= ym) + if (xm < ym) + return x; + else if (xm > ym) + return y; + else if (xs == 1) return x; return y; } diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 4a2d03c72959cb5f1fb67da81e9f11b143086256..e0d9be5fbf4cd541406b93c5d2add6814a82a9eb 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -14,22 +14,45 @@ #include "ieee754dp.h" -enum maddf_flags { - maddf_negate_product = 1 << 0, -}; + +/* 128 bits shift right logical with rounding. */ +void srl128(u64 *hptr, u64 *lptr, int count) +{ + u64 low; + + if (count >= 128) { + *lptr = *hptr != 0 || *lptr != 0; + *hptr = 0; + } else if (count >= 64) { + if (count == 64) { + *lptr = *hptr | (*lptr != 0); + } else { + low = *lptr; + *lptr = *hptr >> (count - 64); + *lptr |= (*hptr << (128 - count)) != 0 || low != 0; + } + *hptr = 0; + } else { + low = *lptr; + *lptr = low >> count | *hptr << (64 - count); + *lptr |= (low << (64 - count)) != 0; + *hptr = *hptr >> count; + } +} static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y, enum maddf_flags flags) { int re; int rs; - u64 rm; unsigned lxm; unsigned hxm; unsigned lym; unsigned hym; u64 lrm; u64 hrm; + u64 lzm; + u64 hzm; u64 t; u64 at; int s; @@ -48,52 +71,34 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, ieee754_clearcx(); - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); + /* + * Handle the cases when at least one of x, y or z is a NaN. + * Order of precedence is sNaN, qNaN and z, x, y. + */ + if (zc == IEEE754_CLASS_SNAN) return ieee754dp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - DPDNORMZ; - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + if (xc == IEEE754_CLASS_SNAN) return ieee754dp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + if (yc == IEEE754_CLASS_SNAN) + return ieee754dp_nanxcpt(y); + if (zc == IEEE754_CLASS_QNAN) + return z; + if (xc == IEEE754_CLASS_QNAN) + return x; + if (yc == IEEE754_CLASS_QNAN) return y; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; + if (zc == IEEE754_CLASS_DNORM) + DPDNORMZ; + /* ZERO z cases are handled separately below */ + switch (CLPAIR(xc, yc)) { /* * Infinity handling */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754dp_indef(); @@ -102,9 +107,27 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754dp_inf(xs ^ ys); + if ((zc == IEEE754_CLASS_INF) && + ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) || + ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) { + /* + * Cases of addition of infinities with opposite signs + * or subtraction of infinities with same signs. + */ + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); + } + /* + * z is here either not an infinity, or an infinity having the + * same sign as product (x*y) (in case of MADDF.D instruction) + * or product -(x*y) (in MSUBF.D case). The result must be an + * infinity, and its sign is determined only by the value of + * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y. + */ + if (flags & MADDF_NEGATE_PRODUCT) + return ieee754dp_inf(1 ^ (xs ^ ys)); + else + return ieee754dp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): @@ -113,32 +136,42 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); - /* Multiplication is 0 so just return z */ + if (zc == IEEE754_CLASS_ZERO) { + /* Handle cases +0 + (-0) and similar ones. */ + if ((!(flags & MADDF_NEGATE_PRODUCT) + && (zs == (xs ^ ys))) || + ((flags & MADDF_NEGATE_PRODUCT) + && (zs != (xs ^ ys)))) + /* + * Cases of addition of zeros of equal signs + * or subtraction of zeroes of opposite signs. + * The sign of the resulting zero is in any + * such case determined only by the sign of z. + */ + return z; + + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); + } + /* x*y is here 0, and z is not 0, so just return z */ return z; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): DPDNORMX; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); DPDNORMY; break; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); DPDNORMX; break; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754dp_inf(zs); /* fall through to real computations */ } @@ -157,7 +190,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, re = xe + ye; rs = xs ^ ys; - if (flags & maddf_negate_product) + if (flags & MADDF_NEGATE_PRODUCT) rs ^= 1; /* shunt to top of word */ @@ -165,7 +198,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. + * Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm. */ /* 32 * 32 => 64 */ @@ -195,78 +228,110 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, hrm = hrm + (t >> 32); - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((s64) rm < 0) { - rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | - ((rm << (DP_FBITS + 1 + 3)) != 0); + /* Put explicit bit at bit 126 if necessary */ + if ((int64_t)hrm < 0) { + lrm = (hrm << 63) | (lrm >> 1); + hrm = hrm >> 1; re++; - } else { - rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | - ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); } - assert(rm & (DP_HIDDEN_BIT << 3)); - /* And now the addition */ - assert(zm & DP_HIDDEN_BIT); + assert(hrm & (1 << 62)); - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; + if (zc == IEEE754_CLASS_ZERO) { + /* + * Move explicit bit from bit 126 to bit 55 since the + * ieee754dp_format code expects the mantissa to be + * 56 bits wide (53 + 3 rounding bits). + */ + srl128(&hrm, &lrm, (126 - 55)); + return ieee754dp_format(rs, re, lrm); + } + + /* Move explicit bit from bit 52 to bit 126 */ + lzm = 0; + hzm = zm << 10; + assert(hzm & (1 << 62)); + /* Make the exponents the same */ if (ze > re) { /* * Have to shift y fraction right to align. */ s = ze - re; - rm = XDPSRS(rm, s); + srl128(&hrm, &lrm, s); re += s; } else if (re > ze) { /* * Have to shift x fraction right to align. */ s = re - ze; - zm = XDPSRS(zm, s); + srl128(&hzm, &lzm, s); ze += s; } assert(ze == re); assert(ze <= DP_EMAX); + /* Do the addition */ if (zs == rs) { /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in xm, xs and xe. + * Generate 128 bit result by adding two 127 bit numbers + * leaving result in hzm:lzm, zs and ze. */ - zm = zm + rm; - - if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ - zm = XDPSRS1(zm); + hzm = hzm + hrm + (lzm > (lzm + lrm)); + lzm = lzm + lrm; + if ((int64_t)hzm < 0) { /* carry out */ + srl128(&hzm, &lzm, 1); ze++; } } else { - if (zm >= rm) { - zm = zm - rm; + if (hzm > hrm || (hzm == hrm && lzm >= lrm)) { + hzm = hzm - hrm - (lzm < lrm); + lzm = lzm - lrm; } else { - zm = rm - zm; + hzm = hrm - hzm - (lrm < lzm); + lzm = lrm - lzm; zs = rs; } - if (zm == 0) + if (lzm == 0 && hzm == 0) return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); /* - * Normalize to rounding precision. + * Put explicit bit at bit 126 if necessary. */ - while ((zm >> (DP_FBITS + 3)) == 0) { - zm <<= 1; - ze--; + if (hzm == 0) { + /* left shift by 63 or 64 bits */ + if ((int64_t)lzm < 0) { + /* MSB of lzm is the explicit bit */ + hzm = lzm >> 1; + lzm = lzm << 63; + ze -= 63; + } else { + hzm = lzm; + lzm = 0; + ze -= 64; + } + } + + t = 0; + while ((hzm >> (62 - t)) == 0) + t++; + + assert(t <= 62); + if (t) { + hzm = hzm << t | lzm >> (64 - t); + lzm = lzm << t; + ze -= t; } } - return ieee754dp_format(zs, ze, zm); + /* + * Move explicit bit from bit 126 to bit 55 since the + * ieee754dp_format code expects the mantissa to be + * 56 bits wide (53 + 3 rounding bits). + */ + srl128(&hzm, &lzm, (126 - 55)); + + return ieee754dp_format(zs, ze, lzm); } union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, @@ -278,5 +343,5 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, union ieee754dp y) { - return _dp_maddf(z, x, y, maddf_negate_product); + return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT); } diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 8bc2f6963324de776a3ab66ec33638e2b8598211..dd2071f430e0bd180dce8e79bbf00df77b7318dc 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -26,6 +26,10 @@ #define CLPAIR(x, y) ((x)*6+(y)) +enum maddf_flags { + MADDF_NEGATE_PRODUCT = 1 << 0, +}; + static inline void ieee754_clearcx(void) { ieee754_csr.cx = 0; diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 8476067075fe013331609ed3db1028b04b9d3e66..0f63e4202cffa214009b0b29c041690645159267 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -45,6 +45,10 @@ static inline int ieee754sp_finite(union ieee754sp x) return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; } +/* 64 bit right shift with rounding */ +#define XSPSRS64(v, rs) \ + (((rs) >= 64) ? ((v) != 0) : ((v) >> (rs)) | ((v) << (64-(rs)) != 0)) + /* 3bit extended single precision sticky right shift */ #define XSPSRS(v, rs) \ ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0)) diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c index 4d000844e48e3d1f7560a3e9dead69ffd9743a2c..74a5a00d2f22b87917cae25c02f9b4f568569dd0 100644 --- a/arch/mips/math-emu/sp_fmax.c +++ b/arch/mips/math-emu/sp_fmax.c @@ -47,14 +47,26 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754sp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -80,9 +92,7 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) return ys ? x : y; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754sp_zero(1); + return ieee754sp_zero(xs & ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; @@ -106,16 +116,32 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) else if (xs < ys) return x; - /* Compare exponent */ - if (xe > ye) - return x; - else if (xe < ye) - return y; + /* Signs of inputs are equal, let's compare exponents */ + if (xs == 0) { + /* Inputs are both positive */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + } else { + /* Inputs are both negative */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + } - /* Compare mantissa */ + /* Signs and exponents of inputs are equal, let's compare mantissas */ + if (xs == 0) { + /* Inputs are both positive, with equal signs and exponents */ + if (xm <= ym) + return y; + return x; + } + /* Inputs are both negative, with equal signs and exponents */ if (xm <= ym) - return y; - return x; + return x; + return y; } union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) @@ -147,14 +173,26 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754sp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -164,6 +202,9 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) /* * Infinity and zero handling */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754sp_inf(xs & ys); + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): @@ -171,7 +212,6 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): return x; - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): @@ -180,9 +220,7 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) return y; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754sp_zero(1); + return ieee754sp_zero(xs & ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; @@ -207,7 +245,11 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) return y; /* Compare mantissa */ - if (xm <= ym) + if (xm < ym) return y; - return x; + else if (xm > ym) + return x; + else if (xs == 0) + return x; + return y; } diff --git a/arch/mips/math-emu/sp_fmin.c b/arch/mips/math-emu/sp_fmin.c index 4eb1bb9e9dec7b45e36355f2bd2eac7da9990810..c51385f46b09968611764d26db082cbf680e8744 100644 --- a/arch/mips/math-emu/sp_fmin.c +++ b/arch/mips/math-emu/sp_fmin.c @@ -47,14 +47,26 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754sp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -80,9 +92,7 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) return ys ? y : x; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754sp_zero(1); + return ieee754sp_zero(xs | ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; @@ -106,16 +116,32 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) else if (xs < ys) return y; - /* Compare exponent */ - if (xe > ye) - return y; - else if (xe < ye) - return x; + /* Signs of inputs are the same, let's compare exponents */ + if (xs == 0) { + /* Inputs are both positive */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + } else { + /* Inputs are both negative */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + } - /* Compare mantissa */ + /* Signs and exponents of inputs are equal, let's compare mantissas */ + if (xs == 0) { + /* Inputs are both positive, with equal signs and exponents */ + if (xm <= ym) + return x; + return y; + } + /* Inputs are both negative, with equal signs and exponents */ if (xm <= ym) - return x; - return y; + return y; + return x; } union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) @@ -147,14 +173,26 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): return ieee754sp_nanxcpt(x); - /* numbers are preferred to NaNs */ + /* + * Quiet NaN handling + */ + + /* + * The case of both inputs quiet NaNs + */ + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + return x; + + /* + * The cases of exactly one input quiet NaN (numbers + * are here preferred as returned values to NaNs) + */ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): return x; - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): @@ -164,25 +202,25 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) /* * Infinity and zero handling */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + return ieee754sp_inf(xs | ys); + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - return x; + return y; - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - return y; + return x; case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - if (xs == ys) - return x; - return ieee754sp_zero(1); + return ieee754sp_zero(xs | ys); case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; @@ -207,7 +245,11 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) return x; /* Compare mantissa */ - if (xm <= ym) + if (xm < ym) + return x; + else if (xm > ym) + return y; + else if (xs == 1) return x; return y; } diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index a8cd8b4f235eb810db8c0472dea29c82dc2cd173..7195fe785d81a8f0a2dda6c2139b95175321803c 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -14,9 +14,6 @@ #include "ieee754sp.h" -enum maddf_flags { - maddf_negate_product = 1 << 0, -}; static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp y, enum maddf_flags flags) @@ -24,14 +21,8 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, int re; int rs; unsigned rm; - unsigned short lxm; - unsigned short hxm; - unsigned short lym; - unsigned short hym; - unsigned lrm; - unsigned hrm; - unsigned t; - unsigned at; + uint64_t rm64; + uint64_t zm64; int s; COMPXSP; @@ -48,51 +39,35 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, ieee754_clearcx(); - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); + /* + * Handle the cases when at least one of x, y or z is a NaN. + * Order of precedence is sNaN, qNaN and z, x, y. + */ + if (zc == IEEE754_CLASS_SNAN) return ieee754sp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - SPDNORMZ; - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + if (xc == IEEE754_CLASS_SNAN) + return ieee754sp_nanxcpt(x); + if (yc == IEEE754_CLASS_SNAN) return ieee754sp_nanxcpt(y); + if (zc == IEEE754_CLASS_QNAN) + return z; + if (xc == IEEE754_CLASS_QNAN) + return x; + if (yc == IEEE754_CLASS_QNAN) + return y; - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x); + if (zc == IEEE754_CLASS_DNORM) + SPDNORMZ; + /* ZERO z cases are handled separately below */ - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; + switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; /* * Infinity handling */ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754sp_indef(); @@ -101,9 +76,27 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754sp_inf(xs ^ ys); + if ((zc == IEEE754_CLASS_INF) && + ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) || + ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) { + /* + * Cases of addition of infinities with opposite signs + * or subtraction of infinities with same signs. + */ + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); + } + /* + * z is here either not an infinity, or an infinity having the + * same sign as product (x*y) (in case of MADDF.D instruction) + * or product -(x*y) (in MSUBF.D case). The result must be an + * infinity, and its sign is determined only by the value of + * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y. + */ + if (flags & MADDF_NEGATE_PRODUCT) + return ieee754sp_inf(1 ^ (xs ^ ys)); + else + return ieee754sp_inf(xs ^ ys); case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): @@ -112,32 +105,42 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); - /* Multiplication is 0 so just return z */ + if (zc == IEEE754_CLASS_ZERO) { + /* Handle cases +0 + (-0) and similar ones. */ + if ((!(flags & MADDF_NEGATE_PRODUCT) + && (zs == (xs ^ ys))) || + ((flags & MADDF_NEGATE_PRODUCT) + && (zs != (xs ^ ys)))) + /* + * Cases of addition of zeros of equal signs + * or subtraction of zeroes of opposite signs. + * The sign of the resulting zero is in any + * such case determined only by the sign of z. + */ + return z; + + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); + } + /* x*y is here 0, and z is not 0, so just return z */ return z; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): SPDNORMX; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); SPDNORMY; break; case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); SPDNORMX; break; case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) + if (zc == IEEE754_CLASS_INF) return ieee754sp_inf(zs); /* fall through to real computations */ } @@ -158,108 +161,93 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, re = xe + ye; rs = xs ^ ys; - if (flags & maddf_negate_product) + if (flags & MADDF_NEGATE_PRODUCT) rs ^= 1; - /* shunt to top of word */ - xm <<= 32 - (SP_FBITS + 1); - ym <<= 32 - (SP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - lxm = xm & 0xffff; - hxm = xm >> 16; - lym = ym & 0xffff; - hym = ym >> 16; - - lrm = lxm * lym; /* 16 * 16 => 32 */ - hrm = hxm * hym; /* 16 * 16 => 32 */ + /* Multiple 24 bit xm and ym to give 48 bit results */ + rm64 = (uint64_t)xm * ym; - t = lxm * hym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); + /* Shunt to top of word */ + rm64 = rm64 << 16; - t = hxm * lym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((int) rm < 0) { - rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | - ((rm << (SP_FBITS + 1 + 3)) != 0); + /* Put explicit bit at bit 62 if necessary */ + if ((int64_t) rm64 < 0) { + rm64 = rm64 >> 1; re++; - } else { - rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | - ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); } - assert(rm & (SP_HIDDEN_BIT << 3)); - /* And now the addition */ + assert(rm64 & (1 << 62)); - assert(zm & SP_HIDDEN_BIT); + if (zc == IEEE754_CLASS_ZERO) { + /* + * Move explicit bit from bit 62 to bit 26 since the + * ieee754sp_format code expects the mantissa to be + * 27 bits wide (24 + 3 rounding bits). + */ + rm = XSPSRS64(rm64, (62 - 26)); + return ieee754sp_format(rs, re, rm); + } - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; + /* Move explicit bit from bit 23 to bit 62 */ + zm64 = (uint64_t)zm << (62 - 23); + assert(zm64 & (1 << 62)); + /* Make the exponents the same */ if (ze > re) { /* * Have to shift r fraction right to align. */ s = ze - re; - rm = XSPSRS(rm, s); + rm64 = XSPSRS64(rm64, s); re += s; } else if (re > ze) { /* * Have to shift z fraction right to align. */ s = re - ze; - zm = XSPSRS(zm, s); + zm64 = XSPSRS64(zm64, s); ze += s; } assert(ze == re); assert(ze <= SP_EMAX); + /* Do the addition */ if (zs == rs) { /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in zm, zs and ze. + * Generate 64 bit result by adding two 63 bit numbers + * leaving result in zm64, zs and ze. */ - zm = zm + rm; - - if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - zm = XSPSRS1(zm); + zm64 = zm64 + rm64; + if ((int64_t)zm64 < 0) { /* carry out */ + zm64 = XSPSRS1(zm64); ze++; } } else { - if (zm >= rm) { - zm = zm - rm; + if (zm64 >= rm64) { + zm64 = zm64 - rm64; } else { - zm = rm - zm; + zm64 = rm64 - zm64; zs = rs; } - if (zm == 0) + if (zm64 == 0) return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); /* - * Normalize in extended single precision + * Put explicit bit at bit 62 if necessary. */ - while ((zm >> (SP_MBITS + 3)) == 0) { - zm <<= 1; + while ((zm64 >> 62) == 0) { + zm64 <<= 1; ze--; } - } + + /* + * Move explicit bit from bit 62 to bit 26 since the + * ieee754sp_format code expects the mantissa to be + * 27 bits wide (24 + 3 rounding bits). + */ + zm = XSPSRS64(zm64, (62 - 26)); + return ieee754sp_format(zs, ze, zm); } @@ -272,5 +260,5 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, union ieee754sp y) { - return _sp_maddf(z, x, y, maddf_negate_product); + return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT); } diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c index d08ea3ff0f53345e7501dd168f32c2177976f6ee..a44052c05f93efe23db370205b5ee58606128e23 100644 --- a/arch/mips/mm/mmap.c +++ b/arch/mips/mm/mmap.c @@ -92,7 +92,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c index 277cf52d80e1895c142970fb43c6a5c49044955a..6c17cba7f383c5d17288140459ca5aac20f02390 100644 --- a/arch/mips/mm/uasm-micromips.c +++ b/arch/mips/mm/uasm-micromips.c @@ -80,7 +80,7 @@ static struct insn insn_table_MM[] = { { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS }, { insn_lb, M(mm_lb32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, { insn_ld, 0, 0 }, - { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RS | RS | SIMM }, + { insn_lh, M(mm_lh32_op, 0, 0, 0, 0, 0), RT | RS | SIMM }, { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM }, { insn_lld, 0, 0 }, { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM }, diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 3660dc67d544fbd44c4ff7188fbc0d000fcabf4e..f4961bc9a61d54baad92908ec1660ba534d471a0 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -275,7 +275,7 @@ asmlinkage void plat_irq_dispatch(void) do_IRQ(nlm_irq_to_xirq(node, i)); } -#ifdef CONFIG_OF +#ifdef CONFIG_CPU_XLP static const struct irq_domain_ops xlp_pic_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; @@ -348,7 +348,7 @@ void __init arch_init_irq(void) #if defined(CONFIG_CPU_XLR) nlm_setup_fmn_irq(); #endif -#if defined(CONFIG_OF) +#ifdef CONFIG_CPU_XLP of_irq_init(xlp_pic_irq_ids); #endif } diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 628c5132b3d8b254ad0c590ef9a606af05412972..a7962f79c4fe18d82266e2a1739c74dd63a48ec8 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -121,7 +121,7 @@ static int wait_pciephy_busy(void) else break; if (retry++ > WAITRETRY_MAX) { - printk(KERN_WARN "PCIE-PHY retry failed.\n"); + pr_warn("PCIE-PHY retry failed.\n"); return -1; } } diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 3c7c9bf57bf36cac56de4c7d9e8df527f0acac88..0696142048d58e5de26d2cf750189c27e72bffba 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -141,8 +141,8 @@ static struct rt2880_pmx_func i2c_grp_mt7628[] = { FUNC("i2c", 0, 4, 2), }; -static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) }; -static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) }; +static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("refclk", 0, 37, 1) }; +static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 36, 1) }; static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) }; static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) }; @@ -176,7 +176,7 @@ static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = { static struct rt2880_pmx_func spis_grp_mt7628[] = { FUNC("pwm_uart2", 3, 14, 4), - FUNC("util", 2, 14, 4), + FUNC("utif", 2, 14, 4), FUNC("gpio", 1, 14, 4), FUNC("spis", 0, 14, 4), }; @@ -190,28 +190,28 @@ static struct rt2880_pmx_func gpio_grp_mt7628[] = { static struct rt2880_pmx_func p4led_kn_grp_mt7628[] = { FUNC("jtag", 3, 30, 1), - FUNC("util", 2, 30, 1), + FUNC("utif", 2, 30, 1), FUNC("gpio", 1, 30, 1), FUNC("p4led_kn", 0, 30, 1), }; static struct rt2880_pmx_func p3led_kn_grp_mt7628[] = { FUNC("jtag", 3, 31, 1), - FUNC("util", 2, 31, 1), + FUNC("utif", 2, 31, 1), FUNC("gpio", 1, 31, 1), FUNC("p3led_kn", 0, 31, 1), }; static struct rt2880_pmx_func p2led_kn_grp_mt7628[] = { FUNC("jtag", 3, 32, 1), - FUNC("util", 2, 32, 1), + FUNC("utif", 2, 32, 1), FUNC("gpio", 1, 32, 1), FUNC("p2led_kn", 0, 32, 1), }; static struct rt2880_pmx_func p1led_kn_grp_mt7628[] = { FUNC("jtag", 3, 33, 1), - FUNC("util", 2, 33, 1), + FUNC("utif", 2, 33, 1), FUNC("gpio", 1, 33, 1), FUNC("p1led_kn", 0, 33, 1), }; @@ -232,28 +232,28 @@ static struct rt2880_pmx_func wled_kn_grp_mt7628[] = { static struct rt2880_pmx_func p4led_an_grp_mt7628[] = { FUNC("jtag", 3, 39, 1), - FUNC("util", 2, 39, 1), + FUNC("utif", 2, 39, 1), FUNC("gpio", 1, 39, 1), FUNC("p4led_an", 0, 39, 1), }; static struct rt2880_pmx_func p3led_an_grp_mt7628[] = { FUNC("jtag", 3, 40, 1), - FUNC("util", 2, 40, 1), + FUNC("utif", 2, 40, 1), FUNC("gpio", 1, 40, 1), FUNC("p3led_an", 0, 40, 1), }; static struct rt2880_pmx_func p2led_an_grp_mt7628[] = { FUNC("jtag", 3, 41, 1), - FUNC("util", 2, 41, 1), + FUNC("utif", 2, 41, 1), FUNC("gpio", 1, 41, 1), FUNC("p2led_an", 0, 41, 1), }; static struct rt2880_pmx_func p1led_an_grp_mt7628[] = { FUNC("jtag", 3, 42, 1), - FUNC("util", 2, 42, 1), + FUNC("utif", 2, 42, 1), FUNC("gpio", 1, 42, 1), FUNC("p1led_an", 0, 42, 1), }; diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index 9e4631acfcb52fc22960fa5bb0c08f06d35b042d..3e68e35daf2130d389bf22f0625fb775f569a0a3 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -145,5 +145,5 @@ void prom_soc_init(struct ralink_soc_info *soc_info) rt2880_pinmux_data = rt3883_pinmux_data; - ralink_soc == RT3883_SOC; + ralink_soc = RT3883_SOC; } diff --git a/arch/mn10300/include/asm/switch_to.h b/arch/mn10300/include/asm/switch_to.h index 393d311735c8b573bd5702eac1dcaaac1103600e..67e333aa7629c406745564cb24acc5903733ec41 100644 --- a/arch/mn10300/include/asm/switch_to.h +++ b/arch/mn10300/include/asm/switch_to.h @@ -16,7 +16,7 @@ struct task_struct; struct thread_struct; -#if !defined(CONFIG_LAZY_SAVE_FPU) +#if defined(CONFIG_FPU) && !defined(CONFIG_LAZY_SAVE_FPU) struct fpu_state_struct; extern asmlinkage void fpu_save(struct fpu_state_struct *); #define switch_fpu(prev, next) \ diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h index 5129f23a9ee1008fc4b7203d2af689b0bc915a46..69f96180a3f4d1a9f4147b14ddfe74aab074d761 100644 --- a/arch/mn10300/include/uapi/asm/socket.h +++ b/arch/mn10300/include/uapi/asm/socket.h @@ -90,4 +90,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h index 140faa16685a2325f3a1b6cbf9cbb9c8e68fc913..1311e6b139916692bb5f81fbfd188a48b844d977 100644 --- a/arch/openrisc/include/asm/uaccess.h +++ b/arch/openrisc/include/asm/uaccess.h @@ -211,7 +211,7 @@ do { \ case 1: __get_user_asm(x, ptr, retval, "l.lbz"); break; \ case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break; \ case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break; \ - case 8: __get_user_asm2(x, ptr, retval); \ + case 8: __get_user_asm2(x, ptr, retval); break; \ default: (x) = __get_user_bad(); \ } \ } while (0) diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S index d68b9ede84231fe618062a68b190491cd25eeba6..c50609aead354871ecb1d769463d9056f59515ba 100644 --- a/arch/openrisc/kernel/vmlinux.lds.S +++ b/arch/openrisc/kernel/vmlinux.lds.S @@ -38,6 +38,8 @@ SECTIONS /* Read-only sections, merged into text segment: */ . = LOAD_BASE ; + _text = .; + /* _s_kernel_ro must be page aligned */ . = ALIGN(PAGE_SIZE); _s_kernel_ro = .; diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index 16e024602737085eee5c3bdfae979fc5e578e2a1..cb7697dec2941e3c52099b72e152cbdeace2d34a 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -20,6 +20,8 @@ ** flush/purge and allocate "regular" cacheable pages for everything. */ +#define DMA_ERROR_CODE (~(dma_addr_t)0) + #ifdef CONFIG_PA11 extern struct dma_map_ops pcxl_dma_ops; extern struct dma_map_ops pcx_dma_ops; @@ -54,12 +56,13 @@ parisc_walk_tree(struct device *dev) break; } } - BUG_ON(!dev->platform_data); return dev->platform_data; } - -#define GET_IOC(dev) (HBA_DATA(parisc_walk_tree(dev))->iommu) - + +#define GET_IOC(dev) ({ \ + void *__pdata = parisc_walk_tree(dev); \ + __pdata ? HBA_DATA(__pdata)->iommu : NULL; \ +}) #ifdef CONFIG_IOMMU_CCIO struct parisc_device; diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h index 8be707e1b6c77f291a722a0f2b4b1cdb62a1f273..82dea145574eb646fd8f298e00e8ed7d0249876f 100644 --- a/arch/parisc/include/asm/ldcw.h +++ b/arch/parisc/include/asm/ldcw.h @@ -11,6 +11,7 @@ for the semaphore. */ #define __PA_LDCW_ALIGNMENT 16 +#define __PA_LDCW_ALIGN_ORDER 4 #define __ldcw_align(a) ({ \ unsigned long __ret = (unsigned long) &(a)->lock[0]; \ __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) \ @@ -28,6 +29,7 @@ ldcd). */ #define __PA_LDCW_ALIGNMENT 4 +#define __PA_LDCW_ALIGN_ORDER 2 #define __ldcw_align(a) (&(a)->slock) #define __LDCW "ldcw,co" diff --git a/arch/parisc/include/asm/mmu_context.h b/arch/parisc/include/asm/mmu_context.h index 59be257644335f7fff70b54ca65661633b9eaa22..a8122625787846b8ee4233217911b23e7b89e2f6 100644 --- a/arch/parisc/include/asm/mmu_context.h +++ b/arch/parisc/include/asm/mmu_context.h @@ -49,15 +49,26 @@ static inline void load_context(mm_context_t context) mtctl(__space_to_prot(context), 8); } -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) +static inline void switch_mm_irqs_off(struct mm_struct *prev, + struct mm_struct *next, struct task_struct *tsk) { - if (prev != next) { mtctl(__pa(next->pgd), 25); load_context(next->context); } } +static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, struct task_struct *tsk) +{ + unsigned long flags; + + local_irq_save(flags); + switch_mm_irqs_off(prev, next, tsk); + local_irq_restore(flags); +} +#define switch_mm_irqs_off switch_mm_irqs_off + #define deactivate_mm(tsk,mm) do { } while (0) static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index 9c935d717df94c998dce3dc66ad8eefd1b71d066..b96a193a2a4d578d1348098a176df6c49163ee4c 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -89,4 +89,6 @@ #define SO_CNX_ADVICE 0x402E +#define SO_COOKIE 0x4032 + #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 53ec75f8e23762b79fc79b542988a42cbf20cbfd..df757c9675e670c0e6e158788189f002cbae6261 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -452,8 +452,8 @@ void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, before it can be accessed through the kernel mapping. */ preempt_disable(); flush_dcache_page_asm(__pa(vfrom), vaddr); - preempt_enable(); copy_page_asm(vto, vfrom); + preempt_enable(); } EXPORT_SYMBOL(copy_user_page); @@ -538,6 +538,10 @@ void flush_cache_mm(struct mm_struct *mm) struct vm_area_struct *vma; pgd_t *pgd; + /* Flush the TLB to avoid speculation if coherency is required. */ + if (parisc_requires_coherency()) + flush_tlb_all(); + /* Flushing the whole cache on each cpu takes forever on rp3440, etc. So, avoid it if the mm isn't too big. */ if (mm_total_size(mm) >= parisc_cache_flush_threshold) { @@ -594,33 +598,21 @@ flush_user_icache_range(unsigned long start, unsigned long end) void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - unsigned long addr; - pgd_t *pgd; - BUG_ON(!vma->vm_mm->context); - if ((end - start) >= parisc_cache_flush_threshold) { - flush_cache_all(); - return; - } + /* Flush the TLB to avoid speculation if coherency is required. */ + if (parisc_requires_coherency()) + flush_tlb_range(vma, start, end); - if (vma->vm_mm->context == mfsp(3)) { - flush_user_dcache_range_asm(start, end); - if (vma->vm_flags & VM_EXEC) - flush_user_icache_range_asm(start, end); + if ((end - start) >= parisc_cache_flush_threshold + || vma->vm_mm->context != mfsp(3)) { + flush_cache_all(); return; } - pgd = vma->vm_mm->pgd; - for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) { - unsigned long pfn; - pte_t *ptep = get_ptep(pgd, addr); - if (!ptep) - continue; - pfn = pte_pfn(*ptep); - if (pfn_valid(pfn)) - __flush_cache_page(vma, addr, PFN_PHYS(pfn)); - } + flush_user_dcache_range_asm(start, end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(start, end); } void @@ -629,7 +621,8 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long BUG_ON(!vma->vm_mm->context); if (pfn_valid(pfn)) { - flush_tlb_page(vma, vmaddr); + if (parisc_requires_coherency()) + flush_tlb_page(vma, vmaddr); __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); } } diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 4fcff2dcc9c304decddf7b7643e90f7803968531..e3d3e8e1d708216dc2a5337b5799c41c27457265 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,14 @@ #endif .import pa_tlb_lock,data + .macro load_pa_tlb_lock reg +#if __PA_LDCW_ALIGNMENT > 4 + load32 PA(pa_tlb_lock) + __PA_LDCW_ALIGNMENT-1, \reg + depi 0,31,__PA_LDCW_ALIGN_ORDER, \reg +#else + load32 PA(pa_tlb_lock), \reg +#endif + .endm /* space_to_prot macro creates a prot id from a space id */ @@ -457,7 +466,7 @@ .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault #ifdef CONFIG_SMP cmpib,COND(=),n 0,\spc,2f - load32 PA(pa_tlb_lock),\tmp + load_pa_tlb_lock \tmp 1: LDCW 0(\tmp),\tmp1 cmpib,COND(=) 0,\tmp1,1b nop @@ -480,7 +489,7 @@ /* Release pa_tlb_lock lock. */ .macro tlb_unlock1 spc,tmp #ifdef CONFIG_SMP - load32 PA(pa_tlb_lock),\tmp + load_pa_tlb_lock \tmp tlb_unlock0 \spc,\tmp #endif .endm diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index adf7187f89515ec69b19461f60ce379e552397dc..2d40c4ff3f6918ae9b2e2c6af71e20658a9850e1 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -36,6 +36,7 @@ #include #include #include +#include #include .text @@ -333,8 +334,12 @@ ENDPROC_CFI(flush_data_cache_local) .macro tlb_lock la,flags,tmp #ifdef CONFIG_SMP - ldil L%pa_tlb_lock,%r1 - ldo R%pa_tlb_lock(%r1),\la +#if __PA_LDCW_ALIGNMENT > 4 + load32 pa_tlb_lock + __PA_LDCW_ALIGNMENT-1, \la + depi 0,31,__PA_LDCW_ALIGN_ORDER, \la +#else + load32 pa_tlb_lock, \la +#endif rsm PSW_SM_I,\flags 1: LDCW 0(\la),\tmp cmpib,<>,n 0,\tmp,3f diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index 518f4f5f1f43ec6b2dcaceb9b2f5c9536097d59f..d63d42533133af4eb390200ff14b707d6da58ba6 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -39,7 +39,7 @@ * the PDC INTRIGUE calls. This is done to eliminate bugs introduced * in various PDC revisions. The code is much more maintainable * and reliable this way vs having to debug on every version of PDC - * on every box. + * on every box. */ #include @@ -195,8 +195,8 @@ static int perf_config(uint32_t *image_ptr); static int perf_release(struct inode *inode, struct file *file); static int perf_open(struct inode *inode, struct file *file); static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos); -static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos); +static ssize_t perf_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos); static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static void perf_start_counters(void); static int perf_stop_counters(uint32_t *raddr); @@ -222,7 +222,7 @@ extern void perf_intrigue_disable_perf_counters (void); /* * configure: * - * Configure the cpu with a given data image. First turn off the counters, + * Configure the cpu with a given data image. First turn off the counters, * then download the image, then turn the counters back on. */ static int perf_config(uint32_t *image_ptr) @@ -234,7 +234,7 @@ static int perf_config(uint32_t *image_ptr) error = perf_stop_counters(raddr); if (error != 0) { printk("perf_config: perf_stop_counters = %ld\n", error); - return -EINVAL; + return -EINVAL; } printk("Preparing to write image\n"); @@ -242,7 +242,7 @@ printk("Preparing to write image\n"); error = perf_write_image((uint64_t *)image_ptr); if (error != 0) { printk("perf_config: DOWNLOAD = %ld\n", error); - return -EINVAL; + return -EINVAL; } printk("Preparing to start counters\n"); @@ -254,7 +254,7 @@ printk("Preparing to start counters\n"); } /* - * Open the device and initialize all of its memory. The device is only + * Open the device and initialize all of its memory. The device is only * opened once, but can be "queried" by multiple processes that know its * file descriptor. */ @@ -298,8 +298,8 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t * called on the processor that the download should happen * on. */ -static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) +static ssize_t perf_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { int err; size_t image_size; @@ -307,11 +307,11 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun uint32_t interface_type; uint32_t test; - if (perf_processor_interface == ONYX_INTF) + if (perf_processor_interface == ONYX_INTF) image_size = PCXU_IMAGE_SIZE; - else if (perf_processor_interface == CUDA_INTF) + else if (perf_processor_interface == CUDA_INTF) image_size = PCXW_IMAGE_SIZE; - else + else return -EFAULT; if (!capable(CAP_SYS_ADMIN)) @@ -331,22 +331,22 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun /* First check the machine type is correct for the requested image */ - if (((perf_processor_interface == CUDA_INTF) && - (interface_type != CUDA_INTF)) || - ((perf_processor_interface == ONYX_INTF) && - (interface_type != ONYX_INTF))) + if (((perf_processor_interface == CUDA_INTF) && + (interface_type != CUDA_INTF)) || + ((perf_processor_interface == ONYX_INTF) && + (interface_type != ONYX_INTF))) return -EINVAL; /* Next check to make sure the requested image is valid */ - if (((interface_type == CUDA_INTF) && + if (((interface_type == CUDA_INTF) && (test >= MAX_CUDA_IMAGES)) || - ((interface_type == ONYX_INTF) && - (test >= MAX_ONYX_IMAGES))) + ((interface_type == ONYX_INTF) && + (test >= MAX_ONYX_IMAGES))) return -EINVAL; /* Copy the image into the processor */ - if (interface_type == CUDA_INTF) + if (interface_type == CUDA_INTF) return perf_config(cuda_images[test]); else return perf_config(onyx_images[test]); @@ -360,7 +360,7 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun static void perf_patch_images(void) { #if 0 /* FIXME!! */ -/* +/* * NOTE: this routine is VERY specific to the current TLB image. * If the image is changed, this routine might also need to be changed. */ @@ -368,9 +368,9 @@ static void perf_patch_images(void) extern void $i_dtlb_miss_2_0(); extern void PA2_0_iva(); - /* + /* * We can only use the lower 32-bits, the upper 32-bits should be 0 - * anyway given this is in the kernel + * anyway given this is in the kernel */ uint32_t itlb_addr = (uint32_t)&($i_itlb_miss_2_0); uint32_t dtlb_addr = (uint32_t)&($i_dtlb_miss_2_0); @@ -378,21 +378,21 @@ static void perf_patch_images(void) if (perf_processor_interface == ONYX_INTF) { /* clear last 2 bytes */ - onyx_images[TLBMISS][15] &= 0xffffff00; + onyx_images[TLBMISS][15] &= 0xffffff00; /* set 2 bytes */ onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24)); onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00; onyx_images[TLBMISS][17] = itlb_addr; /* clear last 2 bytes */ - onyx_images[TLBHANDMISS][15] &= 0xffffff00; + onyx_images[TLBHANDMISS][15] &= 0xffffff00; /* set 2 bytes */ onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24)); onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00; onyx_images[TLBHANDMISS][17] = itlb_addr; /* clear last 2 bytes */ - onyx_images[BIG_CPI][15] &= 0xffffff00; + onyx_images[BIG_CPI][15] &= 0xffffff00; /* set 2 bytes */ onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24)); onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00; @@ -405,24 +405,24 @@ static void perf_patch_images(void) } else if (perf_processor_interface == CUDA_INTF) { /* Cuda interface */ - cuda_images[TLBMISS][16] = + cuda_images[TLBMISS][16] = (cuda_images[TLBMISS][16]&0xffff0000) | ((dtlb_addr >> 8)&0x0000ffff); - cuda_images[TLBMISS][17] = + cuda_images[TLBMISS][17] = ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff); cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000; - cuda_images[TLBHANDMISS][16] = + cuda_images[TLBHANDMISS][16] = (cuda_images[TLBHANDMISS][16]&0xffff0000) | ((dtlb_addr >> 8)&0x0000ffff); - cuda_images[TLBHANDMISS][17] = + cuda_images[TLBHANDMISS][17] = ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff); cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000; - cuda_images[BIG_CPI][16] = + cuda_images[BIG_CPI][16] = (cuda_images[BIG_CPI][16]&0xffff0000) | ((dtlb_addr >> 8)&0x0000ffff); - cuda_images[BIG_CPI][17] = + cuda_images[BIG_CPI][17] = ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff); cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000; } else { @@ -434,7 +434,7 @@ static void perf_patch_images(void) /* * ioctl routine - * All routines effect the processor that they are executed on. Thus you + * All routines effect the processor that they are executed on. Thus you * must be running on the processor that you wish to change. */ @@ -460,7 +460,7 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } /* copy out the Counters */ - if (copy_to_user((void __user *)arg, raddr, + if (copy_to_user((void __user *)arg, raddr, sizeof (raddr)) != 0) { error = -EFAULT; break; @@ -488,7 +488,7 @@ static const struct file_operations perf_fops = { .open = perf_open, .release = perf_release }; - + static struct miscdevice perf_dev = { MISC_DYNAMIC_MINOR, PA_PERF_DEV, @@ -596,7 +596,7 @@ static int perf_stop_counters(uint32_t *raddr) /* OR sticky2 (bit 1496) to counter2 bit 32 */ tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000; raddr[2] = (uint32_t)tmp64; - + /* Counter3 is bits 1497 to 1528 */ tmp64 = (userbuf[23] >> 7) & 0x00000000ffffffff; /* OR sticky3 (bit 1529) to counter3 bit 32 */ @@ -618,7 +618,7 @@ static int perf_stop_counters(uint32_t *raddr) userbuf[22] = 0; userbuf[23] = 0; - /* + /* * Write back the zeroed bytes + the image given * the read was destructive. */ @@ -626,13 +626,13 @@ static int perf_stop_counters(uint32_t *raddr) } else { /* - * Read RDR-15 which contains the counters and sticky bits + * Read RDR-15 which contains the counters and sticky bits */ if (!perf_rdr_read_ubuf(15, userbuf)) { return -13; } - /* + /* * Clear out the counters */ perf_rdr_clear(15); @@ -645,7 +645,7 @@ static int perf_stop_counters(uint32_t *raddr) raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL); raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL); } - + return 0; } @@ -683,7 +683,7 @@ static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer) i = tentry->num_words; while (i--) { buffer[i] = 0; - } + } /* Check for bits an even number of 64 */ if ((xbits = width & 0x03f) != 0) { @@ -809,18 +809,22 @@ static int perf_write_image(uint64_t *memaddr) } runway = ioremap_nocache(cpu_device->hpa.start, 4096); + if (!runway) { + pr_err("perf_write_image: ioremap failed!\n"); + return -ENOMEM; + } /* Merge intrigue bits into Runway STATUS 0 */ tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful; - __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), + __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), runway + RUNWAY_STATUS); - + /* Write RUNWAY DEBUG registers */ for (i = 0; i < 8; i++) { __raw_writeq(*memaddr++, runway + RUNWAY_DEBUG); } - return 0; + return 0; } /* @@ -844,7 +848,7 @@ printk("perf_rdr_write\n"); perf_rdr_shift_out_U(rdr_num, buffer[i]); } else { perf_rdr_shift_out_W(rdr_num, buffer[i]); - } + } } printk("perf_rdr_write done\n"); } diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index e7ffde2758fc02784d6baa4c94210959889a2789..c3a532abac03951cf028017a58a0dc4dab5e1a4b 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include #include #include +#include #include #include @@ -142,6 +144,7 @@ void machine_power_off(void) /* prevent soft lockup/stalled CPU messages for endless loop. */ rcu_sysrq_start(); + lockup_detector_suspend(); for (;;); } @@ -178,6 +181,44 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) return 1; } +/* + * Idle thread support + * + * Detect when running on QEMU with SeaBIOS PDC Firmware and let + * QEMU idle the host too. + */ + +int running_on_qemu __read_mostly; + +void __cpuidle arch_cpu_idle_dead(void) +{ + /* nop on real hardware, qemu will offline CPU. */ + asm volatile("or %%r31,%%r31,%%r31\n":::); +} + +void __cpuidle arch_cpu_idle(void) +{ + local_irq_enable(); + + /* nop on real hardware, qemu will idle sleep. */ + asm volatile("or %%r10,%%r10,%%r10\n":::); +} + +static int __init parisc_idle_init(void) +{ + const char *marker; + + /* check QEMU/SeaBIOS marker in PAGE0 */ + marker = (char *) &PAGE0->pad0; + running_on_qemu = (memcmp(marker, "SeaBIOS", 8) == 0); + + if (!running_on_qemu) + cpu_idle_poll_ctrl(1); + + return 0; +} +arch_initcall(parisc_idle_init); + /* * Copy architecture-specific thread state */ diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 0a393a04e89182cba498fa64774dd32177860eb7..1d7691fa8ab25a4df935e4df5a6841697a3cbae0 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -88,7 +88,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; + struct vm_area_struct *vma, *prev; unsigned long task_size = TASK_SIZE; int do_color_align, last_mmap; struct vm_unmapped_area_info info; @@ -115,9 +115,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, else addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); + vma = find_vma_prev(mm, addr, &prev); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma)) && + (!prev || addr >= vm_end_gap(prev))) goto found_addr; } @@ -141,7 +142,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, const unsigned long len, const unsigned long pgoff, const unsigned long flags) { - struct vm_area_struct *vma; + struct vm_area_struct *vma, *prev; struct mm_struct *mm = current->mm; unsigned long addr = addr0; int do_color_align, last_mmap; @@ -175,9 +176,11 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = COLOR_ALIGN(addr, last_mmap, pgoff); else addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); + + vma = find_vma_prev(mm, addr, &prev); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma)) && + (!prev || addr >= vm_end_gap(prev))) goto found_addr; } diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 23de307c3052aa9ecac21fd6c294657fb53de447..e775f80ae28c5ab8d7fac7456235fa4f415c7215 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -690,15 +690,15 @@ cas_action: /* ELF32 Process entry path */ lws_compare_and_swap_2: #ifdef CONFIG_64BIT - /* Clip the input registers */ + /* Clip the input registers. We don't need to clip %r23 as we + only use it for word operations */ depdi 0, 31, 32, %r26 depdi 0, 31, 32, %r25 depdi 0, 31, 32, %r24 - depdi 0, 31, 32, %r23 #endif /* Check the validity of the size pointer */ - subi,>>= 4, %r23, %r0 + subi,>>= 3, %r23, %r0 b,n lws_exit_nosys /* Jump to the functions which will load the old and new values into @@ -742,7 +742,7 @@ lws_compare_and_swap_2: 10: ldd 0(%r25), %r25 11: ldd 0(%r24), %r24 #else - /* Load new value into r22/r23 - high/low */ + /* Load old value into r22/r23 - high/low */ 10: ldw 0(%r25), %r22 11: ldw 4(%r25), %r23 /* Load new value into fr4 for atomic store later */ @@ -834,11 +834,11 @@ cas2_action: copy %r0, %r28 #else /* Compare first word */ -19: ldw,ma 0(%r26), %r29 +19: ldw 0(%r26), %r29 sub,= %r29, %r22, %r0 b,n cas2_end /* Compare second word */ -20: ldw,ma 4(%r26), %r29 +20: ldw 4(%r26), %r29 sub,= %r29, %r23, %r0 b,n cas2_end /* Perform the store */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 3cfef1de8061af183820e98ca97467d674a8c463..8ec2ff8fae0d59be386ac4cb4287ba8377db4ccc 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -361,7 +361,7 @@ ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */ ENTRY_SAME(add_key) ENTRY_SAME(request_key) /* 265 */ - ENTRY_SAME(keyctl) + ENTRY_COMP(keyctl) ENTRY_SAME(ioprio_set) ENTRY_SAME(ioprio_get) ENTRY_SAME(inotify_init) diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 040c48fc53918c63b49a75ea5d2dc73caa980f96..b6f3b5e988106e492ed5680b5824ed5d066e794e 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -366,7 +366,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code, case 15: /* Data TLB miss fault/Data page fault */ /* send SIGSEGV when outside of vma */ if (!vma || - address < vma->vm_start || address > vma->vm_end) { + address < vma->vm_start || address >= vma->vm_end) { si.si_signo = SIGSEGV; si.si_code = SEGV_MAPERR; break; diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 65fba4c34cd75fd94e7565aeea211e223938c8fe..acb6026329dd82d8f95698c16508366abe560cc6 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -84,6 +84,7 @@ config PPC select ARCH_MIGHT_HAVE_PC_SERIO select BINFMT_ELF select ARCH_HAS_ELF_RANDOMIZE + select ARCH_HAS_FORTIFY_SOURCE select OF select OF_EARLY_FLATTREE select OF_RESERVED_MEM @@ -388,8 +389,8 @@ config DISABLE_MPROFILE_KERNEL be disabled also. If you have a toolchain which supports mprofile-kernel, then you can - enable this. Otherwise leave it disabled. If you're not sure, say - "N". + disable this. Otherwise leave it enabled. If you're not sure, say + "Y". config MPROFILE_KERNEL depends on PPC64 && CPU_LITTLE_ENDIAN @@ -1087,11 +1088,6 @@ source "arch/powerpc/Kconfig.debug" source "security/Kconfig" -config KEYS_COMPAT - bool - depends on COMPAT && KEYS - default y - source "crypto/Kconfig" config PPC_LIB_RHEAP diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 617dece6792427847458203c229505a054b5331e..a60c9c6e5cc17297e7b2e0e620c48b00838c4a09 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -72,8 +72,15 @@ GNUTARGET := powerpc MULTIPLEWORD := -mmultiple endif -cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mbig-endian) +ifdef CONFIG_PPC64 +cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mabi=elfv1) +cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mcall-aixdesc) +aflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mabi=elfv1) +aflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mabi=elfv2 +endif + cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mlittle-endian +cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mbig-endian) ifneq ($(cc-name),clang) cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mno-strict-align endif @@ -113,7 +120,9 @@ ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y) CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,$(call cc-option,-mcall-aixdesc)) AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2) else +CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1) CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcall-aixdesc) +AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1) endif CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,$(call cc-option,-mminimal-toc)) CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions) diff --git a/arch/powerpc/boot/dts/fsl/kmcoge4.dts b/arch/powerpc/boot/dts/fsl/kmcoge4.dts index ae70a24094b02bf3cf46e2edaba45d81e8ab132c..e103c0f3f650cb868a69b0f75696a7a2e344eefb 100644 --- a/arch/powerpc/boot/dts/fsl/kmcoge4.dts +++ b/arch/powerpc/boot/dts/fsl/kmcoge4.dts @@ -83,6 +83,10 @@ }; }; + sdhc@114000 { + status = "disabled"; + }; + i2c@119000 { status = "disabled"; }; diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 2b90335194a76b1ba39ea37c460700da1fc47a72..a2cc8010cd72a70f818d289a57f1bcbc1805bba4 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -560,7 +560,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) * Atomically increments @v by 1, so long as @v is non-zero. * Returns non-zero if @v was non-zero, and zero otherwise. */ -static __inline__ long atomic64_inc_not_zero(atomic64_t *v) +static __inline__ int atomic64_inc_not_zero(atomic64_t *v) { long t1, t2; @@ -579,7 +579,7 @@ static __inline__ long atomic64_inc_not_zero(atomic64_t *v) : "r" (&v->counter) : "cc", "xer", "memory"); - return t1; + return t1 != 0; } #endif /* __powerpc64__ */ diff --git a/arch/powerpc/include/asm/book3s/64/hash.h b/arch/powerpc/include/asm/book3s/64/hash.h index f61cad3de4e69ec093674355332f7d3ee093cf2b..4c935f7504f783532d3521d04142dfdb5831f943 100644 --- a/arch/powerpc/include/asm/book3s/64/hash.h +++ b/arch/powerpc/include/asm/book3s/64/hash.h @@ -201,6 +201,10 @@ extern int __meminit hash__vmemmap_create_mapping(unsigned long start, unsigned long phys); extern void hash__vmemmap_remove_mapping(unsigned long start, unsigned long page_size); + +int hash__create_section_mapping(unsigned long start, unsigned long end); +int hash__remove_section_mapping(unsigned long start, unsigned long end); + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_BOOK3S_64_HASH_H */ diff --git a/arch/powerpc/include/asm/checksum.h b/arch/powerpc/include/asm/checksum.h index 1e8fceb308a518950918e1ea7d9102eb313f66ee..430d038eb2a4e06b719abb8e79b9862c802dd4e2 100644 --- a/arch/powerpc/include/asm/checksum.h +++ b/arch/powerpc/include/asm/checksum.h @@ -53,17 +53,25 @@ static inline __sum16 csum_fold(__wsum sum) return (__force __sum16)(~((__force u32)sum + tmp) >> 16); } +static inline u32 from64to32(u64 x) +{ + /* add up 32-bit and 32-bit for 32+c bit */ + x = (x & 0xffffffff) + (x >> 32); + /* add up carry.. */ + x = (x & 0xffffffff) + (x >> 32); + return (u32)x; +} + static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __wsum sum) { #ifdef __powerpc64__ - unsigned long s = (__force u32)sum; + u64 s = (__force u32)sum; s += (__force u32)saddr; s += (__force u32)daddr; s += proto + len; - s += (s >> 32); - return (__force __wsum) s; + return (__force __wsum) from64to32(s); #else __asm__("\n\ addc %0,%0,%1 \n\ @@ -100,7 +108,7 @@ static inline __wsum csum_add(__wsum csum, __wsum addend) #ifdef __powerpc64__ res += (__force u64)addend; - return (__force __wsum)((u32)res + (res >> 32)); + return (__force __wsum) from64to32(res); #else asm("addc %0,%0,%1;" "addze %0,%0;" @@ -123,8 +131,7 @@ static inline __wsum ip_fast_csum_nofold(const void *iph, unsigned int ihl) for (i = 0; i < ihl - 1; i++, ptr++) s += *ptr; - s += (s >> 32); - return (__force __wsum)s; + return (__force __wsum)from64to32(s); #else __wsum sum, tmp; diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index ee46ffef608ee1679033a77c8ff5353ba6bfb51c..743ad7a400d6c85fc3e50eb59a388d724804131c 100644 --- a/arch/powerpc/include/asm/elf.h +++ b/arch/powerpc/include/asm/elf.h @@ -23,12 +23,13 @@ #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE PAGE_SIZE -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE 0x20000000 +/* + * This is the base location for PIE (ET_DYN with INTERP) loads. On + * 64-bit, this is raised to 4GB to leave the entire 32-bit address + * space open for things that want to use the area for 32-bit pointers. + */ +#define ELF_ET_DYN_BASE (is_32bit_task() ? 0x000400000UL : \ + 0x100000000UL) #define ELF_CORE_EFLAGS (is_elf2_task() ? 2 : 0) diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index b9e3f0aca261da2233a086cb41150bc3afacb9dc..fe208b70b8b147de98b3465a398ccfb8e6ffd125 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -70,13 +70,32 @@ extern void drop_cop(unsigned long acop, struct mm_struct *mm); * switch_mm is the entry point called from the architecture independent * code in kernel/sched/core.c */ -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) +static inline void switch_mm_irqs_off(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) { /* Mark this context has been used on the new CPU */ - if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next))) + if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next))) { cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); + /* + * This full barrier orders the store to the cpumask above vs + * a subsequent operation which allows this CPU to begin loading + * translations for next. + * + * When using the radix MMU that operation is the load of the + * MMU context id, which is then moved to SPRN_PID. + * + * For the hash MMU it is either the first load from slb_cache + * in switch_slb(), and/or the store of paca->mm_ctx_id in + * copy_mm_to_paca(). + * + * On the read side the barrier is in pte_xchg(), which orders + * the store to the PTE vs the load of mm_cpumask. + */ + smp_mb(); + } + /* 32-bit keeps track of the current PGDIR in the thread struct */ #ifdef CONFIG_PPC32 tsk->thread.pgdir = next->pgd; @@ -110,6 +129,18 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, switch_mmu_context(prev, next, tsk); } +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned long flags; + + local_irq_save(flags); + switch_mm_irqs_off(prev, next, tsk); + local_irq_restore(flags); +} +#define switch_mm_irqs_off switch_mm_irqs_off + + #define deactivate_mm(tsk,mm) do { } while (0) /* diff --git a/arch/powerpc/include/asm/pgtable-be-types.h b/arch/powerpc/include/asm/pgtable-be-types.h index 49c0a5a80efa2948764e247d3cbd76fc6fdf06a0..68e087e807f8c526457ff69a693b95ddce9e9688 100644 --- a/arch/powerpc/include/asm/pgtable-be-types.h +++ b/arch/powerpc/include/asm/pgtable-be-types.h @@ -87,6 +87,7 @@ static inline bool pte_xchg(pte_t *ptep, pte_t old, pte_t new) unsigned long *p = (unsigned long *)ptep; __be64 prev; + /* See comment in switch_mm_irqs_off() */ prev = (__force __be64)__cmpxchg_u64(p, (__force unsigned long)pte_raw(old), (__force unsigned long)pte_raw(new)); diff --git a/arch/powerpc/include/asm/pgtable-types.h b/arch/powerpc/include/asm/pgtable-types.h index e7f4f3e0fcde94ba237fa2a269c32d40458cc8f2..41e9d0a6cbeb608836acd25564598ee34b704482 100644 --- a/arch/powerpc/include/asm/pgtable-types.h +++ b/arch/powerpc/include/asm/pgtable-types.h @@ -62,6 +62,7 @@ static inline bool pte_xchg(pte_t *ptep, pte_t old, pte_t new) { unsigned long *p = (unsigned long *)ptep; + /* See comment in switch_mm_irqs_off() */ return pte_val(old) == __cmpxchg_u64(p, pte_val(old), pte_val(new)); } #endif diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 13f5fad21066eb11beb11c5d5ce5f69269e357b2..ceb168cd3b81412155eef93d346f465120d03188 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -337,7 +337,7 @@ #define LPCR_DPFD_SH 52 #define LPCR_DPFD (ASM_CONST(7) << LPCR_DPFD_SH) #define LPCR_VRMASD_SH 47 -#define LPCR_VRMASD (ASM_CONST(1) << LPCR_VRMASD_SH) +#define LPCR_VRMASD (ASM_CONST(0x1f) << LPCR_VRMASD_SH) #define LPCR_VRMA_L ASM_CONST(0x0008000000000000) #define LPCR_VRMA_LP0 ASM_CONST(0x0001000000000000) #define LPCR_VRMA_LP1 ASM_CONST(0x0000800000000000) @@ -1283,7 +1283,7 @@ static inline void msr_check_and_clear(unsigned long bits) " .llong 0\n" \ ".previous" \ : "=r" (rval) \ - : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL)); \ + : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \ rval;}) #else #define mftb() ({unsigned long rval; \ diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h index 1672e3398270bf50a740895c6ad534689eb84cf5..e78550f71833640abafb589da666b57325a51aa9 100644 --- a/arch/powerpc/include/uapi/asm/socket.h +++ b/arch/powerpc/include/uapi/asm/socket.h @@ -97,4 +97,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 1925341dbb9c9df7ceb05975cf95c0ff8a3339a5..adb52d101133d856baf21d241b3f01cb1ab254e9 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -15,7 +15,7 @@ CFLAGS_btext.o += -fPIC endif CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) -CFLAGS_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index b2da7c8baed7ede69a12ccbfe5be063b34c6bd14..292458b694fbedefc9bd953d3162a9b36dd4927c 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -235,6 +235,28 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr) #define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz)) +#define __get_user_or_set_dar(_regs, _dest, _addr) \ + ({ \ + int rc = 0; \ + typeof(_addr) __addr = (_addr); \ + if (__get_user_inatomic(_dest, __addr)) { \ + _regs->dar = (unsigned long)__addr; \ + rc = -EFAULT; \ + } \ + rc; \ + }) + +#define __put_user_or_set_dar(_regs, _src, _addr) \ + ({ \ + int rc = 0; \ + typeof(_addr) __addr = (_addr); \ + if (__put_user_inatomic(_src, __addr)) { \ + _regs->dar = (unsigned long)__addr; \ + rc = -EFAULT; \ + } \ + rc; \ + }) + static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, unsigned int reg, unsigned int nb, unsigned int flags, unsigned int instr, @@ -263,9 +285,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, } else { unsigned long pc = regs->nip ^ (swiz & 4); - if (__get_user_inatomic(instr, - (unsigned int __user *)pc)) + if (__get_user_or_set_dar(regs, instr, + (unsigned int __user *)pc)) return -EFAULT; + if (swiz == 0 && (flags & SW)) instr = cpu_to_le32(instr); nb = (instr >> 11) & 0x1f; @@ -309,31 +332,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, ((nb0 + 3) / 4) * sizeof(unsigned long)); for (i = 0; i < nb; ++i, ++p) - if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz), - SWIZ_PTR(p))) + if (__get_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; for (i = 0; i < nb0; ++i, ++p) - if (__get_user_inatomic(REG_BYTE(rptr, - i ^ bswiz), - SWIZ_PTR(p))) + if (__get_user_or_set_dar(regs, + REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } else { for (i = 0; i < nb; ++i, ++p) - if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz), - SWIZ_PTR(p))) + if (__put_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; for (i = 0; i < nb0; ++i, ++p) - if (__put_user_inatomic(REG_BYTE(rptr, - i ^ bswiz), - SWIZ_PTR(p))) + if (__put_user_or_set_dar(regs, + REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } @@ -345,29 +368,32 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, * Only POWER6 has these instructions, and it does true little-endian, * so we don't need the address swizzling. */ -static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, - unsigned int flags) +static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr, + unsigned int reg, unsigned int flags) { char *ptr0 = (char *) ¤t->thread.TS_FPR(reg); char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); - int i, ret, sw = 0; + int i, sw = 0; if (reg & 1) return 0; /* invalid form: FRS/FRT must be even */ if (flags & SW) sw = 7; - ret = 0; + for (i = 0; i < 8; ++i) { if (!(flags & ST)) { - ret |= __get_user(ptr0[i^sw], addr + i); - ret |= __get_user(ptr1[i^sw], addr + i + 8); + if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } else { - ret |= __put_user(ptr0[i^sw], addr + i); - ret |= __put_user(ptr1[i^sw], addr + i + 8); + if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } } - if (ret) - return -EFAULT; + return 1; /* exception handled and fixed up */ } @@ -377,24 +403,27 @@ static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr, { char *ptr0 = (char *)®s->gpr[reg]; char *ptr1 = (char *)®s->gpr[reg+1]; - int i, ret, sw = 0; + int i, sw = 0; if (reg & 1) return 0; /* invalid form: GPR must be even */ if (flags & SW) sw = 7; - ret = 0; + for (i = 0; i < 8; ++i) { if (!(flags & ST)) { - ret |= __get_user(ptr0[i^sw], addr + i); - ret |= __get_user(ptr1[i^sw], addr + i + 8); + if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } else { - ret |= __put_user(ptr0[i^sw], addr + i); - ret |= __put_user(ptr1[i^sw], addr + i + 8); + if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i)) + return -EFAULT; + if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8)) + return -EFAULT; } } - if (ret) - return -EFAULT; + return 1; /* exception handled and fixed up */ } #endif /* CONFIG_PPC64 */ @@ -687,9 +716,14 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg, for (j = 0; j < length; j += elsize) { for (i = 0; i < elsize; ++i) { if (flags & ST) - ret |= __put_user(ptr[i^sw], addr + i); + ret = __put_user_or_set_dar(regs, ptr[i^sw], + addr + i); else - ret |= __get_user(ptr[i^sw], addr + i); + ret = __get_user_or_set_dar(regs, ptr[i^sw], + addr + i); + + if (ret) + return ret; } ptr += elsize; #ifdef __LITTLE_ENDIAN__ @@ -739,7 +773,7 @@ int fix_alignment(struct pt_regs *regs) unsigned int dsisr; unsigned char __user *addr; unsigned long p, swiz; - int ret, i; + int i; union data { u64 ll; double dd; @@ -936,7 +970,7 @@ int fix_alignment(struct pt_regs *regs) if (flags & F) { /* Special case for 16-byte FP loads and stores */ PPC_WARN_ALIGNMENT(fp_pair, regs); - return emulate_fp_pair(addr, reg, flags); + return emulate_fp_pair(regs, addr, reg, flags); } else { #ifdef CONFIG_PPC64 /* Special case for 16-byte loads and stores */ @@ -966,15 +1000,12 @@ int fix_alignment(struct pt_regs *regs) } data.ll = 0; - ret = 0; p = (unsigned long)addr; for (i = 0; i < nb; i++) - ret |= __get_user_inatomic(data.v[start + i], - SWIZ_PTR(p++)); - - if (unlikely(ret)) - return -EFAULT; + if (__get_user_or_set_dar(regs, data.v[start + i], + SWIZ_PTR(p++))) + return -EFAULT; } else if (flags & F) { data.ll = current->thread.TS_FPR(reg); @@ -1046,15 +1077,13 @@ int fix_alignment(struct pt_regs *regs) break; } - ret = 0; p = (unsigned long)addr; for (i = 0; i < nb; i++) - ret |= __put_user_inatomic(data.v[start + i], - SWIZ_PTR(p++)); + if (__put_user_or_set_dar(regs, data.v[start + i], + SWIZ_PTR(p++))) + return -EFAULT; - if (unlikely(ret)) - return -EFAULT; } else if (flags & F) current->thread.TS_FPR(reg) = data.ll; else diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 7803756998e214f14eae5b07bd45cd84287fa068..9e05c8828ee218705f6fe508d5396e44a983a24f 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -97,6 +97,7 @@ _GLOBAL(__setup_cpu_power9) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PID,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) or r3, r3, r4 @@ -119,6 +120,7 @@ _GLOBAL(__restore_cpu_power9) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PID,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) or r3, r3, r4 diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index f25731627d7f472a44e25bf48e61cffcc2c51055..e5bfbf62827ad544cee160ed6b3991b7eaedb913 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -298,9 +298,17 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) * * For pHyp, we have to enable IO for log retrieval. Otherwise, * 0xFF's is always returned from PCI config space. + * + * When the @severity is EEH_LOG_PERM, the PE is going to be + * removed. Prior to that, the drivers for devices included in + * the PE will be closed. The drivers rely on working IO path + * to bring the devices to quiet state. Otherwise, PCI traffic + * from those devices after they are removed is like to cause + * another unexpected EEH error. */ if (!(pe->type & EEH_PE_PHB)) { - if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG)) + if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG) || + severity == EEH_LOG_PERM) eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); /* diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index a5dd493670a063c8bce09a4cadf618e1228a3115..6ef8f0bceacda49b6eed7e2102bf99ef23807906 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -724,7 +724,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus, */ #define MAX_WAIT_FOR_RECOVERY 300 -static void eeh_handle_normal_event(struct eeh_pe *pe) +static bool eeh_handle_normal_event(struct eeh_pe *pe) { struct pci_bus *frozen_bus; struct eeh_dev *edev, *tmp; @@ -736,7 +736,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) if (!frozen_bus) { pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n", __func__, pe->phb->global_number, pe->addr); - return; + return false; } eeh_pe_update_time_stamp(pe); @@ -870,7 +870,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) pr_info("EEH: Notify device driver to resume\n"); eeh_pe_dev_traverse(pe, eeh_report_resume, NULL); - return; + return false; excess_failures: /* @@ -915,8 +915,12 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) pci_lock_rescan_remove(); pci_hp_remove_devices(frozen_bus); pci_unlock_rescan_remove(); + + /* The passed PE should no longer be used */ + return true; } } + return false; } static void eeh_handle_special_event(void) @@ -982,7 +986,14 @@ static void eeh_handle_special_event(void) */ if (rc == EEH_NEXT_ERR_FROZEN_PE || rc == EEH_NEXT_ERR_FENCED_PHB) { - eeh_handle_normal_event(pe); + /* + * eeh_handle_normal_event() can make the PE stale if it + * determines that the PE cannot possibly be recovered. + * Don't modify the PE state if that's the case. + */ + if (eeh_handle_normal_event(pe)) + continue; + eeh_pe_state_clear(pe, EEH_PE_RECOVERING); } else { pci_lock_rescan_remove(); diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 767ef6d68c9ebf379dad6f065bcc0279a3021bb9..caa6596715990e3e9ad0cb577859c36e503f948c 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -1235,10 +1235,14 @@ _GLOBAL(ftrace_caller) stdu r1,-SWITCH_FRAME_SIZE(r1) /* Save all gprs to pt_regs */ - SAVE_8GPRS(0,r1) - SAVE_8GPRS(8,r1) - SAVE_8GPRS(16,r1) - SAVE_8GPRS(24,r1) + SAVE_GPR(0, r1) + SAVE_10GPRS(2, r1) + SAVE_10GPRS(12, r1) + SAVE_10GPRS(22, r1) + + /* Save previous stack pointer (r1) */ + addi r8, r1, SWITCH_FRAME_SIZE + std r8, GPR1(r1) /* Load special regs for save below */ mfmsr r8 @@ -1292,10 +1296,10 @@ ftrace_call: #endif /* Restore gprs */ - REST_8GPRS(0,r1) - REST_8GPRS(8,r1) - REST_8GPRS(16,r1) - REST_8GPRS(24,r1) + REST_GPR(0,r1) + REST_10GPRS(2,r1) + REST_10GPRS(12,r1) + REST_10GPRS(22,r1) /* Restore callee's TOC */ ld r2, 24(r1) diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 38a1f96430e10499dd465c98f426a7d970a38271..ca03eb229a9af01706ba92cc9decbc2640f68efb 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -735,8 +735,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) andis. r15,r14,(DBSR_IC|DBSR_BT)@h beq+ 1f +#ifdef CONFIG_RELOCATABLE + ld r15,PACATOC(r13) + ld r14,interrupt_base_book3e@got(r15) + ld r15,__end_interrupts@got(r15) +#else LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) LOAD_REG_IMMEDIATE(r15,__end_interrupts) +#endif cmpld cr0,r10,r14 cmpld cr1,r10,r15 blt+ cr0,1f @@ -799,8 +805,14 @@ kernel_dbg_exc: andis. r15,r14,(DBSR_IC|DBSR_BT)@h beq+ 1f +#ifdef CONFIG_RELOCATABLE + ld r15,PACATOC(r13) + ld r14,interrupt_base_book3e@got(r15) + ld r15,__end_interrupts@got(r15) +#else LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) LOAD_REG_IMMEDIATE(r15,__end_interrupts) +#endif cmpld cr0,r10,r14 cmpld cr1,r10,r15 blt+ cr0,1f diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 1ba82ea9023093ae3d58eedba4b9542bae137047..fd68e19b9ef7a7219d239149f884c01698b4082b 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -764,7 +764,29 @@ EXC_REAL(program_check, 0x700, 0x800) EXC_VIRT(program_check, 0x4700, 0x4800, 0x700) TRAMP_KVM(PACA_EXGEN, 0x700) EXC_COMMON_BEGIN(program_check_common) - EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) + /* + * It's possible to receive a TM Bad Thing type program check with + * userspace register values (in particular r1), but with SRR1 reporting + * that we came from the kernel. Normally that would confuse the bad + * stack logic, and we would report a bad kernel stack pointer. Instead + * we switch to the emergency stack if we're taking a TM Bad Thing from + * the kernel. + */ + li r10,MSR_PR /* Build a mask of MSR_PR .. */ + oris r10,r10,0x200000@h /* .. and SRR1_PROGTM */ + and r10,r10,r12 /* Mask SRR1 with that. */ + srdi r10,r10,8 /* Shift it so we can compare */ + cmpldi r10,(0x200000 >> 8) /* .. with an immediate. */ + bne 1f /* If != go to normal path. */ + + /* SRR1 had PR=0 and SRR1_PROGTM=1, so use the emergency stack */ + andi. r10,r12,MSR_PR; /* Set CR0 correctly for label */ + /* 3 in EXCEPTION_PROLOG_COMMON */ + mr r10,r1 /* Save r1 */ + ld r1,PACAEMERGSP(r13) /* Use emergency stack */ + subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ + b 3f /* Jump into the macro !! */ +1: EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) bl save_nvgprs RECONCILE_IRQ_STATE(r10, r11) addi r3,r1,STACK_FRAME_OVERHEAD @@ -1411,10 +1433,8 @@ USE_TEXT_SECTION() .align 7 do_hash_page: #ifdef CONFIG_PPC_STD_MMU_64 - andis. r0,r4,0xa410 /* weird error? */ + andis. r0,r4,0xa450 /* weird error? */ bne- handle_page_fault /* if not, try to insert a HPTE */ - andis. r0,r4,DSISR_DABRMATCH@h - bne- handle_dabr_fault CURRENT_THREAD_INFO(r11, r1) lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */ @@ -1438,11 +1458,16 @@ do_hash_page: /* Error */ blt- 13f + + /* Reload DSISR into r4 for the DABR check below */ + ld r4,_DSISR(r1) #endif /* CONFIG_PPC_STD_MMU_64 */ /* Here we have a page fault that hash_page can't handle. */ handle_page_fault: -11: ld r4,_DAR(r1) +11: andis. r0,r4,DSISR_DABRMATCH@h + bne- handle_dabr_fault + ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD bl do_page_fault diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 3c05c311e35e6aba3e8ad6c1f083d7aef57ec3d8..028a22bfa90c2e6f5685b887e89e5ff099ef4a42 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -146,6 +146,19 @@ notrace unsigned int __check_irq_replay(void) /* Clear bit 0 which we wouldn't clear otherwise */ local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; + if (happened & PACA_IRQ_HARD_DIS) { + /* + * We may have missed a decrementer interrupt if hard disabled. + * Check the decrementer register in case we had a rollover + * while hard disabled. + */ + if (!(happened & PACA_IRQ_DEC)) { + if (decrementer_check_overflow()) { + local_paca->irq_happened |= PACA_IRQ_DEC; + happened |= PACA_IRQ_DEC; + } + } + } /* * Force the delivery of pending soft-disabled interrupts on PS3. @@ -171,7 +184,7 @@ notrace unsigned int __check_irq_replay(void) * in case we also had a rollover while hard disabled */ local_paca->irq_happened &= ~PACA_IRQ_DEC; - if ((happened & PACA_IRQ_DEC) || decrementer_check_overflow()) + if (happened & PACA_IRQ_DEC) return 0x900; /* Finally check if an external interrupt happened */ diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index e785cc9e1ecd8bb0e442168412278bdbcf70afdd..fe97cbe04576e98e2652a2d50bf086b43d27ebf0 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -511,6 +511,15 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc); #endif + /* + * jprobes use jprobe_return() which skips the normal return + * path of the function, and this messes up the accounting of the + * function graph tracer. + * + * Pause function graph tracing while performing the jprobe function. + */ + pause_graph_tracing(); + return 1; } @@ -533,6 +542,8 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) * saved regs... */ memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); + /* It's OK to start function graph tracing again */ + unpause_graph_tracing(); preempt_enable_no_resched(); return 1; } diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index 5e7ece0fda9f5b802eb561ce51774cfb625032a6..ea236bfd841f66dbeea6a64bb1b840964cbc2fc9 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -205,6 +205,8 @@ static void machine_check_process_queued_event(struct irq_work *work) { int index; + add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); + /* * For now just print it to console. * TODO: log this error event to FSP or nvram. diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 34d2c595de23baff57351bbed16764c699d55800..73622673eee32bbf617ab947efe44f783e8c2b78 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -561,6 +561,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, static struct pstore_info nvram_pstore_info = { .owner = THIS_MODULE, .name = "nvram", + .flags = PSTORE_FLAGS_DMESG, .open = nvram_pstore_open, .read = nvram_pstore_read, .write = nvram_pstore_write, diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 49a680d5ae3740041b8819095d3815dda4930417..1c141d50fbc6a990ae4f2ce1f8028b5fb0a3ef51 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -359,7 +359,8 @@ void enable_kernel_vsx(void) cpumsr = msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX); - if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) { + if (current->thread.regs && + (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP))) { check_if_tm_restore_required(current); /* * If a thread has already been reclaimed then the @@ -383,7 +384,7 @@ void flush_vsx_to_thread(struct task_struct *tsk) { if (tsk->thread.regs) { preempt_disable(); - if (tsk->thread.regs->msr & MSR_VSX) { + if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) { BUG_ON(tsk != current); giveup_vsx(tsk); } @@ -839,6 +840,25 @@ static void tm_reclaim_thread(struct thread_struct *thr, if (!MSR_TM_SUSPENDED(mfmsr())) return; + /* + * If we are in a transaction and FP is off then we can't have + * used FP inside that transaction. Hence the checkpointed + * state is the same as the live state. We need to copy the + * live state to the checkpointed state so that when the + * transaction is restored, the checkpointed state is correct + * and the aborted transaction sees the correct state. We use + * ckpt_regs.msr here as that's what tm_reclaim will use to + * determine if it's going to write the checkpointed state or + * not. So either this will write the checkpointed registers, + * or reclaim will. Similarly for VMX. + */ + if ((thr->ckpt_regs.msr & MSR_FP) == 0) + memcpy(&thr->ckfp_state, &thr->fp_state, + sizeof(struct thread_fp_state)); + if ((thr->ckpt_regs.msr & MSR_VEC) == 0) + memcpy(&thr->ckvr_state, &thr->vr_state, + sizeof(struct thread_vr_state)); + giveup_all(container_of(thr, struct task_struct, thread)); tm_reclaim(thr, thr->ckpt_regs.msr, cause); @@ -1640,6 +1660,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) #ifdef CONFIG_VSX current->thread.used_vsr = 0; #endif + current->thread.load_fp = 0; memset(¤t->thread.fp_state, 0, sizeof(current->thread.fp_state)); current->thread.fp_save_area = NULL; #ifdef CONFIG_ALTIVEC @@ -1648,6 +1669,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) current->thread.vr_save_area = NULL; current->thread.vrsave = 0; current->thread.used_vr = 0; + current->thread.load_vec = 0; #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE memset(current->thread.evr, 0, sizeof(current->thread.evr)); @@ -1659,6 +1681,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) current->thread.tm_tfhar = 0; current->thread.tm_texasr = 0; current->thread.tm_tfiar = 0; + current->thread.load_tm = 0; #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ } EXPORT_SYMBOL(start_thread); diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 5c8f12fe9721d0945af35666348a26891c023a04..d97370866a5fa74bcd7c637e5158e67691475b86 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -127,12 +127,19 @@ static void flush_tmregs_to_thread(struct task_struct *tsk) * If task is not current, it will have been flushed already to * it's thread_struct during __switch_to(). * - * A reclaim flushes ALL the state. + * A reclaim flushes ALL the state or if not in TM save TM SPRs + * in the appropriate thread structures from live. */ - if (tsk == current && MSR_TM_SUSPENDED(mfmsr())) - tm_reclaim_current(TM_CAUSE_SIGNAL); + if ((!cpu_has_feature(CPU_FTR_TM)) || (tsk != current)) + return; + if (MSR_TM_SUSPENDED(mfmsr())) { + tm_reclaim_current(TM_CAUSE_SIGNAL); + } else { + tm_enable(); + tm_save_sprs(&(tsk->thread)); + } } #else static inline void flush_tmregs_to_thread(struct task_struct *tsk) { } diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index bbe77aed198d4899f12288f7675e880ae8e4a92e..3600c0d99ae94c283d33db6819d18af7a39f2d09 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -102,7 +102,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, static void do_signal(struct task_struct *tsk) { sigset_t *oldset = sigmask_to_save(); - struct ksignal ksig; + struct ksignal ksig = { .sig = 0 }; int ret; int is32 = is_32bit_task(); diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 96698fdf93b4ae27ac4161ea03f067d122f5fb17..04e92257fd69ec3a14e3c9b74ec4070b9bd0ce59 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -452,9 +452,20 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, if (MSR_TM_RESV(msr)) return -EINVAL; - /* pull in MSR TM from user context */ + /* pull in MSR TS bits from user context */ regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); + /* + * Ensure that TM is enabled in regs->msr before we leave the signal + * handler. It could be the case that (a) user disabled the TM bit + * through the manipulation of the MSR bits in uc_mcontext or (b) the + * TM bit was disabled because a sufficient number of context switches + * happened whilst in the signal handler and load_tm overflowed, + * disabling the TM bit. In either case we can end up with an illegal + * TM state leading to a TM Bad Thing when we return to userspace. + */ + regs->msr |= MSR_TM; + /* pull in MSR LE from user context */ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index bc3f7d0d7b7987dec3a74e4c59c2d133adb1330c..f1d7e996e67313c315a3acb980a92dc7178a19a0 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -407,6 +407,7 @@ void arch_vtime_task_switch(struct task_struct *prev) struct cpu_accounting_data *acct = get_accounting(current); acct->starttime = get_accounting(prev)->starttime; + acct->startspurr = get_accounting(prev)->startspurr; acct->system_time = 0; acct->user_time = 0; } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 023a462725b5dccf39ff51521118986f824afdbe..43021f8e47a64186138f5eea72834d6359644f2f 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -302,8 +302,6 @@ long machine_check_early(struct pt_regs *regs) __this_cpu_inc(irq_stat.mce_exceptions); - add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); - if (cur_cpu_spec && cur_cpu_spec->machine_check_early) handled = cur_cpu_spec->machine_check_early(regs); return handled; @@ -737,6 +735,8 @@ void machine_check_exception(struct pt_regs *regs) __this_cpu_inc(irq_stat.mce_exceptions); + add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); + /* See if any machine dependent calls. In theory, we would want * to call the CPU first, and call the ppc_md. one if the CPU * one returns a positive number. However there is existing code diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index c379ff5a4438d43af1837dd15629536be89c7105..da2a7eccb10a510f0da525218018e103a1a1a9f3 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -129,8 +129,11 @@ static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma) static int kvm_spapr_tce_release(struct inode *inode, struct file *filp) { struct kvmppc_spapr_tce_table *stt = filp->private_data; + struct kvm *kvm = stt->kvm; + mutex_lock(&kvm->lock); list_del_rcu(&stt->list); + mutex_unlock(&kvm->lock); kvm_put_kvm(stt->kvm); @@ -150,6 +153,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, struct kvm_create_spapr_tce_64 *args) { struct kvmppc_spapr_tce_table *stt = NULL; + struct kvmppc_spapr_tce_table *siter; unsigned long npages, size; int ret = -ENOMEM; int i; @@ -157,24 +161,16 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, if (!args->size) return -EINVAL; - /* Check this LIOBN hasn't been previously allocated */ - list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) { - if (stt->liobn == args->liobn) - return -EBUSY; - } - size = args->size; npages = kvmppc_tce_pages(size); ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true); - if (ret) { - stt = NULL; - goto fail; - } + if (ret) + return ret; stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *), GFP_KERNEL); if (!stt) - goto fail; + goto fail_acct; stt->liobn = args->liobn; stt->page_shift = args->page_shift; @@ -188,24 +184,39 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, goto fail; } - kvm_get_kvm(kvm); - mutex_lock(&kvm->lock); - list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables); + + /* Check this LIOBN hasn't been previously allocated */ + ret = 0; + list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) { + if (siter->liobn == args->liobn) { + ret = -EBUSY; + break; + } + } + + if (!ret) + ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops, + stt, O_RDWR | O_CLOEXEC); + + if (ret >= 0) { + list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables); + kvm_get_kvm(kvm); + } mutex_unlock(&kvm->lock); - return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops, - stt, O_RDWR | O_CLOEXEC); + if (ret >= 0) + return ret; -fail: - if (stt) { - for (i = 0; i < npages; i++) - if (stt->pages[i]) - __free_page(stt->pages[i]); + fail: + for (i = 0; i < npages; i++) + if (stt->pages[i]) + __free_page(stt->pages[i]); - kfree(stt); - } + kfree(stt); + fail_acct: + kvmppc_account_memlimit(kvmppc_stt_pages(npages), false); return ret; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 094deb60c6fe0ab0ce035ed5ceb8799846b26d5d..218cba2f56999aae0989ef0561cabe387dc585f6 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2807,12 +2807,38 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) { int r; int srcu_idx; + unsigned long ebb_regs[3] = {}; /* shut up GCC */ + unsigned long user_tar = 0; + unsigned int user_vrsave; if (!vcpu->arch.sane) { run->exit_reason = KVM_EXIT_INTERNAL_ERROR; return -EINVAL; } + /* + * Don't allow entry with a suspended transaction, because + * the guest entry/exit code will lose it. + * If the guest has TM enabled, save away their TM-related SPRs + * (they will get restored by the TM unavailable interrupt). + */ +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + if (cpu_has_feature(CPU_FTR_TM) && current->thread.regs && + (current->thread.regs->msr & MSR_TM)) { + if (MSR_TM_ACTIVE(current->thread.regs->msr)) { + run->exit_reason = KVM_EXIT_FAIL_ENTRY; + run->fail_entry.hardware_entry_failure_reason = 0; + return -EINVAL; + } + /* Enable TM so we can read the TM SPRs */ + mtmsr(mfmsr() | MSR_TM); + current->thread.tm_tfhar = mfspr(SPRN_TFHAR); + current->thread.tm_tfiar = mfspr(SPRN_TFIAR); + current->thread.tm_texasr = mfspr(SPRN_TEXASR); + current->thread.regs->msr &= ~MSR_TM; + } +#endif + kvmppc_core_prepare_to_enter(vcpu); /* No need to go into the guest when all we'll do is come back out */ @@ -2834,6 +2860,15 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) flush_all_to_thread(current); + /* Save userspace EBB and other register values */ + if (cpu_has_feature(CPU_FTR_ARCH_207S)) { + ebb_regs[0] = mfspr(SPRN_EBBHR); + ebb_regs[1] = mfspr(SPRN_EBBRR); + ebb_regs[2] = mfspr(SPRN_BESCR); + user_tar = mfspr(SPRN_TAR); + } + user_vrsave = mfspr(SPRN_VRSAVE); + vcpu->arch.wqp = &vcpu->arch.vcore->wq; vcpu->arch.pgdir = current->mm->pgd; vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST; @@ -2856,6 +2891,16 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu) r = kvmppc_xics_rm_complete(vcpu, 0); } while (is_kvmppc_resume_guest(r)); + /* Restore userspace EBB and other register values */ + if (cpu_has_feature(CPU_FTR_ARCH_207S)) { + mtspr(SPRN_EBBHR, ebb_regs[0]); + mtspr(SPRN_EBBRR, ebb_regs[1]); + mtspr(SPRN_BESCR, ebb_regs[2]); + mtspr(SPRN_TAR, user_tar); + mtspr(SPRN_FSCR, current->thread.fscr); + } + mtspr(SPRN_VRSAVE, user_vrsave); + out: vcpu->arch.state = KVMPPC_VCPU_NOTREADY; atomic_dec(&vcpu->kvm->arch.vcpus_running); diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 0c84d6bc835646c69ddfbe01efc4a690ad3b156e..7e2af42678a067d683b1141f5a099ad0ffedbb7c 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -97,7 +97,8 @@ void __init kvm_cma_reserve(void) (unsigned long)selected_size / SZ_1M); align_size = HPT_ALIGN_PAGES << PAGE_SHIFT; cma_declare_contiguous(0, selected_size, 0, align_size, - KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, false, &kvm_cma); + KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, false, "kvm_cma", + &kvm_cma); } } diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index a0ea63ac2b521b6f8a861aa4b211c0c08dd1062f..a8e3498a853f600ca1c6a46ae15e74e9bd30c09a 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c @@ -376,6 +376,7 @@ static void icp_rm_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, */ if (reject && reject != XICS_IPI) { arch_spin_unlock(&ics->lock); + icp->n_reject++; new_irq = reject; goto again; } @@ -707,10 +708,8 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) state = &ics->irq_state[src]; /* Still asserted, resend it */ - if (state->asserted) { - icp->n_reject++; + if (state->asserted) icp_rm_deliver_irq(xics, icp, irq); - } if (!hlist_empty(&vcpu->kvm->irq_ack_notifier_list)) { icp->rm_action |= XICS_RM_NOTIFY_EOI; diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 6f81adb112f1bf52543cd936b8992b9a98cfde00..0447a22a4df669decea975c09954bdfef6b20386 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -37,6 +37,13 @@ #define NAPPING_CEDE 1 #define NAPPING_NOVCPU 2 +/* Stack frame offsets for kvmppc_hv_entry */ +#define SFS 112 +#define STACK_SLOT_TRAP (SFS-4) +#define STACK_SLOT_CIABR (SFS-16) +#define STACK_SLOT_DAWR (SFS-24) +#define STACK_SLOT_DAWRX (SFS-32) + /* * Call kvmppc_hv_entry in real mode. * Must be called with interrupts hard-disabled. @@ -289,10 +296,10 @@ kvm_novcpu_exit: bl kvmhv_accumulate_time #endif 13: mr r3, r12 - stw r12, 112-4(r1) + stw r12, STACK_SLOT_TRAP(r1) bl kvmhv_commence_exit nop - lwz r12, 112-4(r1) + lwz r12, STACK_SLOT_TRAP(r1) b kvmhv_switch_to_host /* @@ -537,7 +544,7 @@ kvmppc_hv_entry: */ mflr r0 std r0, PPC_LR_STKOFF(r1) - stdu r1, -112(r1) + stdu r1, -SFS(r1) /* Save R1 in the PACA */ std r1, HSTATE_HOST_R1(r13) @@ -698,6 +705,16 @@ kvmppc_got_guest: mtspr SPRN_PURR,r7 mtspr SPRN_SPURR,r8 + /* Save host values of some registers */ +BEGIN_FTR_SECTION + mfspr r5, SPRN_CIABR + mfspr r6, SPRN_DAWR + mfspr r7, SPRN_DAWRX + std r5, STACK_SLOT_CIABR(r1) + std r6, STACK_SLOT_DAWR(r1) + std r7, STACK_SLOT_DAWRX(r1) +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + BEGIN_FTR_SECTION /* Set partition DABR */ /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */ @@ -1361,8 +1378,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) */ li r0, 0 mtspr SPRN_IAMR, r0 - mtspr SPRN_CIABR, r0 - mtspr SPRN_DAWRX, r0 + mtspr SPRN_PSPB, r0 mtspr SPRN_TCSCR, r0 mtspr SPRN_WORT, r0 /* Set MMCRS to 1<<31 to freeze and disable the SPMC counters */ @@ -1378,6 +1394,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) std r6,VCPU_UAMOR(r9) li r6,0 mtspr SPRN_AMR,r6 + mtspr SPRN_UAMOR, r6 /* Switch DSCR back to host value */ mfspr r8, SPRN_DSCR @@ -1519,6 +1536,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) slbia ptesync + /* Restore host values of some registers */ +BEGIN_FTR_SECTION + ld r5, STACK_SLOT_CIABR(r1) + ld r6, STACK_SLOT_DAWR(r1) + ld r7, STACK_SLOT_DAWRX(r1) + mtspr SPRN_CIABR, r5 + mtspr SPRN_DAWR, r6 + mtspr SPRN_DAWRX, r7 +END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + /* * POWER7/POWER8 guest -> host partition switch code. * We don't have to lock against tlbies but we do @@ -1652,8 +1679,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) li r0, KVM_GUEST_MODE_NONE stb r0, HSTATE_IN_GUEST(r13) - ld r0, 112+PPC_LR_STKOFF(r1) - addi r1, r1, 112 + ld r0, SFS+PPC_LR_STKOFF(r1) + addi r1, r1, SFS mtlr r0 blr diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 70963c845e968e3feed8d5942e72f0329e34a2e4..fc0df0f6fe881e2726daab5ab12d16fc88abdff5 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -601,8 +601,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif case KVM_CAP_PPC_HTM: - r = cpu_has_feature(CPU_FTR_TM_COMP) && - is_kvmppc_hv_enabled(kvm); + r = cpu_has_feature(CPU_FTR_TM_COMP) && hv_enabled; break; default: r = 0; diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 6ca3b902f7b9b21aefeda661d9586d892e7a5e16..776c1a1f9bc2bc29211ddaee44724a4d69818cbe 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -687,8 +687,10 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs, case 19: switch ((instr >> 1) & 0x3ff) { case 0: /* mcrf */ - rd = (instr >> 21) & 0x1c; - ra = (instr >> 16) & 0x1c; + rd = 7 - ((instr >> 23) & 0x7); + ra = 7 - ((instr >> 18) & 0x7); + rd *= 4; + ra *= 4; val = (regs->ccr >> ra) & 0xf; regs->ccr = (regs->ccr & ~(0xfUL << rd)) | (val << rd); goto instr_done; @@ -968,6 +970,19 @@ int __kprobes analyse_instr(struct instruction_op *op, struct pt_regs *regs, #endif case 19: /* mfcr */ + if ((instr >> 20) & 1) { + imm = 0xf0000000UL; + for (sh = 0; sh < 8; ++sh) { + if (instr & (0x80000 >> sh)) { + regs->gpr[rd] = regs->ccr & imm; + break; + } + imm >>= 4; + } + + goto instr_done; + } + regs->gpr[rd] = regs->ccr; regs->gpr[rd] &= 0xffffffffUL; goto instr_done; diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 78dabf065ba96eb755267b9099e50dd6f024653d..bd666287c5eda1f9ef6c28607a33cb99fa1ee27b 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -747,7 +747,7 @@ static unsigned long __init htab_get_table_size(void) } #ifdef CONFIG_MEMORY_HOTPLUG -int create_section_mapping(unsigned long start, unsigned long end) +int hash__create_section_mapping(unsigned long start, unsigned long end) { int rc = htab_bolt_mapping(start, end, __pa(start), pgprot_val(PAGE_KERNEL), mmu_linear_psize, @@ -761,7 +761,7 @@ int create_section_mapping(unsigned long start, unsigned long end) return rc; } -int remove_section_mapping(unsigned long start, unsigned long end) +int hash__remove_section_mapping(unsigned long start, unsigned long end) { int rc = htab_remove_mapping(start, end, mmu_linear_psize, mmu_kernel_ssize); diff --git a/arch/powerpc/mm/hugetlbpage-radix.c b/arch/powerpc/mm/hugetlbpage-radix.c index 35254a6784561b6f5f70399822cb163f8e59b14d..a2b2d97f7edacf7ed8bfbc591323d25572f41bb4 100644 --- a/arch/powerpc/mm/hugetlbpage-radix.c +++ b/arch/powerpc/mm/hugetlbpage-radix.c @@ -65,7 +65,7 @@ radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } /* diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index d5ce34dcf4d9a8c2420df31eba81563e7c3af4b2..1e28747d677f89a462f4d80a7affd056b0489534 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include @@ -421,6 +423,28 @@ static int __init parse_disable_radix(char *p) } early_param("disable_radix", parse_disable_radix); +/* + * If we're running under a hypervisor, we currently can't do radix + * since we don't have the code to do the H_REGISTER_PROC_TBL hcall. + * We tell that we're running under a hypervisor by looking for the + * /chosen/ibm,architecture-vec-5 property. + */ +static void early_check_vec5(void) +{ + unsigned long root, chosen; + int size; + const u8 *vec5; + + root = of_get_flat_dt_root(); + chosen = of_get_flat_dt_subnode_by_name(root, "chosen"); + if (chosen == -FDT_ERR_NOTFOUND) + return; + vec5 = of_get_flat_dt_prop(chosen, "ibm,architecture-vec-5", &size); + if (!vec5) + return; + cur_cpu_spec->mmu_features &= ~MMU_FTR_TYPE_RADIX; +} + void __init mmu_early_init_devtree(void) { /* Disable radix mode based on kernel command line. */ @@ -428,6 +452,15 @@ void __init mmu_early_init_devtree(void) if (disable_radix || !(mfmsr() & MSR_HV)) cur_cpu_spec->mmu_features &= ~MMU_FTR_TYPE_RADIX; + /* + * Check /chosen/ibm,architecture-vec-5 if running as a guest. + * When running bare-metal, we can use radix if we like + * even though the ibm,architecture-vec-5 property created by + * skiboot doesn't have the necessary bits set. + */ + if (early_radix_enabled() && !(mfmsr() & MSR_HV)) + early_check_vec5(); + if (early_radix_enabled()) radix__early_init_devtree(); else diff --git a/arch/powerpc/mm/mmap.c b/arch/powerpc/mm/mmap.c index 2f1e44362198d3f16d85fdd4656d37e618b51824..5bc2845cddf416711ad2e038bcf469cf2491d0a1 100644 --- a/arch/powerpc/mm/mmap.c +++ b/arch/powerpc/mm/mmap.c @@ -106,7 +106,7 @@ radix__arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -142,7 +142,7 @@ radix__arch_get_unmapped_area_topdown(struct file *filp, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index 73bf6e14c3aa04c082921c3691c2cd48320c2892..a006f822b1540f0755de1bfdb3ef4e9e137eb6cc 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -167,9 +167,15 @@ void destroy_context(struct mm_struct *mm) mm->context.cop_lockp = NULL; #endif /* CONFIG_PPC_ICSWX */ - if (radix_enabled()) - process_tb[mm->context.id].prtb1 = 0; - else + if (radix_enabled()) { + /* + * Radix doesn't have a valid bit in the process table + * entries. However we know that at least P9 implementation + * will avoid caching an entry with an invalid RTS field, + * and 0 is invalid. So this will do. + */ + process_tb[mm->context.id].prtb0 = 0; + } else subpage_prot_free(mm); destroy_pagetable_page(mm); __destroy_context(mm->context.id); diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index 7de7124ac91bf939ef26aa9f25d5bd8f88d0f57e..fd596808ac24181efe2e3f96ecb6762778a7c2e9 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -81,7 +81,7 @@ struct page *new_iommu_non_cma_page(struct page *page, unsigned long private, gfp_t gfp_mask = GFP_USER; struct page *new_page; - if (PageHuge(page) || PageTransHuge(page) || PageCompound(page)) + if (PageCompound(page)) return NULL; if (PageHighMem(page)) @@ -100,7 +100,7 @@ static int mm_iommu_move_page_from_cma(struct page *page) LIST_HEAD(cma_migrate_pages); /* Ignore huge pages for now */ - if (PageHuge(page) || PageTransHuge(page) || PageCompound(page)) + if (PageCompound(page)) return -EBUSY; lru_add_drain(); diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c index f4f437cbabf1d44447094e40da48fec9e14eaadc..0fad7f6742ff5acfbb2e0508687a2c1b290958d8 100644 --- a/arch/powerpc/mm/pgtable-book3s64.c +++ b/arch/powerpc/mm/pgtable-book3s64.c @@ -125,3 +125,21 @@ void mmu_cleanup_all(void) else if (mmu_hash_ops.hpte_clear_all) mmu_hash_ops.hpte_clear_all(); } + +#ifdef CONFIG_MEMORY_HOTPLUG +int create_section_mapping(unsigned long start, unsigned long end) +{ + if (radix_enabled()) + return -ENODEV; + + return hash__create_section_mapping(start, end); +} + +int remove_section_mapping(unsigned long start, unsigned long end) +{ + if (radix_enabled()) + return -ENODEV; + + return hash__remove_section_mapping(start, end); +} +#endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c index 9a25dce878757517a5a79fcd9b04d280d02f72d6..44c33ee397a02b22d3d8c6f414072512aa821054 100644 --- a/arch/powerpc/mm/pgtable-radix.c +++ b/arch/powerpc/mm/pgtable-radix.c @@ -173,6 +173,10 @@ static void __init radix_init_pgtable(void) */ register_process_table(__pa(process_tb), 0, PRTB_SIZE_SHIFT - 12); pr_info("Process table %p and radix root for kernel: %p\n", process_tb, init_mm.pgd); + asm volatile("ptesync" : : : "memory"); + asm volatile(PPC_TLBIE_5(%0,%1,2,1,1) : : + "r" (TLBIEL_INVAL_SET_LPID), "r" (0)); + asm volatile("eieio; tlbsync; ptesync" : : : "memory"); } static void __init radix_init_partition_table(void) diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 2b27458902ee888d1ba3480191497c105a184e94..c4d5c9c61e0fc16847854015931be0807c80344e 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -105,7 +105,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr, if ((mm->task_size - len) < addr) return 0; vma = find_vma(mm, addr); - return (!vma || (addr + len) <= vma->vm_start); + return (!vma || (addr + len) <= vm_start_gap(vma)); } static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 72c27b8d2cf3240f201eabeb723afcdb0ff9b0de..083f927469513c9252bdd1bc6b4056c499f63240 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -401,8 +401,12 @@ static __u64 power_pmu_bhrb_to(u64 addr) int ret; __u64 target; - if (is_kernel_addr(addr)) - return branch_target((unsigned int *)addr); + if (is_kernel_addr(addr)) { + if (probe_kernel_read(&instr, (void *)addr, sizeof(instr))) + return 0; + + return branch_target(&instr); + } /* Userspace: need copy instruction here then translate it */ pagefault_disable(); diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index 7b2ca16b1eb4faf3a4488bd0ad8b4fb74318275a..991c6a517ddc17d78126229e6b86b353342432f3 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -516,7 +516,7 @@ static int memord(const void *d1, size_t s1, const void *d2, size_t s2) { if (s1 < s2) return 1; - if (s2 > s1) + if (s1 > s2) return -1; return memcmp(d1, d2, s1); diff --git a/arch/powerpc/perf/isa207-common.h b/arch/powerpc/perf/isa207-common.h index 4d0a4e5017c20377fc0ebd9e5bd286d6a26ee74b..8e6dd17fe603eb9ec24ba8f9703926e18fd303f7 100644 --- a/arch/powerpc/perf/isa207-common.h +++ b/arch/powerpc/perf/isa207-common.h @@ -201,6 +201,10 @@ CNST_PMC_VAL(1) | CNST_PMC_VAL(2) | CNST_PMC_VAL(3) | \ CNST_PMC_VAL(4) | CNST_PMC_VAL(5) | CNST_PMC_VAL(6) | CNST_NC_VAL +/* + * Lets restrict use of PMC5 for instruction counting. + */ +#define P9_DD1_TEST_ADDER (ISA207_TEST_ADDER | CNST_PMC_VAL(5)) /* Bits in MMCR1 for PowerISA v2.07 */ #define MMCR1_UNIT_SHIFT(pmc) (60 - (4 * ((pmc) - 1))) diff --git a/arch/powerpc/perf/perf_regs.c b/arch/powerpc/perf/perf_regs.c index d24a8a3668fac5bffcd9ca654d61b9cf356cbf9a..28ae8bd6228edc3d73bb9fd84125704b5087bbc4 100644 --- a/arch/powerpc/perf/perf_regs.c +++ b/arch/powerpc/perf/perf_regs.c @@ -100,5 +100,6 @@ void perf_get_regs_user(struct perf_regs *regs_user, struct pt_regs *regs_user_copy) { regs_user->regs = task_pt_regs(current); - regs_user->abi = perf_reg_abi(current); + regs_user->abi = (regs_user->regs) ? perf_reg_abi(current) : + PERF_SAMPLE_REGS_ABI_NONE; } diff --git a/arch/powerpc/perf/power9-pmu.c b/arch/powerpc/perf/power9-pmu.c index 8e9a81967ff8516b8c04d47e65df92c7daeeba1c..9abcd8f655042daf7356235fa7d252aec616fe7c 100644 --- a/arch/powerpc/perf/power9-pmu.c +++ b/arch/powerpc/perf/power9-pmu.c @@ -295,7 +295,7 @@ static struct power_pmu power9_pmu = { .name = "POWER9", .n_counter = MAX_PMU_COUNTERS, .add_fields = ISA207_ADD_FIELDS, - .test_adder = ISA207_TEST_ADDER, + .test_adder = P9_DD1_TEST_ADDER, .compute_mmcr = isa207_compute_mmcr, .config_bhrb = power9_config_bhrb, .bhrb_filter_map = power9_bhrb_filter_map, diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index e84d8fbc2e21ddbee1a73e1f87cf1f06cc9a11f7..378c37aa69143bd1c2f2a0895eba9151783c7a08 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -197,7 +197,9 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) (REGION_ID(ea) != USER_REGION_ID)) { spin_unlock(&spu->register_lock); - ret = hash_page(ea, _PAGE_PRESENT | _PAGE_READ, 0x300, dsisr); + ret = hash_page(ea, + _PAGE_PRESENT | _PAGE_READ | _PAGE_PRIVILEGED, + 0x300, dsisr); spin_lock(&spu->register_lock); if (!ret) { diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c index 83bebeec0fea58de5babedeceb8714e66fcec635..0f7b16e293478f3540d55a542b26bf83e1f17290 100644 --- a/arch/powerpc/platforms/powernv/opal-async.c +++ b/arch/powerpc/platforms/powernv/opal-async.c @@ -39,18 +39,18 @@ int __opal_async_get_token(void) int token; spin_lock_irqsave(&opal_async_comp_lock, flags); - token = find_first_bit(opal_async_complete_map, opal_max_async_tokens); + token = find_first_zero_bit(opal_async_token_map, opal_max_async_tokens); if (token >= opal_max_async_tokens) { token = -EBUSY; goto out; } - if (__test_and_set_bit(token, opal_async_token_map)) { + if (!__test_and_clear_bit(token, opal_async_complete_map)) { token = -EBUSY; goto out; } - __clear_bit(token, opal_async_complete_map); + __set_bit(token, opal_async_token_map); out: spin_unlock_irqrestore(&opal_async_comp_lock, flags); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index 44d2d842cee79009f012842dcfbda7a1896b00f4..483d8c05d11a2a561edaa2f6a6df16ce08ca82e2 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -146,7 +146,7 @@ opal_tracepoint_entry: opal_tracepoint_return: std r3,STK_REG(R31)(r1) mr r4,r3 - ld r0,STK_REG(R23)(r1) + ld r3,STK_REG(R23)(r1) bl __trace_opal_exit ld r3,STK_REG(R31)(r1) addi r1,r1,STACKFRAMESIZE diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index dcdfee0cd4f2f134f6fddeabe8130232bed4d9c6..f602307a438669236fcdb557b05078d431eecec9 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2623,6 +2623,9 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, level_shift = entries_shift + 3; level_shift = max_t(unsigned, level_shift, PAGE_SHIFT); + if ((level_shift - 3) * levels + page_shift >= 60) + return -EINVAL; + /* Allocate TCE table */ addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift, levels, tce_table_size, &offset, &total_allocated); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index efe8b6bb168b97961f3943f7e2038a9faae2f702..b33faa0015cca3655b72d9b8cc5548a255e23bc8 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -289,7 +289,7 @@ static unsigned long pnv_get_proc_freq(unsigned int cpu) { unsigned long ret_freq; - ret_freq = cpufreq_quick_get(cpu) * 1000ul; + ret_freq = cpufreq_get(cpu) * 1000ul; /* * If the backend cpufreq driver does not exist, diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 423e450efe07cbf9d442f039f7148337251f561b..72ae2cdbcd6a75e7b39592291e9d63c9a40c32f1 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -288,7 +288,6 @@ int dlpar_detach_node(struct device_node *dn) if (rc) return rc; - of_node_put(dn); /* Must decrement the refcount */ return 0; } diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 76ec104e88beea0e89e3473d988e23fbdb7312c1..c0a0947f43bbb71cdc8f5c09e4255659c9149679 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -124,6 +124,7 @@ static struct property *dlpar_clone_drconf_property(struct device_node *dn) for (i = 0; i < num_lmbs; i++) { lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr); lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index); + lmbs[i].aa_index = be32_to_cpu(lmbs[i].aa_index); lmbs[i].flags = be32_to_cpu(lmbs[i].flags); } @@ -147,6 +148,7 @@ static void dlpar_update_drconf_property(struct device_node *dn, for (i = 0; i < num_lmbs; i++) { lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr); lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index); + lmbs[i].aa_index = cpu_to_be32(lmbs[i].aa_index); lmbs[i].flags = cpu_to_be32(lmbs[i].flags); } diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index f2c98f6c1c9c93afec8a674f0e27c6a5e499767e..a7bb872a0dc487f867f4375fd826d844cb4d836e 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -279,7 +279,7 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, int ssize, unsigned long inv_flags) { unsigned long lpar_rc; - unsigned long flags = (newpp & 7) | H_AVPN; + unsigned long flags; unsigned long want_v; want_v = hpte_encode_avpn(vpn, psize, ssize); @@ -287,6 +287,11 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, pr_devel(" update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...", want_v, slot, flags, psize); + flags = (newpp & 7) | H_AVPN; + if (mmu_has_feature(MMU_FTR_KERNEL_RO)) + /* Move pp0 into bit 8 (IBM 55) */ + flags |= (newpp & HPTE_R_PP0) >> 55; + lpar_rc = plpar_pte_protect(flags, slot, want_v); if (lpar_rc == H_NOT_FOUND) { @@ -358,6 +363,10 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, BUG_ON(slot == -1); flags = newpp & 7; + if (mmu_has_feature(MMU_FTR_KERNEL_RO)) + /* Move pp0 into bit 8 (IBM 55) */ + flags |= (newpp & HPTE_R_PP0) >> 55; + lpar_rc = plpar_pte_protect(flags, slot, 0); BUG_ON(lpar_rc != H_SUCCESS); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index a560a98bcf3bc2552486b552ef8e8a887425f0ba..6a5e7467445c8ad09b387e49f93aeed5d088d33e 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -225,8 +225,10 @@ static int add_dt_node(__be32 parent_phandle, __be32 drc_index) return -ENOENT; dn = dlpar_configure_connector(drc_index, parent_dn); - if (!dn) + if (!dn) { + of_node_put(parent_dn); return -ENOENT; + } rc = dlpar_attach_node(dn); if (rc) diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index cc66c49f07aa1b8a6825382216efb38486665460..666ad0611e635789bafd0a84569577d5ba68290f 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -82,7 +82,6 @@ static int pSeries_reconfig_remove_node(struct device_node *np) of_detach_node(np); of_node_put(parent); - of_node_put(np); /* Must decrement the refcount */ return 0; } diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index ada29eaed6e280c08f6d3ee5671c58da9eb06e38..f523ac88315070873eede1c978312569d48953a7 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -274,7 +274,9 @@ static int axon_ram_probe(struct platform_device *device) if (bank->disk->major > 0) unregister_blkdev(bank->disk->major, bank->disk->disk_name); - del_gendisk(bank->disk); + if (bank->disk->flags & GENHD_FL_UP) + del_gendisk(bank->disk); + put_disk(bank->disk); } device->dev.platform_data = NULL; if (bank->io_addr != 0) @@ -299,6 +301,7 @@ axon_ram_remove(struct platform_device *device) device_remove_file(&device->dev, &dev_attr_ecc); free_irq(bank->irq_id, device); del_gendisk(bank->disk); + put_disk(bank->disk); iounmap((void __iomem *) bank->io_addr); kfree(bank); diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index f267ee0afc082068266d3032ff41d194523ccb5a..716353b247ded2be54856a309ff57a9de71f0bcc 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -845,12 +845,12 @@ void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq) u32 ipic_get_mcp_status(void) { - return ipic_read(primary_ipic->regs, IPIC_SERMR); + return ipic_read(primary_ipic->regs, IPIC_SERSR); } void ipic_clear_mcp_status(u32 mask) { - ipic_write(primary_ipic->regs, IPIC_SERMR, mask); + ipic_write(primary_ipic->regs, IPIC_SERSR, mask); } /* Return an interrupt vector or 0 if no interrupt is pending. */ diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c index ef470b470b04ae85488d1a9ffcbe27519884a4db..6afddae2fb4796dc61de3258f683bcc158b15a2e 100644 --- a/arch/powerpc/sysdev/simple_gpio.c +++ b/arch/powerpc/sysdev/simple_gpio.c @@ -75,7 +75,8 @@ static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) { - struct u8_gpio_chip *u8_gc = gpiochip_get_data(&mm_gc->gc); + struct u8_gpio_chip *u8_gc = + container_of(mm_gc, struct u8_gpio_chip, mm_gc); u8_gc->data = in_8(mm_gc->regs); } diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c index 32c46b424dd01b5f46020b71ab57e9fcd5b49571..b53f80f0b4d822b8ecc77271ee7ece8b734bee5a 100644 --- a/arch/powerpc/sysdev/xics/icp-opal.c +++ b/arch/powerpc/sysdev/xics/icp-opal.c @@ -130,14 +130,16 @@ static void icp_opal_cause_ipi(int cpu, unsigned long data) { int hw_cpu = get_hard_smp_processor_id(cpu); + kvmppc_set_host_ipi(cpu, 1); opal_int_set_mfrr(hw_cpu, IPI_PRIORITY); } static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id) { - int hw_cpu = hard_smp_processor_id(); + int cpu = smp_processor_id(); - opal_int_set_mfrr(hw_cpu, 0xff); + kvmppc_set_host_ipi(cpu, 0); + opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff); return smp_ipi_demux(); } diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 426481d4cc86d5f7703c731fa0bb5d6aafa6820e..9aa0d04c9dcc50f0618de6fc3a9dd1e3607d7510 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -359,9 +359,6 @@ config COMPAT config SYSVIPC_COMPAT def_bool y if COMPAT && SYSVIPC -config KEYS_COMPAT - def_bool y if COMPAT && KEYS - config SMP def_bool y prompt "Symmetric multi-processing support" diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 303d28eb03a2f697b5ceb18c25cf8a72df4caf4d..591cbdf615af046d4e0662241b03c3b113280333 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -501,6 +502,12 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, if (err) return err; + /* In fips mode only 128 bit or 256 bit keys are valid */ + if (fips_enabled && key_len != 32 && key_len != 64) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + /* Pick the correct function code based on the key length */ fc = (key_len == 32) ? CPACF_KM_XTS_128 : (key_len == 64) ? CPACF_KM_XTS_256 : 0; diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 1113389d0a39fe661229b68d28cf99e7a2e18eab..fe7368a41aa87cfcd109f093755242daf48bffa1 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] __initconst = { /*** helper functions ***/ +/* + * generate_entropy: + * This algorithm produces 64 bytes of entropy data based on 1024 + * individual stckf() invocations assuming that each stckf() value + * contributes 0.25 bits of entropy. So the caller gets 256 bit + * entropy per 64 byte or 4 bits entropy per byte. + */ static int generate_entropy(u8 *ebuf, size_t nbytes) { int n, ret = 0; - u8 *pg, *h, hash[32]; + u8 *pg, *h, hash[64]; - pg = (u8 *) __get_free_page(GFP_KERNEL); + /* allocate 2 pages */ + pg = (u8 *) __get_free_pages(GFP_KERNEL, 1); if (!pg) { prng_errorflag = PRNG_GEN_ENTROPY_FAILED; return -ENOMEM; } while (nbytes) { - /* fill page with urandom bytes */ - get_random_bytes(pg, PAGE_SIZE); - /* exor page with stckf values */ - for (n = 0; n < PAGE_SIZE / sizeof(u64); n++) { + /* fill pages with urandom bytes */ + get_random_bytes(pg, 2*PAGE_SIZE); + /* exor pages with 1024 stckf values */ + for (n = 0; n < 2 * PAGE_SIZE / sizeof(u64); n++) { u64 *p = ((u64 *)pg) + n; *p ^= get_tod_clock_fast(); } @@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) h = hash; else h = ebuf; - /* generate sha256 from this page */ - cpacf_kimd(CPACF_KIMD_SHA_256, h, pg, PAGE_SIZE); + /* hash over the filled pages */ + cpacf_kimd(CPACF_KIMD_SHA_512, h, pg, 2*PAGE_SIZE); if (n < sizeof(hash)) memcpy(ebuf, hash, n); ret += n; @@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) nbytes -= n; } - free_page((unsigned long)pg); + free_pages((unsigned long)pg, 1); return ret; } @@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(void) static int __init prng_sha512_instantiate(void) { int ret, datalen; - u8 seed[64]; + u8 seed[64 + 32 + 16]; pr_debug("prng runs in SHA-512 mode " "with chunksize=%d and reseed_limit=%u\n", @@ -357,12 +365,12 @@ static int __init prng_sha512_instantiate(void) if (ret) goto outfree; - /* generate initial seed bytestring, first 48 bytes of entropy */ - ret = generate_entropy(seed, 48); - if (ret != 48) + /* generate initial seed bytestring, with 256 + 128 bits entropy */ + ret = generate_entropy(seed, 64 + 32); + if (ret != 64 + 32) goto outfree; /* followed by 16 bytes of unique nonce */ - get_tod_clock_ext(seed + 48); + get_tod_clock_ext(seed + 64 + 32); /* initial seed of the ppno drng */ cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED, @@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(void) static int prng_sha512_reseed(void) { int ret; - u8 seed[32]; + u8 seed[64]; - /* generate 32 bytes of fresh entropy */ + /* fetch 256 bits of fresh entropy */ ret = generate_entropy(seed, sizeof(seed)); if (ret != sizeof(seed)) return ret; diff --git a/arch/s390/include/asm/asm-prototypes.h b/arch/s390/include/asm/asm-prototypes.h new file mode 100644 index 0000000000000000000000000000000000000000..2c3413b0ca52dba8f56e2dedf83c705dbcef5bcd --- /dev/null +++ b/arch/s390/include/asm/asm-prototypes.h @@ -0,0 +1,8 @@ +#ifndef _ASM_S390_PROTOTYPES_H + +#include +#include +#include +#include + +#endif /* _ASM_S390_PROTOTYPES_H */ diff --git a/arch/s390/include/asm/ctl_reg.h b/arch/s390/include/asm/ctl_reg.h index d7697ab802f6c94813a27394baa255fa26a93ddc..8e136b88cdf4f13460b960f8db9d02e1ae88324f 100644 --- a/arch/s390/include/asm/ctl_reg.h +++ b/arch/s390/include/asm/ctl_reg.h @@ -15,7 +15,9 @@ BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\ asm volatile( \ " lctlg %1,%2,%0\n" \ - : : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high));\ + : \ + : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high) \ + : "memory"); \ } #define __ctl_store(array, low, high) { \ diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 1736c7d3c94c7e3fe32a5a44c5f5ddb02dbaaa9f..8d665f1b29f8264ef68afde1753216b98a2bc62c 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -158,14 +158,13 @@ extern unsigned int vdso_enabled; #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE 4096 -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. 64-bit - tasks are aligned to 4GB. */ -#define ELF_ET_DYN_BASE (is_compat_task() ? \ - (STACK_TOP / 3 * 2) : \ - (STACK_TOP / 3 * 2) & ~((1UL << 32) - 1)) +/* + * This is the base location for PIE (ET_DYN with INTERP) loads. On + * 64-bit, this is raised to 4GB to leave the entire 32-bit address + * space open for things that want to use the area for 32-bit pointers. + */ +#define ELF_ET_DYN_BASE (is_compat_task() ? 0x000400000UL : \ + 0x100000000UL) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index bea785d7f853c12ddd35e7b5e7d6f3d76b87aca7..af85d6b120284e2ee674c082098470a787ca49a5 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -5,6 +5,7 @@ #include typedef struct { + spinlock_t lock; cpumask_t cpu_attach_mask; atomic_t flush_count; unsigned int flush_mm; @@ -25,6 +26,7 @@ typedef struct { } mm_context_t; #define INIT_MM_CONTEXT(name) \ + .context.lock = __SPIN_LOCK_UNLOCKED(name.context.lock), \ .context.pgtable_lock = \ __SPIN_LOCK_UNLOCKED(name.context.pgtable_lock), \ .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \ diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 515fea5a3fc4334b33111cdccfbb15a91f0c1c5b..f65a708ac395dc93cf4d5602f9c2f59007e4c7f0 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -15,6 +15,7 @@ static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { + spin_lock_init(&mm->context.lock); spin_lock_init(&mm->context.pgtable_lock); INIT_LIST_HEAD(&mm->context.pgtable_list); spin_lock_init(&mm->context.gmap_lock); @@ -93,7 +94,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if (prev == next) return; cpumask_set_cpu(cpu, &next->context.cpu_attach_mask); - cpumask_set_cpu(cpu, mm_cpumask(next)); /* Clear old ASCE by loading the kernel ASCE. */ __ctl_load(S390_lowcore.kernel_asce, 1, 1); __ctl_load(S390_lowcore.kernel_asce, 7, 7); @@ -111,9 +111,8 @@ static inline void finish_arch_post_lock_switch(void) preempt_disable(); while (atomic_read(&mm->context.flush_count)) cpu_relax(); - - if (mm->context.flush_mm) - __tlb_flush_mm(mm); + cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); + __tlb_flush_mm_lazy(mm); preempt_enable(); } set_fs(current->thread.mm_segment); @@ -126,6 +125,7 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) { switch_mm(prev, next, current); + cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); set_user_asce(next); } diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h index 649eb62c52b3784ec0214e47482b87442d3081dd..9e02cb7955c1b0812583948b55ad9ae13a646492 100644 --- a/arch/s390/include/asm/pci_insn.h +++ b/arch/s390/include/asm/pci_insn.h @@ -81,6 +81,6 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range); int zpci_load(u64 *data, u64 req, u64 offset); int zpci_store(u64 data, u64 req, u64 offset); int zpci_store_block(const u64 *data, u64 req, u64 offset); -void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc); +int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc); #endif diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0cea7026e4ffd558ea4fd3b41a8aeebb2a0f2860..db74d398a443eb092233b7113eb6f1335e35bde6 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -480,7 +480,7 @@ static inline int mm_alloc_pgste(struct mm_struct *mm) * In the case that a guest uses storage keys * faults should no longer be backed by zero pages */ -#define mm_forbids_zeropage mm_use_skey +#define mm_forbids_zeropage mm_has_pgste static inline int mm_use_skey(struct mm_struct *mm) { #ifdef CONFIG_PGSTE @@ -1359,7 +1359,9 @@ static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, static inline void pmdp_invalidate(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp) { - pmdp_xchg_direct(vma->vm_mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_INVALID)); + pmd_t pmd = __pmd(pmd_val(*pmdp) | _SEGMENT_ENTRY_INVALID); + + pmdp_xchg_direct(vma->vm_mm, addr, pmdp, pmd); } #define __HAVE_ARCH_PMDP_SET_WRPROTECT diff --git a/arch/s390/include/asm/runtime_instr.h b/arch/s390/include/asm/runtime_instr.h index 402ad6df4897123e0e0b1a0eb0ba81157cb9380b..c54a9310d81423a39d1c82451e381d909b540f33 100644 --- a/arch/s390/include/asm/runtime_instr.h +++ b/arch/s390/include/asm/runtime_instr.h @@ -85,6 +85,8 @@ static inline void restore_ri_cb(struct runtime_instr_cb *cb_next, load_runtime_instr_cb(&runtime_instr_empty_cb); } -void exit_thread_runtime_instr(void); +struct task_struct; + +void runtime_instr_release(struct task_struct *tsk); #endif /* _RUNTIME_INSTR_H */ diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h index 12d45f0cfdd931e3d8049c4333b1f359e3539443..ff2fbdafe6899fdee9f433f26dc7a4ce2ed407f6 100644 --- a/arch/s390/include/asm/switch_to.h +++ b/arch/s390/include/asm/switch_to.h @@ -29,17 +29,16 @@ static inline void restore_access_regs(unsigned int *acrs) } #define switch_to(prev,next,last) do { \ - if (prev->mm) { \ - save_fpu_regs(); \ - save_access_regs(&prev->thread.acrs[0]); \ - save_ri_cb(prev->thread.ri_cb); \ - } \ - if (next->mm) { \ - update_cr_regs(next); \ - set_cpu_flag(CIF_FPU); \ - restore_access_regs(&next->thread.acrs[0]); \ - restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ - } \ + /* save_fpu_regs() sets the CIF_FPU flag, which enforces \ + * a restore of the floating point / vector registers as \ + * soon as the next task returns to user space \ + */ \ + save_fpu_regs(); \ + save_access_regs(&prev->thread.acrs[0]); \ + save_ri_cb(prev->thread.ri_cb); \ + update_cr_regs(next); \ + restore_access_regs(&next->thread.acrs[0]); \ + restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ prev = __switch_to(prev,next); \ } while (0) diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index 6ba0bf9289096a96a68be68f2e86230404125f3b..6bc941be6921773f566efd701a213ef44793a793 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -64,6 +64,12 @@ static inline void syscall_get_arguments(struct task_struct *task, { unsigned long mask = -1UL; + /* + * No arguments for this syscall, there's nothing to do. + */ + if (!n) + return; + BUG_ON(i + n > 6); #ifdef CONFIG_COMPAT if (test_tsk_thread_flag(task, TIF_31BIT)) diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index 39846100682a3e9c11ab9ffc4223d4734844cd1d..eed927aeb08f9501c0285094b0a911a66d117482 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -43,23 +43,6 @@ static inline void __tlb_flush_global(void) * Flush TLB entries for a specific mm on all CPUs (in case gmap is used * this implicates multiple ASCEs!). */ -static inline void __tlb_flush_full(struct mm_struct *mm) -{ - preempt_disable(); - atomic_inc(&mm->context.flush_count); - if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { - /* Local TLB flush */ - __tlb_flush_local(); - } else { - /* Global TLB flush */ - __tlb_flush_global(); - /* Reset TLB flush mask */ - cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask); - } - atomic_dec(&mm->context.flush_count); - preempt_enable(); -} - static inline void __tlb_flush_mm(struct mm_struct *mm) { unsigned long gmap_asce; @@ -71,16 +54,18 @@ static inline void __tlb_flush_mm(struct mm_struct *mm) */ preempt_disable(); atomic_inc(&mm->context.flush_count); + /* Reset TLB flush mask */ + cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask); + barrier(); gmap_asce = READ_ONCE(mm->context.gmap_asce); if (MACHINE_HAS_IDTE && gmap_asce != -1UL) { if (gmap_asce) __tlb_flush_idte(gmap_asce); __tlb_flush_idte(mm->context.asce); } else { - __tlb_flush_full(mm); + /* Global TLB flush */ + __tlb_flush_global(); } - /* Reset TLB flush mask */ - cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask); atomic_dec(&mm->context.flush_count); preempt_enable(); } @@ -94,7 +79,6 @@ static inline void __tlb_flush_kernel(void) } #else #define __tlb_flush_global() __tlb_flush_local() -#define __tlb_flush_full(mm) __tlb_flush_local() /* * Flush TLB entries for a specific ASCE on all CPUs. @@ -112,10 +96,12 @@ static inline void __tlb_flush_kernel(void) static inline void __tlb_flush_mm_lazy(struct mm_struct * mm) { + spin_lock(&mm->context.lock); if (mm->context.flush_mm) { - __tlb_flush_mm(mm); mm->context.flush_mm = 0; + __tlb_flush_mm(mm); } + spin_unlock(&mm->context.lock); } /* diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h index 41b51c2f4f1ba98055f7f75ac36915665b62392c..04fe908755b55b179b4f63f98d1c41bf22d421ec 100644 --- a/arch/s390/include/uapi/asm/socket.h +++ b/arch/s390/include/uapi/asm/socket.h @@ -96,4 +96,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 0f9cd90c11af6173d78d4ace43465cc70332b18f..f06a9a0063f1b11fecfe3abd77b0ca3989a4a0ce 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -263,6 +263,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplis return retval; } + groups_sort(group_info); retval = set_current_groups(group_info); put_group_info(group_info); diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 408b4f4fda0f80fb5fafaf9777ba408ada2c3f4f..598254461fb73b2a0e13b6f41648f7ef96a2cf14 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -426,6 +426,20 @@ static void *nt_vmcoreinfo(void *ptr) return nt_init_name(ptr, 0, vmcoreinfo, size, "VMCOREINFO"); } +/* + * Initialize final note (needed for /proc/vmcore code) + */ +static void *nt_final(void *ptr) +{ + Elf64_Nhdr *note; + + note = (Elf64_Nhdr *) ptr; + note->n_namesz = 0; + note->n_descsz = 0; + note->n_type = 0; + return PTR_ADD(ptr, sizeof(Elf64_Nhdr)); +} + /* * Initialize ELF header (new kernel) */ @@ -513,6 +527,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset) if (sa->prefix != 0) ptr = fill_cpu_elf_notes(ptr, cpu++, sa); ptr = nt_vmcoreinfo(ptr); + ptr = nt_final(ptr); memset(phdr, 0, sizeof(*phdr)); phdr->p_type = PT_NOTE; phdr->p_offset = notes_offset; diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index c74c59236f4418c3f37933ff67b4812c101e8536..aaf9dab3c1933e7557e679245e58176d1dfbf1a9 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1548,6 +1548,7 @@ static struct s390_insn opcode_e7[] = { { "vfsq", 0xce, INSTR_VRR_VV000MM }, { "vfs", 0xe2, INSTR_VRR_VVV00MM }, { "vftci", 0x4a, INSTR_VRI_VVIMM }, + { "", 0, INSTR_INVALID } }; static struct s390_insn opcode_eb[] = { @@ -1953,7 +1954,7 @@ void show_code(struct pt_regs *regs) { char *mode = user_mode(regs) ? "User" : "Krnl"; unsigned char code[64]; - char buffer[64], *ptr; + char buffer[128], *ptr; mm_segment_t old_fs; unsigned long addr; int start, end, opsize, hops, i; @@ -2016,7 +2017,7 @@ void show_code(struct pt_regs *regs) start += opsize; pr_cont("%s", buffer); ptr = buffer; - ptr += sprintf(ptr, "\n "); + ptr += sprintf(ptr, "\n\t "); hops++; } pr_cont("\n"); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 2374c5b46bbcd41b7f51ff72b3ed9b2a73f61f26..29d87444a655ec82756339e8f1fb94ea27ac2adf 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -345,8 +345,10 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; if (test_facility(40)) S390_lowcore.machine_flags |= MACHINE_FLAG_LPP; - if (test_facility(50) && test_facility(73)) + if (test_facility(50) && test_facility(73)) { S390_lowcore.machine_flags |= MACHINE_FLAG_TE; + __ctl_set_bit(0, 55); + } if (test_facility(51)) S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; if (test_facility(129)) { @@ -363,6 +365,18 @@ static inline void save_vector_registers(void) #endif } +static int __init topology_setup(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (!rc && !enabled) + S390_lowcore.machine_flags &= ~MACHINE_HAS_TOPOLOGY; + return rc; +} +early_param("topology", topology_setup); + static int __init disable_vector_extension(char *str) { S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 49a30737addef4103184ad92907b6f1f5b911bfa..3bc2825173efea39282e98a2f021d771c848821f 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -240,12 +240,17 @@ ENTRY(sie64a) lctlg %c1,%c1,__LC_USER_ASCE # load primary asce .Lsie_done: # some program checks are suppressing. C code (e.g. do_protection_exception) -# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other -# instructions between sie64a and .Lsie_done should not cause program -# interrupts. So lets use a nop (47 00 00 00) as a landing pad. +# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There +# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable. +# Other instructions between sie64a and .Lsie_done should not cause program +# interrupts. So lets use 3 nops as a landing pad for all possible rewinds. # See also .Lcleanup_sie -.Lrewind_pad: - nop 0 +.Lrewind_pad6: + nopr 7 +.Lrewind_pad4: + nopr 7 +.Lrewind_pad2: + nopr 7 .globl sie_exit sie_exit: lg %r14,__SF_EMPTY+8(%r15) # load guest register save area @@ -258,7 +263,9 @@ sie_exit: stg %r14,__SF_EMPTY+16(%r15) # set exit reason code j sie_exit - EX_TABLE(.Lrewind_pad,.Lsie_fault) + EX_TABLE(.Lrewind_pad6,.Lsie_fault) + EX_TABLE(.Lrewind_pad4,.Lsie_fault) + EX_TABLE(.Lrewind_pad2,.Lsie_fault) EX_TABLE(sie_exit,.Lsie_fault) EXPORT_SYMBOL(sie64a) EXPORT_SYMBOL(sie_exit) @@ -321,6 +328,7 @@ ENTRY(system_call) lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) +.Lsysc_exit_timer: stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER lmg %r11,%r15,__PT_R11(%r11) @@ -606,6 +614,7 @@ ENTRY(io_int_handler) lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) +.Lio_exit_timer: stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER lmg %r11,%r15,__PT_R11(%r11) @@ -1135,15 +1144,23 @@ cleanup_critical: br %r14 .Lcleanup_sysc_restore: + # check if stpt has been executed clg %r9,BASED(.Lcleanup_sysc_restore_insn) + jh 0f + mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER + cghi %r11,__LC_SAVE_AREA_ASYNC je 0f + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER +0: clg %r9,BASED(.Lcleanup_sysc_restore_insn+8) + je 1f lg %r9,24(%r11) # get saved pointer to pt_regs mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) -0: lmg %r8,%r9,__LC_RETURN_PSW +1: lmg %r8,%r9,__LC_RETURN_PSW br %r14 .Lcleanup_sysc_restore_insn: + .quad .Lsysc_exit_timer .quad .Lsysc_done - 4 .Lcleanup_io_tif: @@ -1151,15 +1168,20 @@ cleanup_critical: br %r14 .Lcleanup_io_restore: + # check if stpt has been executed clg %r9,BASED(.Lcleanup_io_restore_insn) - je 0f + jh 0f + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER +0: clg %r9,BASED(.Lcleanup_io_restore_insn+8) + je 1f lg %r9,24(%r11) # get saved r11 pointer to pt_regs mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) -0: lmg %r8,%r9,__LC_RETURN_PSW +1: lmg %r8,%r9,__LC_RETURN_PSW br %r14 .Lcleanup_io_restore_insn: + .quad .Lio_exit_timer .quad .Lio_done - 4 .Lcleanup_idle: diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index bba4fa74b321a96880b8e542a003ad9adefd683d..8382fc62cde687ae034c4232f17f77d3960a2ad6 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -70,8 +70,6 @@ extern void kernel_thread_starter(void); */ void exit_thread(struct task_struct *tsk) { - if (tsk == current) - exit_thread_runtime_instr(); } void flush_thread(void) @@ -84,6 +82,7 @@ void release_thread(struct task_struct *dead_task) void arch_release_task_struct(struct task_struct *tsk) { + runtime_instr_release(tsk); } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) @@ -120,6 +119,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, memset(&p->thread.per_user, 0, sizeof(p->thread.per_user)); memset(&p->thread.per_event, 0, sizeof(p->thread.per_event)); clear_tsk_thread_flag(p, TIF_SINGLE_STEP); + p->thread.per_flags = 0; /* Initialize per thread user and system timer values */ ti = task_thread_info(p); ti->user_timer = 0; diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c index fffa0e5462afe047c2df37b969fe8b5b9816a170..fd03a7569e101495d8690a65d2de34c9d25765d3 100644 --- a/arch/s390/kernel/runtime_instr.c +++ b/arch/s390/kernel/runtime_instr.c @@ -18,11 +18,24 @@ /* empty control block to disable RI by loading it */ struct runtime_instr_cb runtime_instr_empty_cb; +void runtime_instr_release(struct task_struct *tsk) +{ + kfree(tsk->thread.ri_cb); +} + static void disable_runtime_instr(void) { - struct pt_regs *regs = task_pt_regs(current); + struct task_struct *task = current; + struct pt_regs *regs; + if (!task->thread.ri_cb) + return; + regs = task_pt_regs(task); + preempt_disable(); load_runtime_instr_cb(&runtime_instr_empty_cb); + kfree(task->thread.ri_cb); + task->thread.ri_cb = NULL; + preempt_enable(); /* * Make sure the RI bit is deleted from the PSW. If the user did not @@ -43,17 +56,6 @@ static void init_runtime_instr_cb(struct runtime_instr_cb *cb) cb->valid = 1; } -void exit_thread_runtime_instr(void) -{ - struct task_struct *task = current; - - if (!task->thread.ri_cb) - return; - disable_runtime_instr(); - kfree(task->thread.ri_cb); - task->thread.ri_cb = NULL; -} - SYSCALL_DEFINE1(s390_runtime_instr, int, command) { struct runtime_instr_cb *cb; @@ -62,9 +64,7 @@ SYSCALL_DEFINE1(s390_runtime_instr, int, command) return -EOPNOTSUPP; if (command == S390_RUNTIME_INSTR_STOP) { - preempt_disable(); - exit_thread_runtime_instr(); - preempt_enable(); + disable_runtime_instr(); return 0; } diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 9b59e6212d8fd22cadbc35f9e3546f7aa47e540c..709da452413d43683b8d6e24bc8a51e606fa773f 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -369,10 +369,10 @@ SYSCALL(sys_recvmmsg,compat_sys_recvmmsg) SYSCALL(sys_sendmmsg,compat_sys_sendmmsg) SYSCALL(sys_socket,sys_socket) SYSCALL(sys_socketpair,compat_sys_socketpair) /* 360 */ -SYSCALL(sys_bind,sys_bind) -SYSCALL(sys_connect,sys_connect) +SYSCALL(sys_bind,compat_sys_bind) +SYSCALL(sys_connect,compat_sys_connect) SYSCALL(sys_listen,sys_listen) -SYSCALL(sys_accept4,sys_accept4) +SYSCALL(sys_accept4,compat_sys_accept4) SYSCALL(sys_getsockopt,compat_sys_getsockopt) /* 365 */ SYSCALL(sys_setsockopt,compat_sys_setsockopt) SYSCALL(sys_getsockname,compat_sys_getsockname) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 8705ee66c0874fb73fe6cdf3c751a2d717fbca90..239f29508f0bfacd579d449a7e738703d655b661 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -37,7 +37,6 @@ static void set_topology_timer(void); static void topology_work_fn(struct work_struct *work); static struct sysinfo_15_1_x *tl_info; -static bool topology_enabled = true; static DECLARE_WORK(topology_work, topology_work_fn); /* @@ -56,7 +55,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) cpumask_t mask; cpumask_copy(&mask, cpumask_of(cpu)); - if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) + if (!MACHINE_HAS_TOPOLOGY) return mask; for (; info; info = info->next) { if (cpumask_test_cpu(cpu, &info->mask)) @@ -71,7 +70,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) int i; cpumask_copy(&mask, cpumask_of(cpu)); - if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) + if (!MACHINE_HAS_TOPOLOGY) return mask; cpu -= cpu % (smp_cpu_mtid + 1); for (i = 0; i <= smp_cpu_mtid; i++) @@ -413,12 +412,6 @@ static const struct cpumask *cpu_drawer_mask(int cpu) return &per_cpu(cpu_topology, cpu).drawer_mask; } -static int __init early_parse_topology(char *p) -{ - return kstrtobool(p, &topology_enabled); -} -early_param("topology", early_parse_topology); - static struct sched_domain_topology_level s390_topology[] = { { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index 4aa8a7e2a1da479c8e33162814d1e9f1a4908952..f5d79840f4e0f8732e5fad51f835b6cbec6b228f 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c @@ -972,11 +972,12 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, ptr = asce.origin * 4096; if (asce.r) { *fake = 1; + ptr = 0; asce.dt = ASCE_TYPE_REGION1; } switch (asce.dt) { case ASCE_TYPE_REGION1: - if (vaddr.rfx01 > asce.tl && !asce.r) + if (vaddr.rfx01 > asce.tl && !*fake) return PGM_REGION_FIRST_TRANS; break; case ASCE_TYPE_REGION2: @@ -1004,8 +1005,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, union region1_table_entry rfte; if (*fake) { - /* offset in 16EB guest memory block */ - ptr = ptr + ((unsigned long) vaddr.rsx << 53UL); + ptr += (unsigned long) vaddr.rfx << 53; rfte.val = ptr; goto shadow_r2t; } @@ -1031,8 +1031,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, union region2_table_entry rste; if (*fake) { - /* offset in 8PB guest memory block */ - ptr = ptr + ((unsigned long) vaddr.rtx << 42UL); + ptr += (unsigned long) vaddr.rsx << 42; rste.val = ptr; goto shadow_r3t; } @@ -1059,8 +1058,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, union region3_table_entry rtte; if (*fake) { - /* offset in 4TB guest memory block */ - ptr = ptr + ((unsigned long) vaddr.sx << 31UL); + ptr += (unsigned long) vaddr.rtx << 31; rtte.val = ptr; goto shadow_sgt; } @@ -1096,8 +1094,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, union segment_table_entry ste; if (*fake) { - /* offset in 2G guest memory block */ - ptr = ptr + ((unsigned long) vaddr.sx << 20UL); + ptr += (unsigned long) vaddr.sx << 20; ste.val = ptr; goto shadow_pgt; } diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index e18435355c16f454fdee19e155af08493abe1d44..c2905a10cb37f494e7026ccb82bc06a9eef9a4a1 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -197,8 +197,6 @@ static int try_handle_skey(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); return -EAGAIN; } - if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) - return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return 0; } @@ -209,6 +207,9 @@ static int handle_iske(struct kvm_vcpu *vcpu) int reg1, reg2; int rc; + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + rc = try_handle_skey(vcpu); if (rc) return rc != -EAGAIN ? rc : 0; @@ -238,6 +239,9 @@ static int handle_rrbe(struct kvm_vcpu *vcpu) int reg1, reg2; int rc; + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + rc = try_handle_skey(vcpu); if (rc) return rc != -EAGAIN ? rc : 0; @@ -273,6 +277,9 @@ static int handle_sske(struct kvm_vcpu *vcpu) int reg1, reg2; int rc; + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); + rc = try_handle_skey(vcpu); if (rc) return rc != -EAGAIN ? rc : 0; diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kvm/sthyi.c index 05c98bb853cf971117530967a94f9176f85ef049..2f04ad1ea01c1a082fcfe6b4c12c14e50f2b4fad 100644 --- a/arch/s390/kvm/sthyi.c +++ b/arch/s390/kvm/sthyi.c @@ -394,7 +394,7 @@ static int sthyi(u64 vaddr) "srl %[cc],28\n" : [cc] "=d" (cc) : [code] "d" (code), [addr] "a" (addr) - : "memory", "cc"); + : "3", "memory", "cc"); return cc; } @@ -422,7 +422,7 @@ int handle_sthyi(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr); trace_kvm_s390_handle_sthyi(vcpu, code, addr); - if (reg1 == reg2 || reg1 & 1 || reg2 & 1 || addr & ~PAGE_MASK) + if (reg1 == reg2 || reg1 & 1 || reg2 & 1) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); if (code & 0xffff) { @@ -430,6 +430,9 @@ int handle_sthyi(struct kvm_vcpu *vcpu) goto out; } + if (addr & ~PAGE_MASK) + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); + /* * If the page has not yet been faulted in, we want to do that * now and not after all the expensive calculations. diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 3ba622702ce47cd2a908150f6b37e2801be47557..cb2cd04e6698a15ac1043d936af1b6fa2e7341a3 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -2124,6 +2124,37 @@ static inline void thp_split_mm(struct mm_struct *mm) #endif } +/* + * Remove all empty zero pages from the mapping for lazy refaulting + * - This must be called after mm->context.has_pgste is set, to avoid + * future creation of zero pages + * - This must be called after THP was enabled + */ +static int __zap_zero_pages(pmd_t *pmd, unsigned long start, + unsigned long end, struct mm_walk *walk) +{ + unsigned long addr; + + for (addr = start; addr != end; addr += PAGE_SIZE) { + pte_t *ptep; + spinlock_t *ptl; + + ptep = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (is_zero_pfn(pte_pfn(*ptep))) + ptep_xchg_direct(walk->mm, addr, ptep, __pte(_PAGE_INVALID)); + pte_unmap_unlock(ptep, ptl); + } + return 0; +} + +static inline void zap_zero_pages(struct mm_struct *mm) +{ + struct mm_walk walk = { .pmd_entry = __zap_zero_pages }; + + walk.mm = mm; + walk_page_range(0, TASK_SIZE, &walk); +} + /* * switch on pgstes for its userspace process (for kvm) */ @@ -2141,6 +2172,7 @@ int s390_enable_sie(void) mm->context.has_pgste = 1; /* split thp mappings and disable thp for future mappings */ thp_split_mm(mm); + zap_zero_pages(mm); up_write(&mm->mmap_sem); return 0; } @@ -2153,13 +2185,6 @@ EXPORT_SYMBOL_GPL(s390_enable_sie); static int __s390_enable_skey(pte_t *pte, unsigned long addr, unsigned long next, struct mm_walk *walk) { - /* - * Remove all zero page mappings, - * after establishing a policy to forbid zero page mappings - * following faults for that page will get fresh anonymous pages - */ - if (is_zero_pfn(pte_pfn(*pte))) - ptep_xchg_direct(walk->mm, addr, pte, __pte(_PAGE_INVALID)); /* Clear storage key */ ptep_zap_key(walk->mm, addr, pte); return 0; diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 18d4107e10eefb5e2ea5935412a95e7a03f2ae41..97fc449a747077b7038b9ae4afef796fd291a785 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -56,13 +56,12 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr, static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { - unsigned long mask, result; struct page *head, *page; + unsigned long mask; int refs; - result = write ? 0 : _SEGMENT_ENTRY_PROTECT; - mask = result | _SEGMENT_ENTRY_INVALID; - if ((pmd_val(pmd) & mask) != result) + mask = (write ? _SEGMENT_ENTRY_PROTECT : 0) | _SEGMENT_ENTRY_INVALID; + if ((pmd_val(pmd) & mask) != 0) return 0; VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT)); diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index eb9df2822da193250fc2c72589a31e620110a599..812368f274c96bacdf2cbba41aefabe2f44ef5a8 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -98,7 +98,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -136,7 +136,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index bee281f3163d039e2fa203bcdaa02b8bf87d6ced..e8dee623d54531d94fba5b4216af800616293fc6 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -1252,7 +1252,8 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp) insn_count = bpf_jit_insn(jit, fp, i); if (insn_count < 0) return -1; - jit->addrs[i + 1] = jit->prg; /* Next instruction address */ + /* Next instruction address */ + jit->addrs[i + insn_count] = jit->prg; } bpf_jit_epilogue(jit); diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 15ffc19c8c0c9e121525ff18c8b27dde1ebfd3eb..03a1d5976ff5016b25841dd1c87a425276cb1609 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -354,7 +354,8 @@ static void zpci_irq_handler(struct airq_struct *airq) /* End of second scan with interrupts on. */ break; /* First scan complete, reenable interrupts. */ - zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); + if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC)) + break; si = 0; continue; } @@ -928,7 +929,7 @@ static int __init pci_base_init(void) if (!s390_pci_probe) return 0; - if (!test_facility(69) || !test_facility(71) || !test_facility(72)) + if (!test_facility(69) || !test_facility(71)) return 0; rc = zpci_debug_init(); diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index fa8d7d4b97515836e0b2d25a1c858fc8b28eef37..248146dcfce32ca466e992b516dda3ec8a481209 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -91,11 +92,14 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range) } /* Set Interruption Controls */ -void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) +int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) { + if (!test_facility(72)) + return -EIO; asm volatile ( " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); + return 0; } /* PCI Load */ diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c index 538c10db35379dfd3b4c97fb137453609b0ded7c..8dc315b212c2f10a0e1ab15653a521667e48894a 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c @@ -165,7 +165,6 @@ static struct plat_sci_port scif2_platform_data = { .scscr = SCSCR_TE | SCSCR_RE, .type = PORT_IRDA, .ops = &sh770x_sci_port_ops, - .regshift = 1, }; static struct resource scif2_resources[] = { diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 6777177807c26f5d6630ec48535bb4f7d5eba0e2..7df7d59441889aa8bc4a748cd4a40dc94ab89cff 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -63,7 +63,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -113,7 +113,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 165ecdd24d22dec52108d54d2b31db4a38f55aab..8b4152f3a764a0502e1d52f5f91678971228aafd 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -187,9 +187,9 @@ config NR_CPUS int "Maximum number of CPUs" depends on SMP range 2 32 if SPARC32 - range 2 1024 if SPARC64 + range 2 4096 if SPARC64 default 32 if SPARC32 - default 64 if SPARC64 + default 4096 if SPARC64 source kernel/Kconfig.hz @@ -568,9 +568,6 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y -config KEYS_COMPAT - def_bool y if COMPAT && KEYS - endmenu source "net/Kconfig" diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h index f7de0dbc38af2dd36c9f34df53e6e951f6729825..83b36a5371ffc62e80fa694e077867f4f8b1f49f 100644 --- a/arch/sparc/include/asm/mmu_64.h +++ b/arch/sparc/include/asm/mmu_64.h @@ -52,7 +52,7 @@ #define CTX_NR_MASK TAG_CONTEXT_BITS #define CTX_HW_MASK (CTX_NR_MASK | CTX_PGSZ_MASK) -#define CTX_FIRST_VERSION ((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL)) +#define CTX_FIRST_VERSION BIT(CTX_VERSION_SHIFT) #define CTX_VALID(__ctx) \ (!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK)) #define CTX_HWBITS(__ctx) ((__ctx.sparc64_ctx_val) & CTX_HW_MASK) diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index b84be675e507857e27766b6339e438270aea0ebe..0cdeb2b483a0dbfa3183566b118006f7545d72f3 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -17,22 +17,19 @@ extern spinlock_t ctx_alloc_lock; extern unsigned long tlb_context_cache; extern unsigned long mmu_context_bmap[]; +DECLARE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm); void get_new_mmu_context(struct mm_struct *mm); -#ifdef CONFIG_SMP -void smp_new_mmu_context_version(void); -#else -#define smp_new_mmu_context_version() do { } while (0) -#endif - int init_new_context(struct task_struct *tsk, struct mm_struct *mm); void destroy_context(struct mm_struct *mm); void __tsb_context_switch(unsigned long pgd_pa, struct tsb_config *tsb_base, struct tsb_config *tsb_huge, - unsigned long tsb_descr_pa); + unsigned long tsb_descr_pa, + unsigned long secondary_ctx); -static inline void tsb_context_switch(struct mm_struct *mm) +static inline void tsb_context_switch_ctx(struct mm_struct *mm, + unsigned long ctx) { __tsb_context_switch(__pa(mm->pgd), &mm->context.tsb_block[0], @@ -43,9 +40,12 @@ static inline void tsb_context_switch(struct mm_struct *mm) #else NULL #endif - , __pa(&mm->context.tsb_descr[0])); + , __pa(&mm->context.tsb_descr[0]), + ctx); } +#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0) + void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long mm_rss); @@ -74,8 +74,9 @@ void __flush_tlb_mm(unsigned long, unsigned long); static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) { unsigned long ctx_valid, flags; - int cpu; + int cpu = smp_processor_id(); + per_cpu(per_cpu_secondary_mm, cpu) = mm; if (unlikely(mm == &init_mm)) return; @@ -114,14 +115,12 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str * cpu0 to update it's TSB because at that point the cpu_vm_mask * only had cpu1 set in it. */ - load_secondary_context(mm); - tsb_context_switch(mm); + tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context)); /* Any time a processor runs a context on an address space * for the first time, we must flush that context out of the * local TLB. */ - cpu = smp_processor_id(); if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) { cpumask_set_cpu(cpu, mm_cpumask(mm)); __flush_tlb_mm(CTX_HWBITS(mm->context), @@ -131,26 +130,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str } #define deactivate_mm(tsk,mm) do { } while (0) - -/* Activate a new MM instance for the current task. */ -static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm) -{ - unsigned long flags; - int cpu; - - spin_lock_irqsave(&mm->context.lock, flags); - if (!CTX_VALID(mm->context)) - get_new_mmu_context(mm); - cpu = smp_processor_id(); - if (!cpumask_test_cpu(cpu, mm_cpumask(mm))) - cpumask_set_cpu(cpu, mm_cpumask(mm)); - - load_secondary_context(mm); - __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); - tsb_context_switch(mm); - spin_unlock_irqrestore(&mm->context.lock, flags); -} - +#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, NULL) #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC64_MMU_CONTEXT_H) */ diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index ce6f56980aefd2902bfae849eb90a993295976eb..cf190728360bbfb43621d23a7fb3a22c443a7399 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -91,9 +91,9 @@ extern unsigned long pfn_base; * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. */ -extern unsigned long empty_zero_page; +extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) (virt_to_page(&empty_zero_page)) +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) /* * In general all page table modifications should use the V8 atomic diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 1fb317fbc0b3419123c99f5c4b2807d3162ffc5f..b6802b978140ada8284e3f28d6cfa715eb6fcab3 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -673,26 +673,27 @@ static inline unsigned long pmd_pfn(pmd_t pmd) return pte_pfn(pte); } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline unsigned long pmd_dirty(pmd_t pmd) +#define __HAVE_ARCH_PMD_WRITE +static inline unsigned long pmd_write(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_dirty(pte); + return pte_write(pte); } -static inline unsigned long pmd_young(pmd_t pmd) +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline unsigned long pmd_dirty(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_young(pte); + return pte_dirty(pte); } -static inline unsigned long pmd_write(pmd_t pmd) +static inline unsigned long pmd_young(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); - return pte_write(pte); + return pte_young(pte); } static inline unsigned long pmd_trans_huge(pmd_t pmd) diff --git a/arch/sparc/include/asm/pil.h b/arch/sparc/include/asm/pil.h index 2669370305465d7a4d1c2f9c5a7c9eae2f66474d..522b43db2ed336a5d34dee17b4e8c3b593e6ee5d 100644 --- a/arch/sparc/include/asm/pil.h +++ b/arch/sparc/include/asm/pil.h @@ -20,7 +20,6 @@ #define PIL_SMP_CALL_FUNC 1 #define PIL_SMP_RECEIVE_SIGNAL 2 #define PIL_SMP_CAPTURE 3 -#define PIL_SMP_CTX_NEW_VERSION 4 #define PIL_DEVICE_IRQ 5 #define PIL_SMP_CALL_FUNC_SNGL 6 #define PIL_DEFERRED_PCR_WORK 7 diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 29d64b1758ed2a0ceb795a07c10205e6f923e6c6..3fae200dd251f094bad756ef145ec39882470d8e 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h @@ -16,7 +16,7 @@ extern char reboot_command[]; */ extern unsigned char boot_cpu_id; -extern unsigned long empty_zero_page; +extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; extern int serial_console; static inline int con_is_present(void) @@ -59,8 +59,11 @@ extern atomic_t dcpage_flushes; extern atomic_t dcpage_flushes_xcall; extern int sysctl_tsb_ratio; -#endif +#ifdef CONFIG_SERIAL_SUNHV +void sunhv_migrate_hvcons_irq(int cpu); +#endif +#endif void sun_do_break(void); extern int stop_a_enabled; extern int scons_pwroff; diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h index ec9c04de3664910d81b7a55bbb09084d5e235d39..ff05992dae7a352597bf99fcd2d83500ad0c2995 100644 --- a/arch/sparc/include/asm/trap_block.h +++ b/arch/sparc/include/asm/trap_block.h @@ -54,6 +54,7 @@ extern struct trap_per_cpu trap_block[NR_CPUS]; void init_cur_cpu_trap(struct thread_info *); void setup_tba(void); extern int ncpus_probed; +extern u64 cpu_mondo_counter[NR_CPUS]; unsigned long real_hard_smp_processor_id(void); diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 8174f6cdbbbbd87af5bdbcb923352ddadb4e237e..9dca7a892978a49d234a2b9325228b2c900d1276 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -327,6 +327,7 @@ struct vio_dev { int compat_len; u64 dev_no; + u64 id; unsigned long channel_id; diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 31aede3af088034934c4205f2ab3bf7003956370..de15f0a09b321522ffa1468b73fbeb11eff198d0 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -86,6 +86,8 @@ #define SO_CNX_ADVICE 0x0037 +#define SO_COOKIE 0x003b + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index 6bcff698069bf1fa57c1d84df180c1cb67f18a65..cec54dc4ab817e7c9c54c2d9b0532f0fd49bc7d8 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c @@ -130,17 +130,16 @@ unsigned long prepare_ftrace_return(unsigned long parent, if (unlikely(atomic_read(¤t->tracing_graph_pause))) return parent + 8UL; - if (ftrace_push_return_trace(parent, self_addr, &trace.depth, - frame_pointer, NULL) == -EBUSY) - return parent + 8UL; - trace.func = self_addr; + trace.depth = current->curr_ret_stack + 1; /* Only trace if the calling function expects to */ - if (!ftrace_graph_entry(&trace)) { - current->curr_ret_stack--; + if (!ftrace_graph_entry(&trace)) + return parent + 8UL; + + if (ftrace_push_return_trace(parent, self_addr, &trace.depth, + frame_pointer, NULL) == -EBUSY) return parent + 8UL; - } return return_hooker; } diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 6aa3da152c20008a08e752c4f9708ff6a89e3d72..9835152a0682346af84f65cf85f668a24e1b4d96 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -935,3 +935,9 @@ ENTRY(__retl_o1) retl mov %o1, %o0 ENDPROC(__retl_o1) + +ENTRY(__retl_o1_asi) + wr %o5, 0x0, %asi + retl + mov %o1, %o0 +ENDPROC(__retl_o1_asi) diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 34a7930b76ef1056dfa6ad1633e4cd8b4493138c..5cbf03c14981037204ddc4aed27afd8be88879c9 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -1021,7 +1021,7 @@ static void __init alloc_one_queue(unsigned long *pa_ptr, unsigned long qmask) unsigned long order = get_order(size); unsigned long p; - p = __get_free_pages(GFP_KERNEL, order); + p = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order); if (!p) { prom_printf("SUN4V: Error, cannot allocate queue.\n"); prom_halt(); @@ -1034,17 +1034,26 @@ static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb) { #ifdef CONFIG_SMP unsigned long page; + void *mondo, *p; - BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); + BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > PAGE_SIZE); + + /* Make sure mondo block is 64byte aligned */ + p = kzalloc(127, GFP_KERNEL); + if (!p) { + prom_printf("SUN4V: Error, cannot allocate mondo block.\n"); + prom_halt(); + } + mondo = (void *)(((unsigned long)p + 63) & ~0x3f); + tb->cpu_mondo_block_pa = __pa(mondo); page = get_zeroed_page(GFP_KERNEL); if (!page) { - prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); + prom_printf("SUN4V: Error, cannot allocate cpu list page.\n"); prom_halt(); } - tb->cpu_mondo_block_pa = __pa(page); - tb->cpu_list_pa = __pa(page + 64); + tb->cpu_list_pa = __pa(page); #endif } diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index c9804551262cc2832ea35b0d1285dc3051319fd4..6ae1e77be0bfde27696595a1f33e939935d83321 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -37,7 +37,6 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr /* smp_64.c */ void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs); void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs); -void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs); void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs); void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs); diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 06981cc716b68022712dc3a872e611565e4e4817..d04111a5c61578bb6b3bc07ae0ffec5bccadef6d 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -1240,8 +1240,6 @@ static int pci_sun4v_probe(struct platform_device *op) * ATU group, but ATU hcalls won't be available. */ hv_atu = false; - pr_err(PFX "Could not register hvapi ATU err=%d\n", - err); } else { pr_info(PFX "Registered hvapi ATU major[%lu] minor[%lu]\n", vatu_major, vatu_minor); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 8182f7caf5b1faa0b5d3cdc3a767411da4ad9f2a..ca7cb8e57ab0f9a0830164795a0afd1dc2f1c190 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -621,22 +621,48 @@ static void cheetah_xcall_deliver(struct trap_per_cpu *tb, int cnt) } } -/* Multi-cpu list version. */ +#define CPU_MONDO_COUNTER(cpuid) (cpu_mondo_counter[cpuid]) +#define MONDO_USEC_WAIT_MIN 2 +#define MONDO_USEC_WAIT_MAX 100 +#define MONDO_RETRY_LIMIT 500000 + +/* Multi-cpu list version. + * + * Deliver xcalls to 'cnt' number of cpus in 'cpu_list'. + * Sometimes not all cpus receive the mondo, requiring us to re-send + * the mondo until all cpus have received, or cpus are truly stuck + * unable to receive mondo, and we timeout. + * Occasionally a target cpu strand is borrowed briefly by hypervisor to + * perform guest service, such as PCIe error handling. Consider the + * service time, 1 second overall wait is reasonable for 1 cpu. + * Here two in-between mondo check wait time are defined: 2 usec for + * single cpu quick turn around and up to 100usec for large cpu count. + * Deliver mondo to large number of cpus could take longer, we adjusts + * the retry count as long as target cpus are making forward progress. + */ static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt) { - int retries, this_cpu, prev_sent, i, saw_cpu_error; + int this_cpu, tot_cpus, prev_sent, i, rem; + int usec_wait, retries, tot_retries; + u16 first_cpu = 0xffff; + unsigned long xc_rcvd = 0; unsigned long status; + int ecpuerror_id = 0; + int enocpu_id = 0; u16 *cpu_list; + u16 cpu; this_cpu = smp_processor_id(); - cpu_list = __va(tb->cpu_list_pa); - - saw_cpu_error = 0; - retries = 0; + usec_wait = cnt * MONDO_USEC_WAIT_MIN; + if (usec_wait > MONDO_USEC_WAIT_MAX) + usec_wait = MONDO_USEC_WAIT_MAX; + retries = tot_retries = 0; + tot_cpus = cnt; prev_sent = 0; + do { - int forward_progress, n_sent; + int n_sent, mondo_delivered, target_cpu_busy; status = sun4v_cpu_mondo_send(cnt, tb->cpu_list_pa, @@ -644,94 +670,113 @@ static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt) /* HV_EOK means all cpus received the xcall, we're done. */ if (likely(status == HV_EOK)) - break; + goto xcall_done; + + /* If not these non-fatal errors, panic */ + if (unlikely((status != HV_EWOULDBLOCK) && + (status != HV_ECPUERROR) && + (status != HV_ENOCPU))) + goto fatal_errors; /* First, see if we made any forward progress. + * + * Go through the cpu_list, count the target cpus that have + * received our mondo (n_sent), and those that did not (rem). + * Re-pack cpu_list with the cpus remain to be retried in the + * front - this simplifies tracking the truly stalled cpus. * * The hypervisor indicates successful sends by setting * cpu list entries to the value 0xffff. + * + * EWOULDBLOCK means some target cpus did not receive the + * mondo and retry usually helps. + * + * ECPUERROR means at least one target cpu is in error state, + * it's usually safe to skip the faulty cpu and retry. + * + * ENOCPU means one of the target cpu doesn't belong to the + * domain, perhaps offlined which is unexpected, but not + * fatal and it's okay to skip the offlined cpu. */ + rem = 0; n_sent = 0; for (i = 0; i < cnt; i++) { - if (likely(cpu_list[i] == 0xffff)) + cpu = cpu_list[i]; + if (likely(cpu == 0xffff)) { n_sent++; + } else if ((status == HV_ECPUERROR) && + (sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) { + ecpuerror_id = cpu + 1; + } else if (status == HV_ENOCPU && !cpu_online(cpu)) { + enocpu_id = cpu + 1; + } else { + cpu_list[rem++] = cpu; + } } - forward_progress = 0; - if (n_sent > prev_sent) - forward_progress = 1; + /* No cpu remained, we're done. */ + if (rem == 0) + break; - prev_sent = n_sent; + /* Otherwise, update the cpu count for retry. */ + cnt = rem; - /* If we get a HV_ECPUERROR, then one or more of the cpus - * in the list are in error state. Use the cpu_state() - * hypervisor call to find out which cpus are in error state. + /* Record the overall number of mondos received by the + * first of the remaining cpus. */ - if (unlikely(status == HV_ECPUERROR)) { - for (i = 0; i < cnt; i++) { - long err; - u16 cpu; + if (first_cpu != cpu_list[0]) { + first_cpu = cpu_list[0]; + xc_rcvd = CPU_MONDO_COUNTER(first_cpu); + } - cpu = cpu_list[i]; - if (cpu == 0xffff) - continue; + /* Was any mondo delivered successfully? */ + mondo_delivered = (n_sent > prev_sent); + prev_sent = n_sent; - err = sun4v_cpu_state(cpu); - if (err == HV_CPU_STATE_ERROR) { - saw_cpu_error = (cpu + 1); - cpu_list[i] = 0xffff; - } - } - } else if (unlikely(status != HV_EWOULDBLOCK)) - goto fatal_mondo_error; + /* or, was any target cpu busy processing other mondos? */ + target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu)); + xc_rcvd = CPU_MONDO_COUNTER(first_cpu); - /* Don't bother rewriting the CPU list, just leave the - * 0xffff and non-0xffff entries in there and the - * hypervisor will do the right thing. - * - * Only advance timeout state if we didn't make any - * forward progress. + /* Retry count is for no progress. If we're making progress, + * reset the retry count. */ - if (unlikely(!forward_progress)) { - if (unlikely(++retries > 10000)) - goto fatal_mondo_timeout; - - /* Delay a little bit to let other cpus catch up - * on their cpu mondo queue work. - */ - udelay(2 * cnt); + if (likely(mondo_delivered || target_cpu_busy)) { + tot_retries += retries; + retries = 0; + } else if (unlikely(retries > MONDO_RETRY_LIMIT)) { + goto fatal_mondo_timeout; } - } while (1); - if (unlikely(saw_cpu_error)) - goto fatal_mondo_cpu_error; + /* Delay a little bit to let other cpus catch up on + * their cpu mondo queue work. + */ + if (!mondo_delivered) + udelay(usec_wait); - return; + retries++; + } while (1); -fatal_mondo_cpu_error: - printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " - "(including %d) were in error state\n", - this_cpu, saw_cpu_error - 1); +xcall_done: + if (unlikely(ecpuerror_id > 0)) { + pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n", + this_cpu, ecpuerror_id - 1); + } else if (unlikely(enocpu_id > 0)) { + pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n", + this_cpu, enocpu_id - 1); + } return; +fatal_errors: + /* fatal errors include bad alignment, etc */ + pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n", + this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa); + panic("Unexpected SUN4V mondo error %lu\n", status); + fatal_mondo_timeout: - printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " - " progress after %d retries.\n", - this_cpu, retries); - goto dump_cpu_list_and_out; - -fatal_mondo_error: - printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", - this_cpu, status); - printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " - "mondo_block_pa(%lx)\n", - this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa); - -dump_cpu_list_and_out: - printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu); - for (i = 0; i < cnt; i++) - printk("%u ", cpu_list[i]); - printk("]\n"); + /* some cpus being non-responsive to the cpu mondo */ + pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n", + this_cpu, first_cpu, (tot_retries + retries), tot_cpus); + panic("SUN4V mondo timeout panic\n"); } static void (*xcall_deliver_impl)(struct trap_per_cpu *, int); @@ -963,37 +1008,6 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) preempt_enable(); } -void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) -{ - struct mm_struct *mm; - unsigned long flags; - - clear_softint(1 << irq); - - /* See if we need to allocate a new TLB context because - * the version of the one we are using is now out of date. - */ - mm = current->active_mm; - if (unlikely(!mm || (mm == &init_mm))) - return; - - spin_lock_irqsave(&mm->context.lock, flags); - - if (unlikely(!CTX_VALID(mm->context))) - get_new_mmu_context(mm); - - spin_unlock_irqrestore(&mm->context.lock, flags); - - load_secondary_context(mm); - __flush_tlb_mm(CTX_HWBITS(mm->context), - SECONDARY_CONTEXT); -} - -void smp_new_mmu_context_version(void) -{ - smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); -} - #ifdef CONFIG_KGDB void kgdb_roundup_cpus(unsigned long flags) { @@ -1451,8 +1465,12 @@ void smp_send_stop(void) int cpu; if (tlb_type == hypervisor) { + int this_cpu = smp_processor_id(); +#ifdef CONFIG_SERIAL_SUNHV + sunhv_migrate_hvcons_irq(this_cpu); +#endif for_each_online_cpu(cpu) { - if (cpu == smp_processor_id()) + if (cpu == this_cpu) continue; #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) { diff --git a/arch/sparc/kernel/sun4v_ivec.S b/arch/sparc/kernel/sun4v_ivec.S index 559bc5e9c199232d092ec425d705a016b639db9a..34631995859afb2c273f3087796ff550371bc634 100644 --- a/arch/sparc/kernel/sun4v_ivec.S +++ b/arch/sparc/kernel/sun4v_ivec.S @@ -26,6 +26,21 @@ sun4v_cpu_mondo: ldxa [%g0] ASI_SCRATCHPAD, %g4 sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4 + /* Get smp_processor_id() into %g3 */ + sethi %hi(trap_block), %g5 + or %g5, %lo(trap_block), %g5 + sub %g4, %g5, %g3 + srlx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 + + /* Increment cpu_mondo_counter[smp_processor_id()] */ + sethi %hi(cpu_mondo_counter), %g5 + or %g5, %lo(cpu_mondo_counter), %g5 + sllx %g3, 3, %g3 + add %g5, %g3, %g5 + ldx [%g5], %g3 + add %g3, 1, %g3 + stx %g3, [%g5] + /* Get CPU mondo queue base phys address into %g7. */ ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index fe8b8ee8e6602307bebf6813704146da7d9bc30e..02e05e221b94516387c58fdc1ec572c6ccef036f 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -118,7 +118,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -181,7 +181,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 4094a51b19708d0174712c36f8f8556a6a87c083..32dafb920908e6757287b77ad69bbf5e9511d031 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -85,7 +85,7 @@ static void dump_tl1_traplog(struct tl1_traplog *p) void bad_trap(struct pt_regs *regs, long lvl) { - char buffer[32]; + char buffer[36]; siginfo_t info; if (notify_die(DIE_TRAP, "bad trap", regs, @@ -116,7 +116,7 @@ void bad_trap(struct pt_regs *regs, long lvl) void bad_trap_tl1(struct pt_regs *regs, long lvl) { - char buffer[32]; + char buffer[36]; if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs, 0, lvl, SIGTRAP) == NOTIFY_STOP) @@ -2051,6 +2051,73 @@ void sun4v_resum_overflow(struct pt_regs *regs) atomic_inc(&sun4v_resum_oflow_cnt); } +/* Given a set of registers, get the virtual addressi that was being accessed + * by the faulting instructions at tpc. + */ +static unsigned long sun4v_get_vaddr(struct pt_regs *regs) +{ + unsigned int insn; + + if (!copy_from_user(&insn, (void __user *)regs->tpc, 4)) { + return compute_effective_address(regs, insn, + (insn >> 25) & 0x1f); + } + return 0; +} + +/* Attempt to handle non-resumable errors generated from userspace. + * Returns true if the signal was handled, false otherwise. + */ +bool sun4v_nonresum_error_user_handled(struct pt_regs *regs, + struct sun4v_error_entry *ent) { + + unsigned int attrs = ent->err_attrs; + + if (attrs & SUN4V_ERR_ATTRS_MEMORY) { + unsigned long addr = ent->err_raddr; + siginfo_t info; + + if (addr == ~(u64)0) { + /* This seems highly unlikely to ever occur */ + pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory error detected in unknown location!\n"); + } else { + unsigned long page_cnt = DIV_ROUND_UP(ent->err_size, + PAGE_SIZE); + + /* Break the unfortunate news. */ + pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory failed at %016lX\n", + addr); + pr_emerg("SUN4V NON-RECOVERABLE ERROR: Claiming %lu ages.\n", + page_cnt); + + while (page_cnt-- > 0) { + if (pfn_valid(addr >> PAGE_SHIFT)) + get_page(pfn_to_page(addr >> PAGE_SHIFT)); + addr += PAGE_SIZE; + } + } + info.si_signo = SIGKILL; + info.si_errno = 0; + info.si_trapno = 0; + force_sig_info(info.si_signo, &info, current); + + return true; + } + if (attrs & SUN4V_ERR_ATTRS_PIO) { + siginfo_t info; + + info.si_signo = SIGBUS; + info.si_code = BUS_ADRERR; + info.si_addr = (void __user *)sun4v_get_vaddr(regs); + force_sig_info(info.si_signo, &info, current); + + return true; + } + + /* Default to doing nothing */ + return false; +} + /* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate. * Log the event, clear the first word of the entry, and die. */ @@ -2075,6 +2142,12 @@ void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset) put_cpu(); + if (!(regs->tstate & TSTATE_PRIV) && + sun4v_nonresum_error_user_handled(regs, &local_copy)) { + /* DON'T PANIC: This userspace error was handled. */ + return; + } + #ifdef CONFIG_PCI /* Check for the special PCI poke sequence. */ if (pci_poke_in_progress && pci_poke_cpu == cpu) { @@ -2659,6 +2732,7 @@ void do_getpsr(struct pt_regs *regs) } } +u64 cpu_mondo_counter[NR_CPUS] = {0}; struct trap_per_cpu trap_block[NR_CPUS]; EXPORT_SYMBOL(trap_block); diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S index d568c8207af72ffbd15aae8e5f41f77401ba5397..7d961f6e3907683292a66744a3b6c16ccab850ab 100644 --- a/arch/sparc/kernel/tsb.S +++ b/arch/sparc/kernel/tsb.S @@ -375,6 +375,7 @@ tsb_flush: * %o1: TSB base config pointer * %o2: TSB huge config pointer, or NULL if none * %o3: Hypervisor TSB descriptor physical address + * %o4: Secondary context to load, if non-zero * * We have to run this whole thing with interrupts * disabled so that the current cpu doesn't change @@ -387,6 +388,17 @@ __tsb_context_switch: rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate + brz,pn %o4, 1f + mov SECONDARY_CONTEXT, %o5 + +661: stxa %o4, [%o5] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %o4, [%o5] ASI_MMU + .previous + flush %g6 + +1: TRAP_LOAD_TRAP_BLOCK(%g2, %g3) stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR] @@ -470,13 +482,16 @@ __tsb_context_switch: .type copy_tsb,#function copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size * %o2=new_tsb_base, %o3=new_tsb_size + * %o4=page_size_shift */ sethi %uhi(TSB_PASS_BITS), %g7 srlx %o3, 4, %o3 - add %o0, %o1, %g1 /* end of old tsb */ + add %o0, %o1, %o1 /* end of old tsb */ sllx %g7, 32, %g7 sub %o3, 1, %o3 /* %o3 == new tsb hash mask */ + mov %o4, %g1 /* page_size_shift */ + 661: prefetcha [%o0] ASI_N, #one_read .section .tsb_phys_patch, "ax" .word 661b @@ -501,9 +516,9 @@ copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size /* This can definitely be computed faster... */ srlx %o0, 4, %o5 /* Build index */ and %o5, 511, %o5 /* Mask index */ - sllx %o5, PAGE_SHIFT, %o5 /* Put into vaddr position */ + sllx %o5, %g1, %o5 /* Put into vaddr position */ or %o4, %o5, %o4 /* Full VADDR. */ - srlx %o4, PAGE_SHIFT, %o4 /* Shift down to create index */ + srlx %o4, %g1, %o4 /* Shift down to create index */ and %o4, %o3, %o4 /* Mask with new_tsb_nents-1 */ sllx %o4, 4, %o4 /* Shift back up into tsb ent offset */ TSB_STORE(%o2 + %o4, %g2) /* Store TAG */ @@ -511,7 +526,7 @@ copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size TSB_STORE(%o2 + %o4, %g3) /* Store TTE */ 80: add %o0, 16, %o0 - cmp %o0, %g1 + cmp %o0, %o1 bne,pt %xcc, 90b nop diff --git a/arch/sparc/kernel/ttable_64.S b/arch/sparc/kernel/ttable_64.S index c6dfdaa29e208994fab3b1942cd24878d0bd2d98..170ead662f2a1355442acd021ef461026b4c2d2b 100644 --- a/arch/sparc/kernel/ttable_64.S +++ b/arch/sparc/kernel/ttable_64.S @@ -50,7 +50,7 @@ tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) -tl0_irq4: TRAP_IRQ(smp_new_mmu_context_version_client, 4) +tl0_irq4: BTRAP(0x44) #else tl0_irq1: BTRAP(0x41) tl0_irq2: BTRAP(0x42) diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index f6bb857254fcfa170155d4cd8dc8cb717c5bfb97..075d38980dee394fdb32f86e130d0b3ec37ebfeb 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -302,13 +302,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, if (!id) { dev_set_name(&vdev->dev, "%s", bus_id_name); vdev->dev_no = ~(u64)0; + vdev->id = ~(u64)0; } else if (!cfg_handle) { dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id); vdev->dev_no = *id; + vdev->id = ~(u64)0; } else { dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name, *cfg_handle, *id); vdev->dev_no = *cfg_handle; + vdev->id = *id; } vdev->dev.parent = parent; @@ -351,27 +354,84 @@ static void vio_add(struct mdesc_handle *hp, u64 node) (void) vio_create_one(hp, node, &root_vdev->dev); } +struct vio_md_node_query { + const char *type; + u64 dev_no; + u64 id; +}; + static int vio_md_node_match(struct device *dev, void *arg) { + struct vio_md_node_query *query = (struct vio_md_node_query *) arg; struct vio_dev *vdev = to_vio_dev(dev); - if (vdev->mp == (u64) arg) - return 1; + if (vdev->dev_no != query->dev_no) + return 0; + if (vdev->id != query->id) + return 0; + if (strcmp(vdev->type, query->type)) + return 0; - return 0; + return 1; } static void vio_remove(struct mdesc_handle *hp, u64 node) { + const char *type; + const u64 *id, *cfg_handle; + u64 a; + struct vio_md_node_query query; struct device *dev; - dev = device_find_child(&root_vdev->dev, (void *) node, + type = mdesc_get_property(hp, node, "device-type", NULL); + if (!type) { + type = mdesc_get_property(hp, node, "name", NULL); + if (!type) + type = mdesc_node_name(hp, node); + } + + query.type = type; + + id = mdesc_get_property(hp, node, "id", NULL); + cfg_handle = NULL; + mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) { + u64 target; + + target = mdesc_arc_target(hp, a); + cfg_handle = mdesc_get_property(hp, target, + "cfg-handle", NULL); + if (cfg_handle) + break; + } + + if (!id) { + query.dev_no = ~(u64)0; + query.id = ~(u64)0; + } else if (!cfg_handle) { + query.dev_no = *id; + query.id = ~(u64)0; + } else { + query.dev_no = *cfg_handle; + query.id = *id; + } + + dev = device_find_child(&root_vdev->dev, &query, vio_md_node_match); if (dev) { printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev)); device_unregister(dev); put_device(dev); + } else { + if (!id) + printk(KERN_ERR "VIO: Removed unknown %s node.\n", + type); + else if (!cfg_handle) + printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n", + type, *id); + else + printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n", + type, *cfg_handle, *id); } } diff --git a/arch/sparc/lib/GENbzero.S b/arch/sparc/lib/GENbzero.S index 8e7a843ddd88366411de59480377798033d4c0a9..2fbf6297d57cfca68cebbf3da2ac9c62eba837b0 100644 --- a/arch/sparc/lib/GENbzero.S +++ b/arch/sparc/lib/GENbzero.S @@ -8,7 +8,7 @@ 98: x,y; \ .section __ex_table,"a";\ .align 4; \ - .word 98b, __retl_o1; \ + .word 98b, __retl_o1_asi;\ .text; \ .align 4; diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 69912d2f8b54e903ef040b346371cc27204b9d15..07c03e72d81248cebe9c3d48bbc93e1e2de455b7 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -15,6 +15,7 @@ lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-$(CONFIG_SPARC64) += atomic_64.o lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o +lib-$(CONFIG_SPARC64) += multi3.o lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o lib-$(CONFIG_SPARC64) += csum_copy.o csum_copy_from_user.o csum_copy_to_user.o diff --git a/arch/sparc/lib/NGbzero.S b/arch/sparc/lib/NGbzero.S index beab29bf419b606ae23a7c1e8151e2527bc0943c..33053bdf3766b35ee4396c04403931f37965c5d8 100644 --- a/arch/sparc/lib/NGbzero.S +++ b/arch/sparc/lib/NGbzero.S @@ -8,7 +8,7 @@ 98: x,y; \ .section __ex_table,"a";\ .align 4; \ - .word 98b, __retl_o1; \ + .word 98b, __retl_o1_asi;\ .text; \ .align 4; diff --git a/arch/sparc/lib/U3memcpy.S b/arch/sparc/lib/U3memcpy.S index 54f98706b03b2f53025adb99e086002a0629e9f0..5a8cb37f0a3b8e31d0a4194d831bb39559bb6a51 100644 --- a/arch/sparc/lib/U3memcpy.S +++ b/arch/sparc/lib/U3memcpy.S @@ -145,13 +145,13 @@ ENDPROC(U3_retl_o2_plus_GS_plus_0x08) ENTRY(U3_retl_o2_and_7_plus_GS) and %o2, 7, %o2 retl - add %o2, GLOBAL_SPARE, %o2 + add %o2, GLOBAL_SPARE, %o0 ENDPROC(U3_retl_o2_and_7_plus_GS) ENTRY(U3_retl_o2_and_7_plus_GS_plus_8) add GLOBAL_SPARE, 8, GLOBAL_SPARE and %o2, 7, %o2 retl - add %o2, GLOBAL_SPARE, %o2 + add %o2, GLOBAL_SPARE, %o0 ENDPROC(U3_retl_o2_and_7_plus_GS_plus_8) #endif diff --git a/arch/sparc/lib/multi3.S b/arch/sparc/lib/multi3.S new file mode 100644 index 0000000000000000000000000000000000000000..d6b6c97fe3c73061f911737a5da23ab41a3eab77 --- /dev/null +++ b/arch/sparc/lib/multi3.S @@ -0,0 +1,35 @@ +#include +#include + + .text + .align 4 +ENTRY(__multi3) /* %o0 = u, %o1 = v */ + mov %o1, %g1 + srl %o3, 0, %g4 + mulx %g4, %g1, %o1 + srlx %g1, 0x20, %g3 + mulx %g3, %g4, %g5 + sllx %g5, 0x20, %o5 + srl %g1, 0, %g4 + sub %o1, %o5, %o5 + srlx %o5, 0x20, %o5 + addcc %g5, %o5, %g5 + srlx %o3, 0x20, %o5 + mulx %g4, %o5, %g4 + mulx %g3, %o5, %o5 + sethi %hi(0x80000000), %g3 + addcc %g5, %g4, %g5 + srlx %g5, 0x20, %g5 + add %g3, %g3, %g3 + movcc %xcc, %g0, %g3 + addcc %o5, %g5, %o5 + sllx %g4, 0x20, %g4 + add %o1, %g4, %o1 + add %o5, %g3, %g2 + mulx %g1, %o2, %g1 + add %g1, %g2, %g1 + mulx %o0, %o3, %o0 + retl + add %g1, %o0, %o0 +ENDPROC(__multi3) +EXPORT_SYMBOL(__multi3) diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 988acc8b1b80a387d9119782f53f1d41dbe53c4e..58cde8d9be8a25c3be709811b27df4dd4f7b45b2 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -116,7 +116,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); if (task_size - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index eb828715527971b050faa9e40693218c7e25db27..3b7092d9ea8f1a39cb9b7b760b2543da76ffc01d 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -301,7 +301,7 @@ void __init mem_init(void) /* Saves us work later. */ - memset((void *)&empty_zero_page, 0, PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5); i += 1; diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 37aa537b3ad841522d9a13c2b4695edb7b092a28..0f183ffe34164c9ec030c570e8d4aa1273aaedc4 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -658,10 +658,58 @@ EXPORT_SYMBOL(__flush_dcache_range); /* get_new_mmu_context() uses "cache + 1". */ DEFINE_SPINLOCK(ctx_alloc_lock); -unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; +unsigned long tlb_context_cache = CTX_FIRST_VERSION; #define MAX_CTX_NR (1UL << CTX_NR_BITS) #define CTX_BMAP_SLOTS BITS_TO_LONGS(MAX_CTX_NR) DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR); +DEFINE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm) = {0}; + +static void mmu_context_wrap(void) +{ + unsigned long old_ver = tlb_context_cache & CTX_VERSION_MASK; + unsigned long new_ver, new_ctx, old_ctx; + struct mm_struct *mm; + int cpu; + + bitmap_zero(mmu_context_bmap, 1 << CTX_NR_BITS); + + /* Reserve kernel context */ + set_bit(0, mmu_context_bmap); + + new_ver = (tlb_context_cache & CTX_VERSION_MASK) + CTX_FIRST_VERSION; + if (unlikely(new_ver == 0)) + new_ver = CTX_FIRST_VERSION; + tlb_context_cache = new_ver; + + /* + * Make sure that any new mm that are added into per_cpu_secondary_mm, + * are going to go through get_new_mmu_context() path. + */ + mb(); + + /* + * Updated versions to current on those CPUs that had valid secondary + * contexts + */ + for_each_online_cpu(cpu) { + /* + * If a new mm is stored after we took this mm from the array, + * it will go into get_new_mmu_context() path, because we + * already bumped the version in tlb_context_cache. + */ + mm = per_cpu(per_cpu_secondary_mm, cpu); + + if (unlikely(!mm || mm == &init_mm)) + continue; + + old_ctx = mm->context.sparc64_ctx_val; + if (likely((old_ctx & CTX_VERSION_MASK) == old_ver)) { + new_ctx = (old_ctx & ~CTX_VERSION_MASK) | new_ver; + set_bit(new_ctx & CTX_NR_MASK, mmu_context_bmap); + mm->context.sparc64_ctx_val = new_ctx; + } + } +} /* Caller does TLB context flushing on local CPU if necessary. * The caller also ensures that CTX_VALID(mm->context) is false. @@ -677,48 +725,30 @@ void get_new_mmu_context(struct mm_struct *mm) { unsigned long ctx, new_ctx; unsigned long orig_pgsz_bits; - int new_version; spin_lock(&ctx_alloc_lock); +retry: + /* wrap might have happened, test again if our context became valid */ + if (unlikely(CTX_VALID(mm->context))) + goto out; orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); ctx = (tlb_context_cache + 1) & CTX_NR_MASK; new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); - new_version = 0; if (new_ctx >= (1 << CTX_NR_BITS)) { new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1); if (new_ctx >= ctx) { - int i; - new_ctx = (tlb_context_cache & CTX_VERSION_MASK) + - CTX_FIRST_VERSION; - if (new_ctx == 1) - new_ctx = CTX_FIRST_VERSION; - - /* Don't call memset, for 16 entries that's just - * plain silly... - */ - mmu_context_bmap[0] = 3; - mmu_context_bmap[1] = 0; - mmu_context_bmap[2] = 0; - mmu_context_bmap[3] = 0; - for (i = 4; i < CTX_BMAP_SLOTS; i += 4) { - mmu_context_bmap[i + 0] = 0; - mmu_context_bmap[i + 1] = 0; - mmu_context_bmap[i + 2] = 0; - mmu_context_bmap[i + 3] = 0; - } - new_version = 1; - goto out; + mmu_context_wrap(); + goto retry; } } + if (mm->context.sparc64_ctx_val) + cpumask_clear(mm_cpumask(mm)); mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63)); new_ctx |= (tlb_context_cache & CTX_VERSION_MASK); -out: tlb_context_cache = new_ctx; mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; +out: spin_unlock(&ctx_alloc_lock); - - if (unlikely(new_version)) - smp_new_mmu_context_version(); } static int numa_enabled = 1; @@ -1495,7 +1525,7 @@ bool kern_addr_valid(unsigned long addr) if ((long)addr < 0L) { unsigned long pa = __pa(addr); - if ((addr >> max_phys_bits) != 0UL) + if ((pa >> max_phys_bits) != 0UL) return false; return pfn_valid(pa >> PAGE_SHIFT); @@ -2361,9 +2391,16 @@ void __init mem_init(void) { high_memory = __va(last_valid_pfn << PAGE_SHIFT); - register_page_bootmem_info(); free_all_bootmem(); + /* + * Must be done after boot memory is put on freelist, because here we + * might set fields in deferred struct pages that have not yet been + * initialized, and free_all_bootmem() initializes all the reserved + * deferred pages for us. + */ + register_page_bootmem_info(); + /* * Set up the zero page, mark it reserved, so that page count * is not manipulated when freeing the page from user ptes. diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index c7f2a5295b3a54599b68e4932c1c68cf2bdab99f..83a73cf5116aa15d071f83c754fbf99aa614af07 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -54,6 +54,7 @@ enum mbus_module srmmu_modtype; static unsigned int hwbug_bitmask; int vac_cache_size; +EXPORT_SYMBOL(vac_cache_size); int vac_line_size; extern struct resource sparc_iomap; diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index e20fbbafb0b04af0fa85b21188cd6c851c132e6e..84cd593117a6da9e1afc06383344477df833c4c8 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -451,7 +451,8 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss) extern void copy_tsb(unsigned long old_tsb_base, unsigned long old_tsb_size, unsigned long new_tsb_base, - unsigned long new_tsb_size); + unsigned long new_tsb_size, + unsigned long page_size_shift); unsigned long old_tsb_base = (unsigned long) old_tsb; unsigned long new_tsb_base = (unsigned long) new_tsb; @@ -459,7 +460,9 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss) old_tsb_base = __pa(old_tsb_base); new_tsb_base = __pa(new_tsb_base); } - copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size); + copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size, + tsb_index == MM_TSB_BASE ? + PAGE_SHIFT : REAL_HPAGE_SHIFT); } mm->context.tsb_block[tsb_index].tsb = new_tsb; diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S index 5d2fd6cd31896b87a3373a59cbfc3130808c6908..fcf4d27a38fb47af30d026079022d07bb803e323 100644 --- a/arch/sparc/mm/ultra.S +++ b/arch/sparc/mm/ultra.S @@ -971,11 +971,6 @@ xcall_capture: wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint retry - .globl xcall_new_mmu_context_version -xcall_new_mmu_context_version: - wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint - retry - #ifdef CONFIG_KGDB .globl xcall_kgdb_capture xcall_kgdb_capture: diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c index 17bd2e167e07edd934dfe9957c43712b21401c55..df707a8ad3117074805e138a3992a7e080d43e5a 100644 --- a/arch/sparc/power/hibernate.c +++ b/arch/sparc/power/hibernate.c @@ -35,6 +35,5 @@ void restore_processor_state(void) { struct mm_struct *mm = current->active_mm; - load_secondary_context(mm); - tsb_context_switch(mm); + tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context)); } diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index 77ceaa343fcef10956b73222f7033031035c3897..67508b249ede3dd4d3810fe7a997655f6e3f0db4 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c @@ -232,7 +232,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } if (current->mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h index 053baff036746f8360a6ff81034a6e3bcc332156..14fc4d240ab786ac175a1a77bdcaeee93ee8bf6e 100644 --- a/arch/um/include/asm/thread_info.h +++ b/arch/um/include/asm/thread_info.h @@ -63,6 +63,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_RESTORE_SIGMASK 7 #define TIF_NOTIFY_RESUME 8 #define TIF_SECCOMP 9 /* secure computing */ +#define TIF_MM_RELEASED 10 /* task MM has been released */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c index 48bae81f8dcab2febedc7238f190b985e5da4a13..6f6e7896e53f4ea1f7141b1cbbec9de266108498 100644 --- a/arch/um/kernel/initrd.c +++ b/arch/um/kernel/initrd.c @@ -14,7 +14,7 @@ static char *initrd __initdata = NULL; static int load_initrd(char *filename, void *buf, int size); -static int __init read_initrd(void) +int __init read_initrd(void) { void *area; long long size; @@ -46,8 +46,6 @@ static int __init read_initrd(void) return 0; } -__uml_postsetup(read_initrd); - static int __init uml_initrd_setup(char *line, int *add) { initrd = line; diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index e8175a8aa22c7b8c7c2f4ea2daf4addd1c8eb666..26b47deca2a0fb6efbbed8e005654ceac9132dc1 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -336,11 +336,17 @@ int __init linux_main(int argc, char **argv) return start_uml(); } +int __init __weak read_initrd(void) +{ + return 0; +} + void __init setup_arch(char **cmdline_p) { stack_protections((unsigned long) &init_thread_info); setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); mem_total_pages(physmem_size, iomem_size, highmem); + read_initrd(); paging_init(); strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index bada636d1065c5451d3e42f54820757e4cf30455..d2f5372c51d20a9a211cd0aefbcea417b456abc7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -26,6 +26,7 @@ config X86 select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_FAST_MULTIPLIER + select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE if X86_64 select ARCH_HAS_KCOV if X86_64 @@ -45,7 +46,7 @@ config X86 select ARCH_USE_CMPXCHG_LOCKREF if X86_64 select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS - select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP + select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION if X86_32 @@ -64,6 +65,7 @@ config X86 select GENERIC_CLOCKEVENTS_MIN_ADJUST select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_FIND_FIRST_BIT select GENERIC_IOMAP @@ -407,6 +409,19 @@ config GOLDFISH def_bool y depends on X86_GOLDFISH +config RETPOLINE + bool "Avoid speculative indirect branches in kernel" + default y + ---help--- + Compile kernel with the retpoline compiler options to guard against + kernel-to-user data leaks by avoiding speculative indirect + branches. Requires a compiler with -mindirect-branch=thunk-extern + support for full protection. The kernel may run slower. + + Without compiler support, at least indirect branches in assembler + code are eliminated. Since this includes the syscall entry path, + it is not entirely pointless. + if X86_32 config X86_EXTENDED_PLATFORM bool "Support for extended (non-PC) x86 platforms" @@ -2732,10 +2747,6 @@ config COMPAT_FOR_U64_ALIGNMENT config SYSVIPC_COMPAT def_bool y depends on SYSVIPC - -config KEYS_COMPAT - def_bool y - depends on KEYS endif endmenu diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 75725dc4df7a7a31c8f88c7b59c88d70529ed3de..10a7d0f0288f7b62b05071d825d667d05b6b4044 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -184,6 +184,14 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_CFLAGS += $(mflags-y) KBUILD_AFLAGS += $(mflags-y) +# Avoid indirect branches in kernel to deal with Spectre +ifdef CONFIG_RETPOLINE + RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register) + ifneq ($(RETPOLINE_CFLAGS),) + KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE + endif +endif + archscripts: scripts_basic $(Q)$(MAKE) $(build)=arch/x86/tools relocs diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index e5612f3e3b57ca7611f1e348c7f317f1416dd54a..d7ac721a8a966c94cd4fd49faade3deaa3080a57 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -16,7 +16,7 @@ #ifndef BOOT_BOOT_H #define BOOT_BOOT_H -#define STACK_SIZE 512 /* Minimum number of bytes for stack */ +#define STACK_SIZE 1024 /* Minimum number of bytes for stack */ #ifndef __ASSEMBLY__ diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 34d9e15857c3ba69681038b3ee032c0efa8126f8..4669b3a931edb1e18679050c4d6e31c8620e8e00 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -94,7 +94,7 @@ vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o quiet_cmd_check_data_rel = DATAREL $@ define cmd_check_data_rel for obj in $(filter %.o,$^); do \ - readelf -S $$obj | grep -qF .rel.local && { \ + ${CROSS_COMPILE}readelf -S $$obj | grep -qF .rel.local && { \ echo "error: $$obj has data relocations!" >&2; \ exit 1; \ } || true; \ diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index a66854d99ee1a34951faa2d426c8579bf4849bbc..6de58f1bd7ec27e9dfcba04d062e524d4c85052b 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -430,9 +430,6 @@ void choose_random_location(unsigned long input, { unsigned long random_addr, min_addr; - /* By default, keep output position unchanged. */ - *virt_addr = *output; - if (cmdline_find_option_bool("nokaslr")) { warn("KASLR disabled: 'nokaslr' on cmdline."); return; diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index b3c5a5f030ced9e6610aeb84889561a3a0f7500e..59559542f3b7b05341e411a60aa8e92367bbed4c 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -338,7 +338,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, unsigned long output_len) { const unsigned long kernel_total_size = VO__end - VO__text; - unsigned long virt_addr = (unsigned long)output; + unsigned long virt_addr = LOAD_PHYSICAL_ADDR; /* Retain x86 boot parameters pointer passed from startup_32/64. */ boot_params = rmode; @@ -397,7 +397,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, #ifndef CONFIG_RELOCATABLE if ((unsigned long)output != LOAD_PHYSICAL_ADDR) error("Destination address does not match LOAD_PHYSICAL_ADDR"); - if ((unsigned long)output != virt_addr) + if (virt_addr != LOAD_PHYSICAL_ADDR) error("Destination virtual address changed when not relocatable"); #endif @@ -409,3 +409,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, debug_putstr("done.\nBooting the kernel.\n"); return output; } + +void fortify_panic(const char *name) +{ + error("detected buffer overflow"); +} diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 1c8355eadbd199027fd12da0347f5f3f5f2dcf43..2728e1b7e4a61bb76671e11ab358f775c6db09f7 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -9,6 +9,7 @@ */ #undef CONFIG_PARAVIRT #undef CONFIG_PARAVIRT_SPINLOCKS +#undef CONFIG_PAGE_TABLE_ISOLATION #undef CONFIG_KASAN #include @@ -81,8 +82,6 @@ static inline void choose_random_location(unsigned long input, unsigned long output_size, unsigned long *virt_addr) { - /* No change from existing output location. */ - *virt_addr = *output; } #endif diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index cc3bd583dce1abc5fafe6b92417b8a713cd4cdfd..9e240fcba784b085bd55e77dc79c08d21d1a23e2 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -14,6 +14,7 @@ #include #include "ctype.h" +#include "string.h" int memcmp(const void *s1, const void *s2, size_t len) { diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h index 725e820602b1781308b863a10c105dd3d2734d31..113588ddb43f8d7e7be66283118a2f33c46fb7e1 100644 --- a/arch/x86/boot/string.h +++ b/arch/x86/boot/string.h @@ -18,4 +18,13 @@ int memcmp(const void *s1, const void *s2, size_t len); #define memset(d,c,l) __builtin_memset(d,c,l) #define memcmp __builtin_memcmp +extern int strcmp(const char *str1, const char *str2); +extern int strncmp(const char *cs, const char *ct, size_t count); +extern size_t strlen(const char *s); +extern char *strstr(const char *s1, const char *s2); +extern size_t strnlen(const char *s, size_t maxlen); +extern unsigned int atou(const char *s); +extern unsigned long long simple_strtoull(const char *cp, char **endp, + unsigned int base); + #endif /* BOOT_STRING_H */ diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index 383a6f84a060f103c7c43923ad84029e0ce2a9f1..fa8801b35e51a5f9b592cbd5214d9babc0c0ba0c 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -32,6 +32,7 @@ #include #include #include +#include /* * The following macros are used to move an (un)aligned 16 byte value to/from @@ -2734,7 +2735,7 @@ ENTRY(aesni_xts_crypt8) pxor INC, STATE4 movdqu IV, 0x30(OUTP) - call *%r11 + CALL_NOSPEC %r11 movdqu 0x00(OUTP), INC pxor INC, STATE1 @@ -2779,7 +2780,7 @@ ENTRY(aesni_xts_crypt8) _aesni_gf128mul_x_ble() movups IV, (IVP) - call *%r11 + CALL_NOSPEC %r11 movdqu 0x40(OUTP), INC pxor INC, STATE1 diff --git a/arch/x86/crypto/camellia-aesni-avx-asm_64.S b/arch/x86/crypto/camellia-aesni-avx-asm_64.S index aa9e8bd163f61b0440372bfbc26e956f71bf95d3..77ff4de2224d92c17efbb5ab56e14fac4a70d13d 100644 --- a/arch/x86/crypto/camellia-aesni-avx-asm_64.S +++ b/arch/x86/crypto/camellia-aesni-avx-asm_64.S @@ -17,6 +17,7 @@ #include #include +#include #define CAMELLIA_TABLE_BYTE_LEN 272 @@ -1224,7 +1225,7 @@ camellia_xts_crypt_16way: vpxor 14 * 16(%rax), %xmm15, %xmm14; vpxor 15 * 16(%rax), %xmm15, %xmm15; - call *%r9; + CALL_NOSPEC %r9; addq $(16 * 16), %rsp; diff --git a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S index 16186c18656dfdc67fc7433a48dcc51ee62d9bea..7384342fbb4113dbaaff124991d06962fa425a2e 100644 --- a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S +++ b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S @@ -12,6 +12,7 @@ #include #include +#include #define CAMELLIA_TABLE_BYTE_LEN 272 @@ -1337,7 +1338,7 @@ camellia_xts_crypt_32way: vpxor 14 * 32(%rax), %ymm15, %ymm14; vpxor 15 * 32(%rax), %ymm15, %ymm15; - call *%r9; + CALL_NOSPEC %r9; addq $(16 * 32), %rsp; diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S index dc05f010ca9b6fd598c444c60a488953e7725655..174fd4146043f7be019d5efa20d800e6f06ba283 100644 --- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S @@ -45,6 +45,7 @@ #include #include +#include ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction @@ -172,7 +173,7 @@ continue_block: movzxw (bufp, %rax, 2), len lea crc_array(%rip), bufp lea (bufp, len, 1), bufp - jmp *bufp + JMP_NOSPEC bufp ################################################################ ## 2a) PROCESS FULL BLOCKS: diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c index 399a29d067d6367603714633fb8c4de6ab77275a..cb91a64a99e7cdbc0422227383611378fb6b076a 100644 --- a/arch/x86/crypto/salsa20_glue.c +++ b/arch/x86/crypto/salsa20_glue.c @@ -59,13 +59,6 @@ static int encrypt(struct blkcipher_desc *desc, salsa20_ivsetup(ctx, walk.iv); - if (likely(walk.nbytes == nbytes)) - { - salsa20_encrypt_bytes(ctx, walk.src.virt.addr, - walk.dst.virt.addr, nbytes); - return blkcipher_walk_done(desc, &walk, 0); - } - while (walk.nbytes >= 64) { salsa20_encrypt_bytes(ctx, walk.src.virt.addr, walk.dst.virt.addr, diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S index 96df6a39d7e240d241d1c46077a1336d2717f80d..a2ae6891e1fcc62a41810d493a7506f1ef9f51c2 100644 --- a/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S +++ b/arch/x86/crypto/sha1-mb/sha1_mb_mgr_flush_avx2.S @@ -157,8 +157,8 @@ LABEL skip_ %I .endr # Find min length - vmovdqa _lens+0*16(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 + vmovdqu _lens+0*16(state), %xmm0 + vmovdqu _lens+1*16(state), %xmm1 vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} @@ -178,8 +178,8 @@ LABEL skip_ %I vpsubd %xmm2, %xmm0, %xmm0 vpsubd %xmm2, %xmm1, %xmm1 - vmovdqa %xmm0, _lens+0*16(state) - vmovdqa %xmm1, _lens+1*16(state) + vmovdqu %xmm0, _lens+0*16(state) + vmovdqu %xmm1, _lens+1*16(state) # "state" and "args" are the same address, arg1 # len is arg2 @@ -235,8 +235,8 @@ ENTRY(sha1_mb_mgr_get_comp_job_avx2) jc .return_null # Find min length - vmovdqa _lens(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 + vmovdqu _lens(state), %xmm0 + vmovdqu _lens+1*16(state), %xmm1 vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} diff --git a/arch/x86/crypto/sha1_avx2_x86_64_asm.S b/arch/x86/crypto/sha1_avx2_x86_64_asm.S index 1cd792db15efe760e3a6fc8b17b9a4c4e6f35233..1eab79c9ac484172a63d9cc0c4a409b7fffe7e8b 100644 --- a/arch/x86/crypto/sha1_avx2_x86_64_asm.S +++ b/arch/x86/crypto/sha1_avx2_x86_64_asm.S @@ -117,11 +117,10 @@ .set T1, REG_T1 .endm -#define K_BASE %r8 #define HASH_PTR %r9 +#define BLOCKS_CTR %r8 #define BUFFER_PTR %r10 #define BUFFER_PTR2 %r13 -#define BUFFER_END %r11 #define PRECALC_BUF %r14 #define WK_BUF %r15 @@ -205,14 +204,14 @@ * blended AVX2 and ALU instruction scheduling * 1 vector iteration per 8 rounds */ - vmovdqu ((i * 2) + PRECALC_OFFSET)(BUFFER_PTR), W_TMP + vmovdqu (i * 2)(BUFFER_PTR), W_TMP .elseif ((i & 7) == 1) - vinsertf128 $1, (((i-1) * 2)+PRECALC_OFFSET)(BUFFER_PTR2),\ + vinsertf128 $1, ((i-1) * 2)(BUFFER_PTR2),\ WY_TMP, WY_TMP .elseif ((i & 7) == 2) vpshufb YMM_SHUFB_BSWAP, WY_TMP, WY .elseif ((i & 7) == 4) - vpaddd K_XMM(K_BASE), WY, WY_TMP + vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP .elseif ((i & 7) == 7) vmovdqu WY_TMP, PRECALC_WK(i&~7) @@ -255,7 +254,7 @@ vpxor WY, WY_TMP, WY_TMP .elseif ((i & 7) == 7) vpxor WY_TMP2, WY_TMP, WY - vpaddd K_XMM(K_BASE), WY, WY_TMP + vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP vmovdqu WY_TMP, PRECALC_WK(i&~7) PRECALC_ROTATE_WY @@ -291,7 +290,7 @@ vpsrld $30, WY, WY vpor WY, WY_TMP, WY .elseif ((i & 7) == 7) - vpaddd K_XMM(K_BASE), WY, WY_TMP + vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP vmovdqu WY_TMP, PRECALC_WK(i&~7) PRECALC_ROTATE_WY @@ -446,6 +445,16 @@ .endm +/* Add constant only if (%2 > %3) condition met (uses RTA as temp) + * %1 + %2 >= %3 ? %4 : 0 + */ +.macro ADD_IF_GE a, b, c, d + mov \a, RTA + add $\d, RTA + cmp $\c, \b + cmovge RTA, \a +.endm + /* * macro implements 80 rounds of SHA-1, for multiple blocks with s/w pipelining */ @@ -463,13 +472,16 @@ lea (2*4*80+32)(%rsp), WK_BUF # Precalc WK for first 2 blocks - PRECALC_OFFSET = 0 + ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 2, 64 .set i, 0 .rept 160 PRECALC i .set i, i + 1 .endr - PRECALC_OFFSET = 128 + + /* Go to next block if needed */ + ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 3, 128 + ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128 xchg WK_BUF, PRECALC_BUF .align 32 @@ -479,8 +491,8 @@ _loop: * we use K_BASE value as a signal of a last block, * it is set below by: cmovae BUFFER_PTR, K_BASE */ - cmp K_BASE, BUFFER_PTR - jne _begin + test BLOCKS_CTR, BLOCKS_CTR + jnz _begin .align 32 jmp _end .align 32 @@ -512,10 +524,10 @@ _loop0: .set j, j+2 .endr - add $(2*64), BUFFER_PTR /* move to next odd-64-byte block */ - cmp BUFFER_END, BUFFER_PTR /* is current block the last one? */ - cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */ - + /* Update Counter */ + sub $1, BLOCKS_CTR + /* Move to the next block only if needed*/ + ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 4, 128 /* * rounds * 60,62,64,66,68 @@ -532,8 +544,8 @@ _loop0: UPDATE_HASH 12(HASH_PTR), D UPDATE_HASH 16(HASH_PTR), E - cmp K_BASE, BUFFER_PTR /* is current block the last one? */ - je _loop + test BLOCKS_CTR, BLOCKS_CTR + jz _loop mov TB, B @@ -575,10 +587,10 @@ _loop2: .set j, j+2 .endr - add $(2*64), BUFFER_PTR2 /* move to next even-64-byte block */ - - cmp BUFFER_END, BUFFER_PTR2 /* is current block the last one */ - cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */ + /* update counter */ + sub $1, BLOCKS_CTR + /* Move to the next block only if needed*/ + ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128 jmp _loop3 _loop3: @@ -641,19 +653,12 @@ _loop3: avx2_zeroupper - lea K_XMM_AR(%rip), K_BASE - + /* Setup initial values */ mov CTX, HASH_PTR mov BUF, BUFFER_PTR - lea 64(BUF), BUFFER_PTR2 - - shl $6, CNT /* mul by 64 */ - add BUF, CNT - add $64, CNT - mov CNT, BUFFER_END - cmp BUFFER_END, BUFFER_PTR2 - cmovae K_BASE, BUFFER_PTR2 + mov BUF, BUFFER_PTR2 + mov CNT, BLOCKS_CTR xmm_mov BSWAP_SHUFB_CTL(%rip), YMM_SHUFB_BSWAP diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S index a78a0694ddef37be737599dbf6ba305eb88b3cba..ec9bee661d50ba1379ec3859c2c3ed5b67ca8259 100644 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S +++ b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S @@ -155,8 +155,8 @@ LABEL skip_ %I .endr # Find min length - vmovdqa _lens+0*16(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 + vmovdqu _lens+0*16(state), %xmm0 + vmovdqu _lens+1*16(state), %xmm1 vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} @@ -176,8 +176,8 @@ LABEL skip_ %I vpsubd %xmm2, %xmm0, %xmm0 vpsubd %xmm2, %xmm1, %xmm1 - vmovdqa %xmm0, _lens+0*16(state) - vmovdqa %xmm1, _lens+1*16(state) + vmovdqu %xmm0, _lens+0*16(state) + vmovdqu %xmm1, _lens+1*16(state) # "state" and "args" are the same address, arg1 # len is arg2 @@ -234,8 +234,8 @@ ENTRY(sha256_mb_mgr_get_comp_job_avx2) jc .return_null # Find min length - vmovdqa _lens(state), %xmm0 - vmovdqa _lens+1*16(state), %xmm1 + vmovdqu _lens(state), %xmm0 + vmovdqu _lens+1*16(state), %xmm1 vpminud %xmm1, %xmm0, %xmm2 # xmm2 has {D,C,B,A} vpalignr $8, %xmm2, %xmm3, %xmm3 # xmm3 has {x,x,D,C} diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index edba8606b99a0daa86853e6869553c6854b0efe3..bdc9aeaf2e4561fda8d5657264ab2b04fb9713e8 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -45,6 +45,7 @@ #include #include #include +#include .section .entry.text, "ax" @@ -260,7 +261,7 @@ ENTRY(ret_from_fork) /* kernel thread */ 1: movl %edi, %eax - call *%ebx + CALL_NOSPEC %ebx /* * A kernel thread is allowed to return here after successfully * calling do_execve(). Exit to userspace to complete the execve() @@ -984,7 +985,8 @@ trace: movl 0x4(%ebp), %edx subl $MCOUNT_INSN_SIZE, %eax - call *ftrace_trace_function + movl ftrace_trace_function, %ecx + CALL_NOSPEC %ecx popl %edx popl %ecx @@ -1020,7 +1022,7 @@ return_to_handler: movl %eax, %ecx popl %edx popl %eax - jmp *%ecx + JMP_NOSPEC %ecx #endif #ifdef CONFIG_TRACING @@ -1062,7 +1064,7 @@ error_code: movl %ecx, %es TRACE_IRQS_OFF movl %esp, %eax # pt_regs pointer - call *%edi + CALL_NOSPEC %edi jmp ret_from_exception END(page_fault) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index ef766a358b37dd355e8d5d75c10a61d47a83e04f..b9c901ce6582a8974356154d1fd935b136333e78 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include /* Avoid __ASSEMBLER__'ifying just for this. */ @@ -146,6 +148,7 @@ ENTRY(entry_SYSCALL_64) * it is too small to ever cause noticeable irq latency. */ SWAPGS_UNSAFE_STACK + SWITCH_KERNEL_CR3_NO_STACK /* * A hypervisor implementation might want to use a label * after the swapgs, so that it can do the swapgs @@ -206,7 +209,12 @@ entry_SYSCALL_64_fastpath: * It might end up jumping to the slow path. If it jumps, RAX * and all argument registers are clobbered. */ +#ifdef CONFIG_RETPOLINE + movq sys_call_table(, %rax, 8), %rax + call __x86_indirect_thunk_rax +#else call *sys_call_table(, %rax, 8) +#endif .Lentry_SYSCALL_64_after_fastpath_call: movq %rax, RAX(%rsp) @@ -228,6 +236,14 @@ entry_SYSCALL_64_fastpath: movq RIP(%rsp), %rcx movq EFLAGS(%rsp), %r11 RESTORE_C_REGS_EXCEPT_RCX_R11 + /* + * This opens a window where we have a user CR3, but are + * running in the kernel. This makes using the CS + * register useless for telling whether or not we need to + * switch CR3 in NMIs. Normal interrupts are OK because + * they are off here. + */ + SWITCH_USER_CR3 movq RSP(%rsp), %rsp USERGS_SYSRET64 @@ -323,10 +339,26 @@ return_from_SYSCALL_64: syscall_return_via_sysret: /* rcx and r11 are already restored (see code above) */ RESTORE_C_REGS_EXCEPT_RCX_R11 + /* + * This opens a window where we have a user CR3, but are + * running in the kernel. This makes using the CS + * register useless for telling whether or not we need to + * switch CR3 in NMIs. Normal interrupts are OK because + * they are off here. + */ + SWITCH_USER_CR3 movq RSP(%rsp), %rsp USERGS_SYSRET64 opportunistic_sysret_failed: + /* + * This opens a window where we have a user CR3, but are + * running in the kernel. This makes using the CS + * register useless for telling whether or not we need to + * switch CR3 in NMIs. Normal interrupts are OK because + * they are off here. + */ + SWITCH_USER_CR3 SWAPGS jmp restore_c_regs_and_iret END(entry_SYSCALL_64) @@ -354,7 +386,7 @@ ENTRY(stub_ptregs_64) jmp entry_SYSCALL64_slow_path 1: - jmp *%rax /* Called from C */ + JMP_NOSPEC %rax /* Called from C */ END(stub_ptregs_64) .macro ptregs_stub func @@ -424,13 +456,14 @@ ENTRY(ret_from_fork) movq %rsp, %rdi call syscall_return_slowpath /* returns with IRQs disabled */ TRACE_IRQS_ON /* user mode is traced as IRQS on */ + SWITCH_USER_CR3 SWAPGS jmp restore_regs_and_iret 1: /* kernel thread */ movq %r12, %rdi - call *%rbx + CALL_NOSPEC %rbx /* * A kernel thread is allowed to return here after successfully * calling do_execve(). Exit to userspace to complete the execve() @@ -478,6 +511,7 @@ END(irq_entries_start) * tracking that we're in kernel mode. */ SWAPGS + SWITCH_KERNEL_CR3 /* * We need to tell lockdep that IRQs are off. We can't do this until @@ -535,6 +569,7 @@ GLOBAL(retint_user) mov %rsp,%rdi call prepare_exit_to_usermode TRACE_IRQS_IRETQ + SWITCH_USER_CR3 SWAPGS jmp restore_regs_and_iret @@ -612,6 +647,7 @@ native_irq_return_ldt: pushq %rdi /* Stash user RDI */ SWAPGS + SWITCH_KERNEL_CR3 movq PER_CPU_VAR(espfix_waddr), %rdi movq %rax, (0*8)(%rdi) /* user RAX */ movq (1*8)(%rsp), %rax /* user RIP */ @@ -638,6 +674,7 @@ native_irq_return_ldt: * still points to an RO alias of the ESPFIX stack. */ orq PER_CPU_VAR(espfix_stack), %rax + SWITCH_USER_CR3 SWAPGS movq %rax, %rsp @@ -1022,7 +1059,11 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vec /* * Save all registers in pt_regs, and switch gs if needed. * Use slow, but surefire "are we in kernel?" check. - * Return: ebx=0: need swapgs on exit, ebx=1: otherwise + * + * Return: ebx=0: needs swapgs but not SWITCH_USER_CR3 in paranoid_exit + * ebx=1: needs neither swapgs nor SWITCH_USER_CR3 in paranoid_exit + * ebx=2: needs both swapgs and SWITCH_USER_CR3 in paranoid_exit + * ebx=3: needs SWITCH_USER_CR3 but not swapgs in paranoid_exit */ ENTRY(paranoid_entry) cld @@ -1035,7 +1076,26 @@ ENTRY(paranoid_entry) js 1f /* negative -> in kernel */ SWAPGS xorl %ebx, %ebx -1: ret +1: +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* + * We might have come in between a swapgs and a SWITCH_KERNEL_CR3 + * on entry, or between a SWITCH_USER_CR3 and a swapgs on exit. + * Do a conditional SWITCH_KERNEL_CR3: this could safely be done + * unconditionally, but we need to find out whether the reverse + * should be done on return (conveyed to paranoid_exit in %ebx). + */ + ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER + testl $KAISER_SHADOW_PGD_OFFSET, %eax + jz 2f + orl $2, %ebx + andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax + /* If PCID enabled, set X86_CR3_PCID_NOFLUSH_BIT */ + ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID + movq %rax, %cr3 +2: +#endif + ret END(paranoid_entry) /* @@ -1048,19 +1108,26 @@ END(paranoid_entry) * be complicated. Fortunately, we there's no good reason * to try to handle preemption here. * - * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) + * On entry: ebx=0: needs swapgs but not SWITCH_USER_CR3 + * ebx=1: needs neither swapgs nor SWITCH_USER_CR3 + * ebx=2: needs both swapgs and SWITCH_USER_CR3 + * ebx=3: needs SWITCH_USER_CR3 but not swapgs */ ENTRY(paranoid_exit) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF_DEBUG - testl %ebx, %ebx /* swapgs needed? */ + TRACE_IRQS_IRETQ_DEBUG +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* No ALTERNATIVE for X86_FEATURE_KAISER: paranoid_entry sets %ebx */ + testl $2, %ebx /* SWITCH_USER_CR3 needed? */ + jz paranoid_exit_no_switch + SWITCH_USER_CR3 +paranoid_exit_no_switch: +#endif + testl $1, %ebx /* swapgs needed? */ jnz paranoid_exit_no_swapgs - TRACE_IRQS_IRETQ SWAPGS_UNSAFE_STACK - jmp paranoid_exit_restore paranoid_exit_no_swapgs: - TRACE_IRQS_IRETQ_DEBUG -paranoid_exit_restore: RESTORE_EXTRA_REGS RESTORE_C_REGS REMOVE_PT_GPREGS_FROM_STACK 8 @@ -1075,6 +1142,13 @@ ENTRY(error_entry) cld SAVE_C_REGS 8 SAVE_EXTRA_REGS 8 + /* + * error_entry() always returns with a kernel gsbase and + * CR3. We must also have a kernel CR3/gsbase before + * calling TRACE_IRQS_*. Just unconditionally switch to + * the kernel CR3 here. + */ + SWITCH_KERNEL_CR3 xorl %ebx, %ebx testb $3, CS+8(%rsp) jz .Lerror_kernelspace @@ -1215,6 +1289,8 @@ ENTRY(nmi) * other IST entries. */ + ASM_CLAC + /* Use %rdx as our temp variable throughout */ pushq %rdx @@ -1233,6 +1309,10 @@ ENTRY(nmi) */ SWAPGS_UNSAFE_STACK + /* + * percpu variables are mapped with user CR3, so no need + * to switch CR3 here. + */ cld movq %rsp, %rdx movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp @@ -1266,12 +1346,34 @@ ENTRY(nmi) movq %rsp, %rdi movq $-1, %rsi +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* Unconditionally use kernel CR3 for do_nmi() */ + /* %rax is saved above, so OK to clobber here */ + ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER + /* If PCID enabled, NOFLUSH now and NOFLUSH on return */ + ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID + pushq %rax + /* mask off "user" bit of pgd address and 12 PCID bits: */ + andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax + movq %rax, %cr3 +2: +#endif call do_nmi +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* + * Unconditionally restore CR3. I know we return to + * kernel code that needs user CR3, but do we ever return + * to "user mode" where we need the kernel CR3? + */ + ALTERNATIVE "", "popq %rax; movq %rax, %cr3", X86_FEATURE_KAISER +#endif + /* * Return back to user mode. We must *not* do the normal exit - * work, because we don't want to enable interrupts. Fortunately, - * do_nmi doesn't modify pt_regs. + * work, because we don't want to enable interrupts. Do not + * switch to user CR3: we might be going back to kernel code + * that had a user CR3 set. */ SWAPGS jmp restore_c_regs_and_iret @@ -1468,22 +1570,55 @@ end_repeat_nmi: ALLOC_PT_GPREGS_ON_STACK /* - * Use paranoid_entry to handle SWAPGS, but no need to use paranoid_exit - * as we should not be calling schedule in NMI context. - * Even with normal interrupts enabled. An NMI should not be - * setting NEED_RESCHED or anything that normal interrupts and - * exceptions might do. + * Use the same approach as paranoid_entry to handle SWAPGS, but + * without CR3 handling since we do that differently in NMIs. No + * need to use paranoid_exit as we should not be calling schedule + * in NMI context. Even with normal interrupts enabled. An NMI + * should not be setting NEED_RESCHED or anything that normal + * interrupts and exceptions might do. */ - call paranoid_entry - - /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ + cld + SAVE_C_REGS + SAVE_EXTRA_REGS + movl $1, %ebx + movl $MSR_GS_BASE, %ecx + rdmsr + testl %edx, %edx + js 1f /* negative -> in kernel */ + SWAPGS + xorl %ebx, %ebx +1: movq %rsp, %rdi movq $-1, %rsi +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* Unconditionally use kernel CR3 for do_nmi() */ + /* %rax is saved above, so OK to clobber here */ + ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER + /* If PCID enabled, NOFLUSH now and NOFLUSH on return */ + ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID + pushq %rax + /* mask off "user" bit of pgd address and 12 PCID bits: */ + andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax + movq %rax, %cr3 +2: +#endif + + /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ call do_nmi +#ifdef CONFIG_PAGE_TABLE_ISOLATION + /* + * Unconditionally restore CR3. We might be returning to + * kernel code that needs user CR3, like just just before + * a sysret. + */ + ALTERNATIVE "", "popq %rax; movq %rax, %cr3", X86_FEATURE_KAISER +#endif + testl %ebx, %ebx /* swapgs needed? */ jnz nmi_restore nmi_swapgs: + /* We fixed up CR3 above, so no need to switch it here */ SWAPGS_UNSAFE_STACK nmi_restore: RESTORE_EXTRA_REGS diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index e1721dafbcb13fab9230cc20d598b18ebef8306b..d76a97653980145dc982c6abbd3ac541dc1050bb 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -48,6 +50,7 @@ ENTRY(entry_SYSENTER_compat) /* Interrupts are off on entry. */ SWAPGS_UNSAFE_STACK + SWITCH_KERNEL_CR3_NO_STACK movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp /* @@ -184,6 +187,7 @@ ENDPROC(entry_SYSENTER_compat) ENTRY(entry_SYSCALL_compat) /* Interrupts are off on entry. */ SWAPGS_UNSAFE_STACK + SWITCH_KERNEL_CR3_NO_STACK /* Stash user ESP and switch to the kernel stack. */ movl %esp, %r8d @@ -259,6 +263,7 @@ sysret32_from_system_call: xorq %r8, %r8 xorq %r9, %r9 xorq %r10, %r10 + SWITCH_USER_CR3 movq RSP-ORIG_RAX(%rsp), %rsp swapgs sysretl @@ -297,7 +302,7 @@ ENTRY(entry_INT80_compat) PARAVIRT_ADJUST_EXCEPTION_FRAME ASM_CLAC /* Do this early to minimize exposure */ SWAPGS - + SWITCH_KERNEL_CR3_NO_STACK /* * User tracing code (ptrace or signal handlers) might assume that * the saved RAX contains a 32-bit number when we're invoking a 32-bit @@ -338,6 +343,7 @@ ENTRY(entry_INT80_compat) /* Go back to user mode. */ TRACE_IRQS_ON + SWITCH_USER_CR3 SWAPGS jmp restore_regs_and_iret END(entry_INT80_compat) diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 636c4b341f36a93975c1ab732f8dfc5fb66bf4ba..6bb7e92c6d5058dc17e4137fa5861dd0b2e0d2da 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -66,6 +66,11 @@ static int __init vsyscall_setup(char *str) } early_param("vsyscall", vsyscall_setup); +bool vsyscall_enabled(void) +{ + return vsyscall_mode != NONE; +} + static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, const char *message) { diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 38623e21981677a56eb673f3ce9f68c484631252..9604b2574d6c6532ae5acac4f6809c4faaed6ae4 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -505,6 +505,10 @@ int x86_pmu_hw_config(struct perf_event *event) if (event->attr.precise_ip > precise) return -EOPNOTSUPP; + + /* There's no sense in having PEBS for non sampling events: */ + if (!is_sampling_event(event)) + return -EINVAL; } /* * check that PEBS LBR correction does not conflict with diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index cb8522290e6a3f6dc3b5baacfc618d0ee8db65e3..f0f197f459b56b1d9af61f0781708d95713dc9c5 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -431,11 +431,11 @@ static __initconst const u64 skl_hw_cache_event_ids [ C(DTLB) ] = { [ C(OP_READ) ] = { [ C(RESULT_ACCESS) ] = 0x81d0, /* MEM_INST_RETIRED.ALL_LOADS */ - [ C(RESULT_MISS) ] = 0x608, /* DTLB_LOAD_MISSES.WALK_COMPLETED */ + [ C(RESULT_MISS) ] = 0xe08, /* DTLB_LOAD_MISSES.WALK_COMPLETED */ }, [ C(OP_WRITE) ] = { [ C(RESULT_ACCESS) ] = 0x82d0, /* MEM_INST_RETIRED.ALL_STORES */ - [ C(RESULT_MISS) ] = 0x649, /* DTLB_STORE_MISSES.WALK_COMPLETED */ + [ C(RESULT_MISS) ] = 0xe49, /* DTLB_STORE_MISSES.WALK_COMPLETED */ }, [ C(OP_PREFETCH) ] = { [ C(RESULT_ACCESS) ] = 0x0, @@ -3164,13 +3164,16 @@ static void intel_pmu_cpu_starting(int cpu) if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) { for_each_cpu(i, topology_sibling_cpumask(cpu)) { + struct cpu_hw_events *sibling; struct intel_excl_cntrs *c; - c = per_cpu(cpu_hw_events, i).excl_cntrs; + sibling = &per_cpu(cpu_hw_events, i); + c = sibling->excl_cntrs; if (c && c->core_id == core_id) { cpuc->kfree_on_online[1] = cpuc->excl_cntrs; cpuc->excl_cntrs = c; - cpuc->excl_thread_id = 1; + if (!sibling->excl_thread_id) + cpuc->excl_thread_id = 1; break; } } @@ -3975,7 +3978,7 @@ __init int intel_pmu_init(void) x86_pmu.num_counters, INTEL_PMC_MAX_GENERIC); x86_pmu.num_counters = INTEL_PMC_MAX_GENERIC; } - x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1; + x86_pmu.intel_ctrl = (1ULL << x86_pmu.num_counters) - 1; if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED) { WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!", diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index fec8a461bdef6da49c0e7f46c655f235e7fc1275..1076c9a77292d77e5dbb34adbd5ce526121daa73 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -434,6 +434,7 @@ static struct pmu cstate_core_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, }; static struct pmu cstate_pkg_pmu = { @@ -447,6 +448,7 @@ static struct pmu cstate_pkg_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, }; static const struct cstate_model nhm_cstates __initconst = { diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index be202390bbd37b00106864123a647786497ce2cd..8e7a3f1df3a5dc298d45de5543e5ca11dc30c9a9 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -2,11 +2,15 @@ #include #include +#include #include #include #include "../perf_event.h" +static +DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct debug_store, cpu_debug_store); + /* The size of a BTS record in bytes: */ #define BTS_RECORD_SIZE 24 @@ -268,6 +272,39 @@ void fini_debug_store_on_cpu(int cpu) static DEFINE_PER_CPU(void *, insn_buffer); +static void *dsalloc(size_t size, gfp_t flags, int node) +{ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + unsigned int order = get_order(size); + struct page *page; + unsigned long addr; + + page = __alloc_pages_node(node, flags | __GFP_ZERO, order); + if (!page) + return NULL; + addr = (unsigned long)page_address(page); + if (kaiser_add_mapping(addr, size, __PAGE_KERNEL) < 0) { + __free_pages(page, order); + addr = 0; + } + return (void *)addr; +#else + return kmalloc_node(size, flags | __GFP_ZERO, node); +#endif +} + +static void dsfree(const void *buffer, size_t size) +{ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + if (!buffer) + return; + kaiser_remove_mapping((unsigned long)buffer, size); + free_pages((unsigned long)buffer, get_order(size)); +#else + kfree(buffer); +#endif +} + static int alloc_pebs_buffer(int cpu) { struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; @@ -278,7 +315,7 @@ static int alloc_pebs_buffer(int cpu) if (!x86_pmu.pebs) return 0; - buffer = kzalloc_node(x86_pmu.pebs_buffer_size, GFP_KERNEL, node); + buffer = dsalloc(x86_pmu.pebs_buffer_size, GFP_KERNEL, node); if (unlikely(!buffer)) return -ENOMEM; @@ -289,7 +326,7 @@ static int alloc_pebs_buffer(int cpu) if (x86_pmu.intel_cap.pebs_format < 2) { ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node); if (!ibuffer) { - kfree(buffer); + dsfree(buffer, x86_pmu.pebs_buffer_size); return -ENOMEM; } per_cpu(insn_buffer, cpu) = ibuffer; @@ -315,7 +352,8 @@ static void release_pebs_buffer(int cpu) kfree(per_cpu(insn_buffer, cpu)); per_cpu(insn_buffer, cpu) = NULL; - kfree((void *)(unsigned long)ds->pebs_buffer_base); + dsfree((void *)(unsigned long)ds->pebs_buffer_base, + x86_pmu.pebs_buffer_size); ds->pebs_buffer_base = 0; } @@ -329,7 +367,7 @@ static int alloc_bts_buffer(int cpu) if (!x86_pmu.bts) return 0; - buffer = kzalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, node); + buffer = dsalloc(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_NOWARN, node); if (unlikely(!buffer)) { WARN_ONCE(1, "%s: BTS buffer allocation failure\n", __func__); return -ENOMEM; @@ -355,19 +393,15 @@ static void release_bts_buffer(int cpu) if (!ds || !x86_pmu.bts) return; - kfree((void *)(unsigned long)ds->bts_buffer_base); + dsfree((void *)(unsigned long)ds->bts_buffer_base, BTS_BUFFER_SIZE); ds->bts_buffer_base = 0; } static int alloc_ds_buffer(int cpu) { - int node = cpu_to_node(cpu); - struct debug_store *ds; - - ds = kzalloc_node(sizeof(*ds), GFP_KERNEL, node); - if (unlikely(!ds)) - return -ENOMEM; + struct debug_store *ds = per_cpu_ptr(&cpu_debug_store, cpu); + memset(ds, 0, sizeof(*ds)); per_cpu(cpu_hw_events, cpu).ds = ds; return 0; @@ -381,7 +415,6 @@ static void release_ds_buffer(int cpu) return; per_cpu(cpu_hw_events, cpu).ds = NULL; - kfree(ds); } void release_ds_buffers(void) @@ -1389,9 +1422,13 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) continue; /* log dropped samples number */ - if (error[bit]) + if (error[bit]) { perf_log_lost_samples(event, error[bit]); + if (perf_event_account_interrupt(event)) + x86_pmu_stop(event, 0); + } + if (counts[bit]) { __intel_pmu_pebs_event(event, iregs, base, top, bit, counts[bit]); diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index c5047b8f777b27e918b3c5e0982dd274cf652dd0..df60b58691e7c29b395c3603f696e056ddfa6ab2 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -106,18 +106,24 @@ static struct attribute_group pt_cap_group = { }; PMU_FORMAT_ATTR(cyc, "config:1" ); +PMU_FORMAT_ATTR(pwr_evt, "config:4" ); +PMU_FORMAT_ATTR(fup_on_ptw, "config:5" ); PMU_FORMAT_ATTR(mtc, "config:9" ); PMU_FORMAT_ATTR(tsc, "config:10" ); PMU_FORMAT_ATTR(noretcomp, "config:11" ); +PMU_FORMAT_ATTR(ptw, "config:12" ); PMU_FORMAT_ATTR(mtc_period, "config:14-17" ); PMU_FORMAT_ATTR(cyc_thresh, "config:19-22" ); PMU_FORMAT_ATTR(psb_period, "config:24-27" ); static struct attribute *pt_formats_attr[] = { &format_attr_cyc.attr, + &format_attr_pwr_evt.attr, + &format_attr_fup_on_ptw.attr, &format_attr_mtc.attr, &format_attr_tsc.attr, &format_attr_noretcomp.attr, + &format_attr_ptw.attr, &format_attr_mtc_period.attr, &format_attr_cyc_thresh.attr, &format_attr_psb_period.attr, diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c index 0a535cea8ff31adf6e06fc32ff763d423a73ab74..4c1b7ea185415930f2a4811ac1b57122c5c42387 100644 --- a/arch/x86/events/intel/rapl.c +++ b/arch/x86/events/intel/rapl.c @@ -161,7 +161,13 @@ static u64 rapl_timer_ms; static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu) { - return rapl_pmus->pmus[topology_logical_package_id(cpu)]; + unsigned int pkgid = topology_logical_package_id(cpu); + + /* + * The unsigned check also catches the '-1' return value for non + * existent mappings in the topology map. + */ + return pkgid < rapl_pmus->maxpkg ? rapl_pmus->pmus[pkgid] : NULL; } static inline u64 rapl_read_counter(struct perf_event *event) @@ -402,6 +408,8 @@ static int rapl_pmu_event_init(struct perf_event *event) /* must be done before validate_group */ pmu = cpu_to_rapl_pmu(event->cpu); + if (!pmu) + return -EINVAL; event->cpu = pmu->cpu; event->pmu_private = pmu; event->hw.event_base = msr; @@ -585,6 +593,19 @@ static int rapl_cpu_online(unsigned int cpu) struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); int target; + if (!pmu) { + pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); + if (!pmu) + return -ENOMEM; + + raw_spin_lock_init(&pmu->lock); + INIT_LIST_HEAD(&pmu->active_list); + pmu->pmu = &rapl_pmus->pmu; + pmu->timer_interval = ms_to_ktime(rapl_timer_ms); + rapl_hrtimer_init(pmu); + + rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu; + } /* * Check if there is an online cpu in the package which collects rapl * events already. @@ -598,27 +619,6 @@ static int rapl_cpu_online(unsigned int cpu) return 0; } -static int rapl_cpu_prepare(unsigned int cpu) -{ - struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); - - if (pmu) - return 0; - - pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); - if (!pmu) - return -ENOMEM; - - raw_spin_lock_init(&pmu->lock); - INIT_LIST_HEAD(&pmu->active_list); - pmu->pmu = &rapl_pmus->pmu; - pmu->timer_interval = ms_to_ktime(rapl_timer_ms); - pmu->cpu = -1; - rapl_hrtimer_init(pmu); - rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu; - return 0; -} - static int rapl_check_hw_unit(bool apply_quirk) { u64 msr_rapl_power_unit_bits; @@ -697,6 +697,7 @@ static int __init init_rapl_pmus(void) rapl_pmus->pmu.start = rapl_pmu_event_start; rapl_pmus->pmu.stop = rapl_pmu_event_stop; rapl_pmus->pmu.read = rapl_pmu_event_read; + rapl_pmus->pmu.module = THIS_MODULE; return 0; } @@ -759,7 +760,7 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = { X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, hsw_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, hsw_rapl_init), - X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, hsx_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsw_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init), @@ -803,28 +804,21 @@ static int __init rapl_pmu_init(void) * Install callbacks. Core will call them for each online cpu. */ - ret = cpuhp_setup_state(CPUHP_PERF_X86_RAPL_PREP, "PERF_X86_RAPL_PREP", - rapl_cpu_prepare, NULL); - if (ret) - goto out; - ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE, "AP_PERF_X86_RAPL_ONLINE", rapl_cpu_online, rapl_cpu_offline); if (ret) - goto out1; + goto out; ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1); if (ret) - goto out2; + goto out1; rapl_advertise(); return 0; -out2: - cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE); out1: - cpuhp_remove_state(CPUHP_PERF_X86_RAPL_PREP); + cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE); out: pr_warn("Initialization failed (%d), disabled\n", ret); cleanup_rapl_pmus(); @@ -835,7 +829,6 @@ module_init(rapl_pmu_init); static void __exit intel_rapl_exit(void) { cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE); - cpuhp_remove_state_nocalls(CPUHP_PERF_X86_RAPL_PREP); perf_pmu_unregister(&rapl_pmus->pmu); cleanup_rapl_pmus(); } diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 19d646a783fd6c71373294fb8e16d626c2afe5fc..aec6cc925af809d3a11e749c0ba9d63f995e15d7 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -733,6 +733,7 @@ static int uncore_pmu_register(struct intel_uncore_pmu *pmu) .start = uncore_pmu_event_start, .stop = uncore_pmu_event_stop, .read = uncore_pmu_event_read, + .module = THIS_MODULE, }; } else { pmu->pmu = *pmu->type->pmu; diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index 272427700d48deebdbcb582b1bd4af143e44a58c..afe8024e9e95e6a2326bcfcf4c5e6aa964fd7e48 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -2686,7 +2686,7 @@ static struct intel_uncore_type *hswep_msr_uncores[] = { void hswep_uncore_cpu_init(void) { - int pkg = topology_phys_to_logical_pkg(0); + int pkg = boot_cpu_data.logical_proc_id; if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h index e7636bac7372d41d4b8077f4d7df7d81de32ee32..6c98821fef5ed9f0b953141a905b99893663652e 100644 --- a/arch/x86/include/asm/alternative-asm.h +++ b/arch/x86/include/asm/alternative-asm.h @@ -62,8 +62,10 @@ #define new_len2 145f-144f /* - * max without conditionals. Idea adapted from: + * gas compatible max based on the idea from: * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax + * + * The additional "-" is needed because gas uses a "true" value of -1. */ #define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b))))) diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 1b020381ab38965ae2a80d2d86df32c66c92e2e8..deca9b9c7923dafdcc31cb1b0abab54194af63a6 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -103,12 +103,12 @@ static inline int alternatives_text_reserved(void *start, void *end) alt_end_marker ":\n" /* - * max without conditionals. Idea adapted from: + * gas compatible max based on the idea from: * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax * - * The additional "-" is needed because gas works with s32s. + * The additional "-" is needed because gas uses a "true" value of -1. */ -#define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))" +#define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") < (" b ")))))" /* * Pad the second replacement alternative with additional NOPs if it is @@ -139,7 +139,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ".popsection\n" \ ".pushsection .altinstr_replacement, \"ax\"\n" \ ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ - ".popsection" + ".popsection\n" #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ OLDINSTR_2(oldinstr, 1, 2) \ @@ -150,7 +150,7 @@ static inline int alternatives_text_reserved(void *start, void *end) ".pushsection .altinstr_replacement, \"ax\"\n" \ ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ - ".popsection" + ".popsection\n" /* * Alternative instructions for different CPU types or capabilities. diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h index 44b8762fa0c784b44a44d22e390af48ce2dcb5d0..b15aa4083dfd47bd23af35c8f98afd67f079061e 100644 --- a/arch/x86/include/asm/asm-prototypes.h +++ b/arch/x86/include/asm/asm-prototypes.h @@ -10,7 +10,32 @@ #include #include #include +#include #ifndef CONFIG_X86_CMPXCHG64 extern void cmpxchg8b_emu(void); #endif + +#ifdef CONFIG_RETPOLINE +#ifdef CONFIG_X86_32 +#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_e ## reg(void); +#else +#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_r ## reg(void); +INDIRECT_THUNK(8) +INDIRECT_THUNK(9) +INDIRECT_THUNK(10) +INDIRECT_THUNK(11) +INDIRECT_THUNK(12) +INDIRECT_THUNK(13) +INDIRECT_THUNK(14) +INDIRECT_THUNK(15) +#endif +INDIRECT_THUNK(ax) +INDIRECT_THUNK(bx) +INDIRECT_THUNK(cx) +INDIRECT_THUNK(dx) +INDIRECT_THUNK(si) +INDIRECT_THUNK(di) +INDIRECT_THUNK(bp) +INDIRECT_THUNK(sp) +#endif /* CONFIG_RETPOLINE */ diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 7acb51c49fec46220052c94c5f6a4a308f4a1fc9..00523524edbfe3b0422be6a0a1eb543bb895102f 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -125,4 +125,15 @@ /* For C file, we already have NOKPROBE_SYMBOL macro */ #endif +#ifndef __ASSEMBLY__ +/* + * This output constraint should be used for any inline asm which has a "call" + * instruction. Otherwise the asm may be inserted before the frame pointer + * gets set up by the containing function. If you forget to do this, objtool + * may print a "call without frame pointer save/setup" warning. + */ +register unsigned long current_stack_pointer asm(_ASM_SP); +#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer) +#endif + #endif /* _ASM_X86_ASM_H */ diff --git a/arch/x86/include/asm/cmdline.h b/arch/x86/include/asm/cmdline.h index e01f7f7ccb0c5711db4f1fe130938cee36169965..84ae170bc3d0cd73cfa7d08fa6f730bd3106e4ea 100644 --- a/arch/x86/include/asm/cmdline.h +++ b/arch/x86/include/asm/cmdline.h @@ -2,5 +2,7 @@ #define _ASM_X86_CMDLINE_H int cmdline_find_option_bool(const char *cmdline_ptr, const char *option); +int cmdline_find_option(const char *cmdline_ptr, const char *option, + char *buffer, int bufsize); #endif /* _ASM_X86_CMDLINE_H */ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 1d2b69fc0ceb15baa25f6022b35ace5b55c11de2..9ea67a04ff4f4e459046972e68100315cfb47d86 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -135,6 +135,8 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; set_bit(bit, (unsigned long *)cpu_caps_set); \ } while (0) +#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit) + #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_X86_FAST_FEATURE_TESTS) /* * Static testing of CPU features. Used the same as boot_cpu_has(). diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index ed10b5bf9b93d73b3102263c7b025af6fa9b47e9..4467568a531b524cb99d1264a6713a12f5810cbb 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -189,14 +189,21 @@ #define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ #define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ +#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 4) /* Effectively INVPCID && CR4.PCIDE=1 */ #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ +#define X86_FEATURE_RETPOLINE ( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */ +#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */ + #define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ #define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ +/* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */ +#define X86_FEATURE_KAISER ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */ + /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ #define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ @@ -312,5 +319,8 @@ #define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ #define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ #define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ +#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */ +#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ +#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 12080d87da3b189f421d421c5d6a3cca5dc83014..2ed5a2b3f8f7e86976118ac217199f20d9f17d7d 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -43,7 +43,7 @@ struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; } __attribute__((aligned(PAGE_SIZE))); -DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page); +DECLARE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(struct gdt_page, gdt_page); static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) { diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h index 85599ad4d0247863cef655d02b9a4b3f83c77fb7..21c5ac15657b25ba4598eea357671340332f1959 100644 --- a/arch/x86/include/asm/disabled-features.h +++ b/arch/x86/include/asm/disabled-features.h @@ -21,11 +21,13 @@ # define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31)) # define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) # define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) +# define DISABLE_PCID 0 #else # define DISABLE_VME 0 # define DISABLE_K6_MTRR 0 # define DISABLE_CYRIX_ARR 0 # define DISABLE_CENTAUR_MCR 0 +# define DISABLE_PCID (1<<(X86_FEATURE_PCID & 31)) #endif /* CONFIG_X86_64 */ #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS @@ -43,7 +45,7 @@ #define DISABLED_MASK1 0 #define DISABLED_MASK2 0 #define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) -#define DISABLED_MASK4 0 +#define DISABLED_MASK4 (DISABLE_PCID) #define DISABLED_MASK5 0 #define DISABLED_MASK6 0 #define DISABLED_MASK7 0 diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 94aad6364b4742deebb242f4e2469094501adacc..7bcd138c3aa98dcb9f24619174a0147ddb49e9f2 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -204,6 +204,7 @@ void set_personality_ia32(bool); #define ELF_CORE_COPY_REGS(pr_reg, regs) \ do { \ + unsigned long base; \ unsigned v; \ (pr_reg)[0] = (regs)->r15; \ (pr_reg)[1] = (regs)->r14; \ @@ -226,8 +227,8 @@ do { \ (pr_reg)[18] = (regs)->flags; \ (pr_reg)[19] = (regs)->sp; \ (pr_reg)[20] = (regs)->ss; \ - (pr_reg)[21] = current->thread.fsbase; \ - (pr_reg)[22] = current->thread.gsbase; \ + rdmsrl(MSR_FS_BASE, base); (pr_reg)[21] = base; \ + rdmsrl(MSR_KERNEL_GS_BASE, base); (pr_reg)[22] = base; \ asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \ asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \ asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \ @@ -245,12 +246,13 @@ extern int force_personality32; #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE 4096 -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +/* + * This is the base location for PIE (ET_DYN with INTERP) loads. On + * 64-bit, this is above 4GB to leave the entire 32-bit address + * space open for things that want to use the area for 32-bit pointers. + */ +#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \ + (TASK_SIZE / 3 * 2)) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 59405a248fc2488c66259e5669c1f857b13954aa..9b76cd331990159dcdd042e10f90946f7440adba 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -22,8 +22,8 @@ typedef struct { #ifdef CONFIG_SMP unsigned int irq_resched_count; unsigned int irq_call_count; - unsigned int irq_tlb_count; #endif + unsigned int irq_tlb_count; #ifdef CONFIG_X86_THERMAL_VECTOR unsigned int irq_thermal_count; #endif diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index b90e1053049bdd17ad36989315db8ac1b3ccc973..0817d63bce41e378743d4044662b0a6aa547379c 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -178,7 +178,7 @@ extern char irq_entries_start[]; #define VECTOR_RETRIGGERED ((void *)~0UL) typedef struct irq_desc* vector_irq_t[NR_VECTORS]; -DECLARE_PER_CPU(vector_irq_t, vector_irq); +DECLARE_PER_CPU_USER_MAPPED(vector_irq_t, vector_irq); #endif /* !ASSEMBLY_ */ diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index d34bd370074b46662e5a96014ed4cd5b521f6045..6c5020163db0b342f6fc01d2f32539ad1cc4f058 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -304,13 +304,13 @@ static inline unsigned type in##bwl##_p(int port) \ static inline void outs##bwl(int port, const void *addr, unsigned long count) \ { \ asm volatile("rep; outs" #bwl \ - : "+S"(addr), "+c"(count) : "d"(port)); \ + : "+S"(addr), "+c"(count) : "d"(port) : "memory"); \ } \ \ static inline void ins##bwl(int port, void *addr, unsigned long count) \ { \ asm volatile("rep; ins" #bwl \ - : "+D"(addr), "+c"(count) : "d"(port)); \ + : "+D"(addr), "+c"(count) : "d"(port) : "memory"); \ } BUILDIO(b, b, char) diff --git a/arch/x86/include/asm/kaiser.h b/arch/x86/include/asm/kaiser.h new file mode 100644 index 0000000000000000000000000000000000000000..802bbbdfe14313eed1c3bdb1235475aed472de00 --- /dev/null +++ b/arch/x86/include/asm/kaiser.h @@ -0,0 +1,141 @@ +#ifndef _ASM_X86_KAISER_H +#define _ASM_X86_KAISER_H + +#include /* For PCID constants */ + +/* + * This file includes the definitions for the KAISER feature. + * KAISER is a counter measure against x86_64 side channel attacks on + * the kernel virtual memory. It has a shadow pgd for every process: the + * shadow pgd has a minimalistic kernel-set mapped, but includes the whole + * user memory. Within a kernel context switch, or when an interrupt is handled, + * the pgd is switched to the normal one. When the system switches to user mode, + * the shadow pgd is enabled. By this, the virtual memory caches are freed, + * and the user may not attack the whole kernel memory. + * + * A minimalistic kernel mapping holds the parts needed to be mapped in user + * mode, such as the entry/exit functions of the user space, or the stacks. + */ + +#define KAISER_SHADOW_PGD_OFFSET 0x1000 + +#ifdef __ASSEMBLY__ +#ifdef CONFIG_PAGE_TABLE_ISOLATION + +.macro _SWITCH_TO_KERNEL_CR3 reg +movq %cr3, \reg +andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), \reg +/* If PCID enabled, set X86_CR3_PCID_NOFLUSH_BIT */ +ALTERNATIVE "", "bts $63, \reg", X86_FEATURE_PCID +movq \reg, %cr3 +.endm + +.macro _SWITCH_TO_USER_CR3 reg regb +/* + * regb must be the low byte portion of reg: because we have arranged + * for the low byte of the user PCID to serve as the high byte of NOFLUSH + * (0x80 for each when PCID is enabled, or 0x00 when PCID and NOFLUSH are + * not enabled): so that the one register can update both memory and cr3. + */ +movq %cr3, \reg +orq PER_CPU_VAR(x86_cr3_pcid_user), \reg +js 9f +/* If PCID enabled, FLUSH this time, reset to NOFLUSH for next time */ +movb \regb, PER_CPU_VAR(x86_cr3_pcid_user+7) +9: +movq \reg, %cr3 +.endm + +.macro SWITCH_KERNEL_CR3 +ALTERNATIVE "jmp 8f", "pushq %rax", X86_FEATURE_KAISER +_SWITCH_TO_KERNEL_CR3 %rax +popq %rax +8: +.endm + +.macro SWITCH_USER_CR3 +ALTERNATIVE "jmp 8f", "pushq %rax", X86_FEATURE_KAISER +_SWITCH_TO_USER_CR3 %rax %al +popq %rax +8: +.endm + +.macro SWITCH_KERNEL_CR3_NO_STACK +ALTERNATIVE "jmp 8f", \ + __stringify(movq %rax, PER_CPU_VAR(unsafe_stack_register_backup)), \ + X86_FEATURE_KAISER +_SWITCH_TO_KERNEL_CR3 %rax +movq PER_CPU_VAR(unsafe_stack_register_backup), %rax +8: +.endm + +#else /* CONFIG_PAGE_TABLE_ISOLATION */ + +.macro SWITCH_KERNEL_CR3 +.endm +.macro SWITCH_USER_CR3 +.endm +.macro SWITCH_KERNEL_CR3_NO_STACK +.endm + +#endif /* CONFIG_PAGE_TABLE_ISOLATION */ + +#else /* __ASSEMBLY__ */ + +#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * Upon kernel/user mode switch, it may happen that the address + * space has to be switched before the registers have been + * stored. To change the address space, another register is + * needed. A register therefore has to be stored/restored. +*/ +DECLARE_PER_CPU_USER_MAPPED(unsigned long, unsafe_stack_register_backup); + +DECLARE_PER_CPU(unsigned long, x86_cr3_pcid_user); + +extern char __per_cpu_user_mapped_start[], __per_cpu_user_mapped_end[]; + +extern int kaiser_enabled; +extern void __init kaiser_check_boottime_disable(void); +#else +#define kaiser_enabled 0 +static inline void __init kaiser_check_boottime_disable(void) {} +#endif /* CONFIG_PAGE_TABLE_ISOLATION */ + +/* + * Kaiser function prototypes are needed even when CONFIG_PAGE_TABLE_ISOLATION is not set, + * so as to build with tests on kaiser_enabled instead of #ifdefs. + */ + +/** + * kaiser_add_mapping - map a virtual memory part to the shadow (user) mapping + * @addr: the start address of the range + * @size: the size of the range + * @flags: The mapping flags of the pages + * + * The mapping is done on a global scope, so no bigger + * synchronization has to be done. the pages have to be + * manually unmapped again when they are not needed any longer. + */ +extern int kaiser_add_mapping(unsigned long addr, unsigned long size, unsigned long flags); + +/** + * kaiser_remove_mapping - unmap a virtual memory part of the shadow mapping + * @addr: the start address of the range + * @size: the size of the range + */ +extern void kaiser_remove_mapping(unsigned long start, unsigned long size); + +/** + * kaiser_init - Initialize the shadow mapping + * + * Most parts of the shadow mapping can be mapped upon boot + * time. Only per-process things like the thread stacks + * or a new LDT have to be mapped at runtime. These boot- + * time mappings are permanent and never unmapped. + */ +extern void kaiser_init(void); + +#endif /* __ASSEMBLY */ + +#endif /* _ASM_X86_KAISER_H */ diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index e9cd7befcb76af6e4052c193b879b5f869420754..fc3c7e49c8e48982552c551a74925dda6cd6eebd 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -221,6 +221,9 @@ struct x86_emulate_ops { void (*get_cpuid)(struct x86_emulate_ctxt *ctxt, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked); + + unsigned (*get_hflags)(struct x86_emulate_ctxt *ctxt); + void (*set_hflags)(struct x86_emulate_ctxt *ctxt, unsigned hflags); }; typedef u32 __attribute__((vector_size(16))) sse128_t; @@ -290,10 +293,10 @@ struct x86_emulate_ctxt { /* interruptibility state, as a result of execution of STI or MOV SS */ int interruptibility; - int emul_flags; bool perm_ok; /* do not check permissions if true */ bool ud; /* inject an #UD if host doesn't support insn */ + bool tf; /* TF value before instruction (after for syscall/sysret) */ bool have_exception; struct x86_exception exception; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index bdde80731f490ecc05af1234d99c6ae2820975d4..cbd1d44da2d38a33fbfbc3844881a7107cb5a677 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1397,4 +1397,7 @@ static inline int kvm_cpu_get_apicid(int mps_cpu) #endif } +void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, + unsigned long start, unsigned long end); + #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 9bd7ff5ffbcccd61ed36e2615a877d68003c222c..70c9cc3f098c616431a1a5cf3dfc633041659d64 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -257,6 +257,7 @@ static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { } #endif int mce_available(struct cpuinfo_x86 *c); +bool mce_is_memory_error(struct mce *m); DECLARE_PER_CPU(unsigned, mce_exception_count); DECLARE_PER_CPU(unsigned, mce_poll_count); diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 72198c64e646d3cbb0d9831d950e4e815003cdd3..8b272a08d1a845a48796b24dd82c8e93ce9bc549 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -33,12 +33,6 @@ typedef struct { #endif } mm_context_t; -#ifdef CONFIG_SMP void leave_mm(int cpu); -#else -static inline void leave_mm(int cpu) -{ -} -#endif #endif /* _ASM_X86_MMU_H */ diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 8e0a9fe86de466eee5a520aa8ef9776a0e0e637d..d23e35584f157f3fc748fbe3e01e33f8ae6650a1 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -99,10 +99,8 @@ static inline void load_mm_ldt(struct mm_struct *mm) static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { -#ifdef CONFIG_SMP if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) this_cpu_write(cpu_tlbstate.state, TLBSTATE_LAZY); -#endif } static inline int init_new_context(struct task_struct *tsk, @@ -116,9 +114,7 @@ static inline int init_new_context(struct task_struct *tsk, mm->context.execute_only_pkey = -1; } #endif - init_new_context_ldt(tsk, mm); - - return 0; + return init_new_context_ldt(tsk, mm); } static inline void destroy_context(struct mm_struct *mm) { diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 78f3760ca1f2985cfcbb278d59fbe71f92f69ea7..b11c4c072df8065eaeb1ba51356d515032000f19 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -330,6 +330,9 @@ #define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL #define FAM10H_MMIO_CONF_BASE_SHIFT 20 #define MSR_FAM10H_NODE_ID 0xc001100c +#define MSR_F10H_DECFG 0xc0011029 +#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT 1 +#define MSR_F10H_DECFG_LFENCE_SERIALIZE BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT) /* K8 MSRs */ #define MSR_K8_TOP_MEM1 0xc001001a @@ -405,6 +408,8 @@ #define MSR_IA32_TSC_ADJUST 0x0000003b #define MSR_IA32_BNDCFGS 0x00000d90 +#define MSR_IA32_BNDCFGS_RSVD 0x00000ffc + #define MSR_IA32_XSS 0x00000da0 #define FEATURE_CONTROL_LOCKED (1<<0) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h new file mode 100644 index 0000000000000000000000000000000000000000..402a11c803c38b0bf8de9d5664e5113249427d47 --- /dev/null +++ b/arch/x86/include/asm/nospec-branch.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __NOSPEC_BRANCH_H__ +#define __NOSPEC_BRANCH_H__ + +#include +#include +#include + +/* + * Fill the CPU return stack buffer. + * + * Each entry in the RSB, if used for a speculative 'ret', contains an + * infinite 'pause; jmp' loop to capture speculative execution. + * + * This is required in various cases for retpoline and IBRS-based + * mitigations for the Spectre variant 2 vulnerability. Sometimes to + * eliminate potentially bogus entries from the RSB, and sometimes + * purely to ensure that it doesn't get empty, which on some CPUs would + * allow predictions from other (unwanted!) sources to be used. + * + * We define a CPP macro such that it can be used from both .S files and + * inline assembly. It's possible to do a .macro and then include that + * from C via asm(".include ") but let's not go there. + */ + +#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ +#define RSB_FILL_LOOPS 16 /* To avoid underflow */ + +/* + * Google experimented with loop-unrolling and this turned out to be + * the optimal version — two calls, each with their own speculation + * trap should their return address end up getting used, in a loop. + */ +#define __FILL_RETURN_BUFFER(reg, nr, sp) \ + mov $(nr/2), reg; \ +771: \ + call 772f; \ +773: /* speculation trap */ \ + pause; \ + jmp 773b; \ +772: \ + call 774f; \ +775: /* speculation trap */ \ + pause; \ + jmp 775b; \ +774: \ + dec reg; \ + jnz 771b; \ + add $(BITS_PER_LONG/8) * nr, sp; + +#ifdef __ASSEMBLY__ + +/* + * This should be used immediately before a retpoline alternative. It tells + * objtool where the retpolines are so that it can make sense of the control + * flow by just reading the original instruction(s) and ignoring the + * alternatives. + */ +.macro ANNOTATE_NOSPEC_ALTERNATIVE + .Lannotate_\@: + .pushsection .discard.nospec + .long .Lannotate_\@ - . + .popsection +.endm + +/* + * These are the bare retpoline primitives for indirect jmp and call. + * Do not use these directly; they only exist to make the ALTERNATIVE + * invocation below less ugly. + */ +.macro RETPOLINE_JMP reg:req + call .Ldo_rop_\@ +.Lspec_trap_\@: + pause + jmp .Lspec_trap_\@ +.Ldo_rop_\@: + mov \reg, (%_ASM_SP) + ret +.endm + +/* + * This is a wrapper around RETPOLINE_JMP so the called function in reg + * returns to the instruction after the macro. + */ +.macro RETPOLINE_CALL reg:req + jmp .Ldo_call_\@ +.Ldo_retpoline_jmp_\@: + RETPOLINE_JMP \reg +.Ldo_call_\@: + call .Ldo_retpoline_jmp_\@ +.endm + +/* + * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple + * indirect jmp/call which may be susceptible to the Spectre variant 2 + * attack. + */ +.macro JMP_NOSPEC reg:req +#ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE_2 __stringify(jmp *\reg), \ + __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ + __stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD +#else + jmp *\reg +#endif +.endm + +.macro CALL_NOSPEC reg:req +#ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE_2 __stringify(call *\reg), \ + __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ + __stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD +#else + call *\reg +#endif +.endm + + /* + * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP + * monstrosity above, manually. + */ +.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req +#ifdef CONFIG_RETPOLINE + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE "jmp .Lskip_rsb_\@", \ + __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \ + \ftr +.Lskip_rsb_\@: +#endif +.endm + +#else /* __ASSEMBLY__ */ + +#define ANNOTATE_NOSPEC_ALTERNATIVE \ + "999:\n\t" \ + ".pushsection .discard.nospec\n\t" \ + ".long 999b - .\n\t" \ + ".popsection\n\t" + +#if defined(CONFIG_X86_64) && defined(RETPOLINE) + +/* + * Since the inline asm uses the %V modifier which is only in newer GCC, + * the 64-bit one is dependent on RETPOLINE not CONFIG_RETPOLINE. + */ +# define CALL_NOSPEC \ + ANNOTATE_NOSPEC_ALTERNATIVE \ + ALTERNATIVE( \ + "call *%[thunk_target]\n", \ + "call __x86_indirect_thunk_%V[thunk_target]\n", \ + X86_FEATURE_RETPOLINE) +# define THUNK_TARGET(addr) [thunk_target] "r" (addr) + +#elif defined(CONFIG_X86_32) && defined(CONFIG_RETPOLINE) +/* + * For i386 we use the original ret-equivalent retpoline, because + * otherwise we'll run out of registers. We don't care about CET + * here, anyway. + */ +# define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \ + " jmp 904f;\n" \ + " .align 16\n" \ + "901: call 903f;\n" \ + "902: pause;\n" \ + " jmp 902b;\n" \ + " .align 16\n" \ + "903: addl $4, %%esp;\n" \ + " pushl %[thunk_target];\n" \ + " ret;\n" \ + " .align 16\n" \ + "904: call 901b;\n", \ + X86_FEATURE_RETPOLINE) + +# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) +#else /* No retpoline for C / inline asm */ +# define CALL_NOSPEC "call *%[thunk_target]\n" +# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) +#endif + +/* The Spectre V2 mitigation variants */ +enum spectre_v2_mitigation { + SPECTRE_V2_NONE, + SPECTRE_V2_RETPOLINE_MINIMAL, + SPECTRE_V2_RETPOLINE_MINIMAL_AMD, + SPECTRE_V2_RETPOLINE_GENERIC, + SPECTRE_V2_RETPOLINE_AMD, + SPECTRE_V2_IBRS, +}; + +/* + * On VMEXIT we must ensure that no RSB predictions learned in the guest + * can be followed in the host, by overwriting the RSB completely. Both + * retpoline and IBRS mitigations for Spectre v2 need this; only on future + * CPUs with IBRS_ATT *might* it be avoided. + */ +static inline void vmexit_fill_RSB(void) +{ +#ifdef CONFIG_RETPOLINE + unsigned long loops = RSB_CLEAR_LOOPS / 2; + + asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE("jmp 910f", + __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)), + X86_FEATURE_RETPOLINE) + "910:" + : "=&r" (loops), ASM_CALL_CONSTRAINT + : "r" (loops) : "memory" ); +#endif +} +#endif /* __ASSEMBLY__ */ +#endif /* __NOSPEC_BRANCH_H__ */ diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h index 0b1ff4c1c14e782c0375027ce99cab09e96a04fb..fffb2794dd895521d4f6ca39a5de4c2544c1a676 100644 --- a/arch/x86/include/asm/pat.h +++ b/arch/x86/include/asm/pat.h @@ -7,6 +7,7 @@ bool pat_enabled(void); void pat_disable(const char *reason); extern void pat_init(void); +extern void init_cache_modes(void); extern int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm); diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h index b6d425999f99de01b7f8a5645894a39e04ac685c..1178a51b77f31533f2f306678831ff74d48e2d2d 100644 --- a/arch/x86/include/asm/pgalloc.h +++ b/arch/x86/include/asm/pgalloc.h @@ -27,6 +27,17 @@ static inline void paravirt_release_pud(unsigned long pfn) {} */ extern gfp_t __userpte_alloc_gfp; +#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * Instead of one PGD, we acquire two PGDs. Being order-1, it is + * both 8k in size and 8k-aligned. That lets us just flip bit 12 + * in a pointer to swap between the two 4k halves. + */ +#define PGD_ALLOCATION_ORDER 1 +#else +#define PGD_ALLOCATION_ORDER 0 +#endif + /* * Allocate and free page tables. */ diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 437feb436efa666dbe13732c7d4269160fed49e3..2536f90cd30c5a0207f70475682decd1d6a962f1 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -18,6 +18,12 @@ #ifndef __ASSEMBLY__ #include +#ifdef CONFIG_PAGE_TABLE_ISOLATION +extern int kaiser_enabled; +#else +#define kaiser_enabled 0 +#endif + void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd); void ptdump_walk_pgd_level_checkwx(void); @@ -690,7 +696,17 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address) static inline int pgd_bad(pgd_t pgd) { - return (pgd_flags(pgd) & ~_PAGE_USER) != _KERNPG_TABLE; + pgdval_t ignore_flags = _PAGE_USER; + /* + * We set NX on KAISER pgds that map userspace memory so + * that userspace can not meaningfully use the kernel + * page table by accident; it will fault on the first + * instruction it tries to run. See native_set_pgd(). + */ + if (kaiser_enabled) + ignore_flags |= _PAGE_NX; + + return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE; } static inline int pgd_none(pgd_t pgd) @@ -903,7 +919,15 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, */ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) { - memcpy(dst, src, count * sizeof(pgd_t)); + memcpy(dst, src, count * sizeof(pgd_t)); +#ifdef CONFIG_PAGE_TABLE_ISOLATION + if (kaiser_enabled) { + /* Clone the shadow pgd part as well */ + memcpy(native_get_shadow_pgd(dst), + native_get_shadow_pgd(src), + count * sizeof(pgd_t)); + } +#endif } #define PTE_SHIFT ilog2(PTRS_PER_PTE) diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 1cc82ece9ac1819b92ec82aca72805c0e966af97..ce97c8c6a310eb84ce121bfa068307225fc5b81a 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -106,9 +106,32 @@ static inline void native_pud_clear(pud_t *pud) native_set_pud(pud, native_make_pud(0)); } +#ifdef CONFIG_PAGE_TABLE_ISOLATION +extern pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd); + +static inline pgd_t *native_get_shadow_pgd(pgd_t *pgdp) +{ +#ifdef CONFIG_DEBUG_VM + /* linux/mmdebug.h may not have been included at this point */ + BUG_ON(!kaiser_enabled); +#endif + return (pgd_t *)((unsigned long)pgdp | (unsigned long)PAGE_SIZE); +} +#else +static inline pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd) +{ + return pgd; +} +static inline pgd_t *native_get_shadow_pgd(pgd_t *pgdp) +{ + BUILD_BUG_ON(1); + return NULL; +} +#endif /* CONFIG_PAGE_TABLE_ISOLATION */ + static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) { - *pgdp = pgd; + *pgdp = kaiser_set_shadow_pgd(pgdp, pgd); } static inline void native_pgd_clear(pgd_t *pgd) diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 8b4de22d64299e8997e8b12270e5c23112f85597..f1c8ac46829289415a0fdc9325c0fd926b1f1920 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -119,7 +119,7 @@ #define _PAGE_DEVMAP (_AT(pteval_t, 0)) #endif -#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE) +#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ _PAGE_ACCESSED | _PAGE_DIRTY) @@ -137,6 +137,33 @@ _PAGE_SOFT_DIRTY) #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE) +/* The ASID is the lower 12 bits of CR3 */ +#define X86_CR3_PCID_ASID_MASK (_AC((1<<12)-1,UL)) + +/* Mask for all the PCID-related bits in CR3: */ +#define X86_CR3_PCID_MASK (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_MASK) +#define X86_CR3_PCID_ASID_KERN (_AC(0x0,UL)) + +#if defined(CONFIG_PAGE_TABLE_ISOLATION) && defined(CONFIG_X86_64) +/* Let X86_CR3_PCID_ASID_USER be usable for the X86_CR3_PCID_NOFLUSH bit */ +#define X86_CR3_PCID_ASID_USER (_AC(0x80,UL)) + +#define X86_CR3_PCID_KERN_FLUSH (X86_CR3_PCID_ASID_KERN) +#define X86_CR3_PCID_USER_FLUSH (X86_CR3_PCID_ASID_USER) +#define X86_CR3_PCID_KERN_NOFLUSH (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_KERN) +#define X86_CR3_PCID_USER_NOFLUSH (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_USER) +#else +#define X86_CR3_PCID_ASID_USER (_AC(0x0,UL)) +/* + * PCIDs are unsupported on 32-bit and none of these bits can be + * set in CR3: + */ +#define X86_CR3_PCID_KERN_FLUSH (0) +#define X86_CR3_PCID_USER_FLUSH (0) +#define X86_CR3_PCID_KERN_NOFLUSH (0) +#define X86_CR3_PCID_USER_NOFLUSH (0) +#endif + /* * The cache modes defined here are used to translate between pure SW usage * and the HW defined cache mode bits and/or PAT entries. diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h index 529bb4a6487a9e42d07d0c4ceb226e41b5808f0f..e2904373010d3a16634a777b393ee674a0fcdfe0 100644 --- a/arch/x86/include/asm/pmem.h +++ b/arch/x86/include/asm/pmem.h @@ -103,7 +103,7 @@ static inline size_t arch_copy_from_iter_pmem(void *addr, size_t bytes, if (bytes < 8) { if (!IS_ALIGNED(dest, 4) || (bytes != 4)) - arch_wb_cache_pmem(addr, 1); + arch_wb_cache_pmem(addr, bytes); } else { if (!IS_ALIGNED(dest, 8)) { dest = ALIGN(dest, boot_cpu_data.x86_clflush_size); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 83db0eae99797da9fca22c59eee3fb1ed12ca373..e40b19ca486ebfb1b29583ec3ce5cabf1459f690 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -156,8 +156,8 @@ extern struct cpuinfo_x86 boot_cpu_data; extern struct cpuinfo_x86 new_cpu_data; extern struct tss_struct doublefault_tss; -extern __u32 cpu_caps_cleared[NCAPINTS]; -extern __u32 cpu_caps_set[NCAPINTS]; +extern __u32 cpu_caps_cleared[NCAPINTS + NBUGINTS]; +extern __u32 cpu_caps_set[NCAPINTS + NBUGINTS]; #ifdef CONFIG_SMP DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info); @@ -308,7 +308,7 @@ struct tss_struct { } ____cacheline_aligned; -DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss); +DECLARE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct tss_struct, cpu_tss); #ifdef CONFIG_X86_32 DECLARE_PER_CPU(unsigned long, cpu_current_top_of_stack); diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h index 3d3e8353ee5c09db9b83000efde37a9e34365690..e9ee84873de50a3b60a4cf8e978d4bf6eae9665f 100644 --- a/arch/x86/include/asm/string_32.h +++ b/arch/x86/include/asm/string_32.h @@ -142,7 +142,9 @@ static __always_inline void *__constant_memcpy(void *to, const void *from, } #define __HAVE_ARCH_MEMCPY +extern void *memcpy(void *, const void *, size_t); +#ifndef CONFIG_FORTIFY_SOURCE #ifdef CONFIG_X86_USE_3DNOW #include @@ -195,11 +197,15 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len) #endif #endif +#endif /* !CONFIG_FORTIFY_SOURCE */ #define __HAVE_ARCH_MEMMOVE void *memmove(void *dest, const void *src, size_t n); +extern int memcmp(const void *, const void *, size_t); +#ifndef CONFIG_FORTIFY_SOURCE #define memcmp __builtin_memcmp +#endif #define __HAVE_ARCH_MEMCHR extern void *memchr(const void *cs, int c, size_t count); @@ -321,6 +327,8 @@ void *__constant_c_and_count_memset(void *s, unsigned long pattern, : __memset_generic((s), (c), (count))) #define __HAVE_ARCH_MEMSET +extern void *memset(void *, int, size_t); +#ifndef CONFIG_FORTIFY_SOURCE #if (__GNUC__ >= 4) #define memset(s, c, count) __builtin_memset(s, c, count) #else @@ -330,6 +338,7 @@ void *__constant_c_and_count_memset(void *s, unsigned long pattern, (count)) \ : __memset((s), (c), (count))) #endif +#endif /* !CONFIG_FORTIFY_SOURCE */ /* * find the first occurrence of byte 'c', or 1 past the area if none diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h index a164862d77e3b4573e7a264c8712fac06ef7a830..f942debb7120c8841dff2ea6be5f15a6e19fa83b 100644 --- a/arch/x86/include/asm/string_64.h +++ b/arch/x86/include/asm/string_64.h @@ -31,6 +31,7 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t extern void *memcpy(void *to, const void *from, size_t len); extern void *__memcpy(void *to, const void *from, size_t len); +#ifndef CONFIG_FORTIFY_SOURCE #ifndef CONFIG_KMEMCHECK #if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || __GNUC__ < 4 #define memcpy(dst, src, len) \ @@ -51,6 +52,7 @@ extern void *__memcpy(void *to, const void *from, size_t len); */ #define memcpy(dst, src, len) __inline_memcpy((dst), (src), (len)) #endif +#endif /* !CONFIG_FORTIFY_SOURCE */ #define __HAVE_ARCH_MEMSET void *memset(void *s, int c, size_t n); @@ -77,6 +79,11 @@ int strcmp(const char *cs, const char *ct); #define memcpy(dst, src, len) __memcpy(dst, src, len) #define memmove(dst, src, len) __memmove(dst, src, len) #define memset(s, c, n) __memset(s, c, n) + +#ifndef __NO_FORTIFY +#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ +#endif + #endif __must_check int memcpy_mcsafe_unrolled(void *dst, const void *src, size_t cnt); diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 91dfcafe27a662cba41d162bf374d9632961406e..bad25bb80679fe79cec042a0644d1205db5498fc 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -21,7 +21,7 @@ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); asmlinkage long sys_iopl(unsigned int); /* kernel/ldt.c */ -asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); +asmlinkage long sys_modify_ldt(int, void __user *, unsigned long); /* kernel/signal.c */ asmlinkage long sys_rt_sigreturn(void); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index ad6f5eb07a95bd221fe4e13c8cdb3af0cd27aa37..bdf9c4c91572200f4a895b6bf2edc701ae9a886c 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -152,17 +152,6 @@ struct thread_info { */ #ifndef __ASSEMBLY__ -static inline unsigned long current_stack_pointer(void) -{ - unsigned long sp; -#ifdef CONFIG_X86_64 - asm("mov %%rsp,%0" : "=g" (sp)); -#else - asm("mov %%esp,%0" : "=g" (sp)); -#endif - return sp; -} - /* * Walks up the stack frames to make sure that the specified object is * entirely contained by a single stack frame. diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index fc5abff9b7fd63d6b3a01a18061be8b3f752d109..94146f665a3ce9f251425c6b6c859393ce365653 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -7,6 +7,7 @@ #include #include #include +#include static inline void __invpcid(unsigned long pcid, unsigned long addr, unsigned long type) @@ -65,10 +66,8 @@ static inline void invpcid_flush_all_nonglobals(void) #endif struct tlb_state { -#ifdef CONFIG_SMP struct mm_struct *active_mm; int state; -#endif /* * Access to this CR4 shadow and to H/W CR4 is protected by @@ -133,6 +132,24 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask) cr4_set_bits(mask); } +/* + * Declare a couple of kaiser interfaces here for convenience, + * to avoid the need for asm/kaiser.h in unexpected places. + */ +#ifdef CONFIG_PAGE_TABLE_ISOLATION +extern int kaiser_enabled; +extern void kaiser_setup_pcid(void); +extern void kaiser_flush_tlb_on_return_to_user(void); +#else +#define kaiser_enabled 0 +static inline void kaiser_setup_pcid(void) +{ +} +static inline void kaiser_flush_tlb_on_return_to_user(void) +{ +} +#endif + static inline void __native_flush_tlb(void) { /* @@ -141,6 +158,8 @@ static inline void __native_flush_tlb(void) * back: */ preempt_disable(); + if (kaiser_enabled) + kaiser_flush_tlb_on_return_to_user(); native_write_cr3(native_read_cr3()); preempt_enable(); } @@ -150,20 +169,27 @@ static inline void __native_flush_tlb_global_irq_disabled(void) unsigned long cr4; cr4 = this_cpu_read(cpu_tlbstate.cr4); - /* clear PGE */ - native_write_cr4(cr4 & ~X86_CR4_PGE); - /* write old PGE again and flush TLBs */ - native_write_cr4(cr4); + if (cr4 & X86_CR4_PGE) { + /* clear PGE and flush TLB of all entries */ + native_write_cr4(cr4 & ~X86_CR4_PGE); + /* restore PGE as it was before */ + native_write_cr4(cr4); + } else { + /* do it with cr3, letting kaiser flush user PCID */ + __native_flush_tlb(); + } } static inline void __native_flush_tlb_global(void) { unsigned long flags; - if (static_cpu_has(X86_FEATURE_INVPCID)) { + if (this_cpu_has(X86_FEATURE_INVPCID)) { /* * Using INVPCID is considerably faster than a pair of writes * to CR4 sandwiched inside an IRQ flag save/restore. + * + * Note, this works with CR4.PCIDE=0 or 1. */ invpcid_flush_all(); return; @@ -175,23 +201,52 @@ static inline void __native_flush_tlb_global(void) * be called from deep inside debugging code.) */ raw_local_irq_save(flags); - __native_flush_tlb_global_irq_disabled(); - raw_local_irq_restore(flags); } static inline void __native_flush_tlb_single(unsigned long addr) { - asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); + /* + * SIMICS #GP's if you run INVPCID with type 2/3 + * and X86_CR4_PCIDE clear. Shame! + * + * The ASIDs used below are hard-coded. But, we must not + * call invpcid(type=1/2) before CR4.PCIDE=1. Just call + * invlpg in the case we are called early. + */ + + if (!this_cpu_has(X86_FEATURE_INVPCID_SINGLE)) { + if (kaiser_enabled) + kaiser_flush_tlb_on_return_to_user(); + asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); + return; + } + /* Flush the address out of both PCIDs. */ + /* + * An optimization here might be to determine addresses + * that are only kernel-mapped and only flush the kernel + * ASID. But, userspace flushes are probably much more + * important performance-wise. + * + * Make sure to do only a single invpcid when KAISER is + * disabled and we have only a single ASID. + */ + if (kaiser_enabled) + invpcid_flush_one(X86_CR3_PCID_ASID_USER, addr); + invpcid_flush_one(X86_CR3_PCID_ASID_KERN, addr); } static inline void __flush_tlb_all(void) { - if (boot_cpu_has(X86_FEATURE_PGE)) - __flush_tlb_global(); - else - __flush_tlb(); + __flush_tlb_global(); + /* + * Note: if we somehow had PCID but not PGE, then this wouldn't work -- + * we'd end up flushing kernel translations for the current ASID but + * we might fail to flush kernel translations for other cached ASIDs. + * + * To avoid this issue, we force PCID off if PGE is off. + */ } static inline void __flush_tlb_one(unsigned long addr) @@ -205,7 +260,6 @@ static inline void __flush_tlb_one(unsigned long addr) /* * TLB flushing: * - * - flush_tlb() flushes the current mm struct TLBs * - flush_tlb_all() flushes all processes TLBs * - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_page(vma, vmaddr) flushes one page @@ -217,84 +271,6 @@ static inline void __flush_tlb_one(unsigned long addr) * and page-granular flushes are available only on i486 and up. */ -#ifndef CONFIG_SMP - -/* "_up" is for UniProcessor. - * - * This is a helper for other header functions. *Not* intended to be called - * directly. All global TLB flushes need to either call this, or to bump the - * vm statistics themselves. - */ -static inline void __flush_tlb_up(void) -{ - count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); - __flush_tlb(); -} - -static inline void flush_tlb_all(void) -{ - count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); - __flush_tlb_all(); -} - -static inline void flush_tlb(void) -{ - __flush_tlb_up(); -} - -static inline void local_flush_tlb(void) -{ - __flush_tlb_up(); -} - -static inline void flush_tlb_mm(struct mm_struct *mm) -{ - if (mm == current->active_mm) - __flush_tlb_up(); -} - -static inline void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr) -{ - if (vma->vm_mm == current->active_mm) - __flush_tlb_one(addr); -} - -static inline void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - if (vma->vm_mm == current->active_mm) - __flush_tlb_up(); -} - -static inline void flush_tlb_mm_range(struct mm_struct *mm, - unsigned long start, unsigned long end, unsigned long vmflag) -{ - if (mm == current->active_mm) - __flush_tlb_up(); -} - -static inline void native_flush_tlb_others(const struct cpumask *cpumask, - struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ -} - -static inline void reset_lazy_tlbstate(void) -{ -} - -static inline void flush_tlb_kernel_range(unsigned long start, - unsigned long end) -{ - flush_tlb_all(); -} - -#else /* SMP */ - -#include - #define local_flush_tlb() __flush_tlb() #define flush_tlb_mm(mm) flush_tlb_mm_range(mm, 0UL, TLB_FLUSH_ALL, 0UL) @@ -303,13 +279,14 @@ static inline void flush_tlb_kernel_range(unsigned long start, flush_tlb_mm_range(vma->vm_mm, start, end, vma->vm_flags) extern void flush_tlb_all(void); -extern void flush_tlb_current_task(void); -extern void flush_tlb_page(struct vm_area_struct *, unsigned long); extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long vmflag); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); -#define flush_tlb() flush_tlb_current_task() +static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long a) +{ + flush_tlb_mm_range(vma->vm_mm, a, a + PAGE_SIZE, VM_NONE); +} void native_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, @@ -324,8 +301,6 @@ static inline void reset_lazy_tlbstate(void) this_cpu_write(cpu_tlbstate.active_mm, &init_mm); } -#endif /* SMP */ - #ifndef CONFIG_PARAVIRT #define flush_tlb_others(mask, mm, start, end) \ native_flush_tlb_others(mask, mm, start, end) diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index faf3687f1035c466c87684110fbc221afcce141f..dead0f3921f33287b05f5cfbab8ef9af6f7c0968 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -68,6 +68,12 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un __chk_range_not_ok((unsigned long __force)(addr), size, limit); \ }) +#ifdef CONFIG_DEBUG_ATOMIC_SLEEP +# define WARN_ON_IN_IRQ() WARN_ON_ONCE(!in_task()) +#else +# define WARN_ON_IN_IRQ() +#endif + /** * access_ok: - Checks if a user space pointer is valid * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that @@ -88,8 +94,11 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un * checks that the pointer is in the user space range - after calling * this function, memory access functions may still return -EFAULT. */ -#define access_ok(type, addr, size) \ - likely(!__range_not_ok(addr, size, user_addr_max())) +#define access_ok(type, addr, size) \ +({ \ + WARN_ON_IN_IRQ(); \ + likely(!__range_not_ok(addr, size, user_addr_max())); \ +}) /* * These are the main single-value transfer routines. They automatically @@ -315,10 +324,10 @@ do { \ #define __get_user_asm_u64(x, ptr, retval, errret) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ - asm volatile(ASM_STAC "\n" \ + asm volatile("\n" \ "1: movl %2,%%eax\n" \ "2: movl %3,%%edx\n" \ - "3: " ASM_CLAC "\n" \ + "3:\n" \ ".section .fixup,\"ax\"\n" \ "4: mov %4,%0\n" \ " xorl %%eax,%%eax\n" \ @@ -327,7 +336,7 @@ do { \ ".previous\n" \ _ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE(2b, 4b) \ - : "=r" (retval), "=A"(x) \ + : "=r" (retval), "=&A"(x) \ : "m" (__m(__ptr)), "m" __m(((u32 *)(__ptr)) + 1), \ "i" (errret), "0" (retval)); \ }) diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h index 6ba66ee79710ffdc19806994df22375859b95736..4865e10dbb550f00150d556e91ad3b9611152731 100644 --- a/arch/x86/include/asm/vsyscall.h +++ b/arch/x86/include/asm/vsyscall.h @@ -12,12 +12,14 @@ extern void map_vsyscall(void); * Returns true if handled. */ extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address); +extern bool vsyscall_enabled(void); #else static inline void map_vsyscall(void) {} static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) { return false; } +static inline bool vsyscall_enabled(void) { return false; } #endif #endif /* _ASM_X86_VSYSCALL_H */ diff --git a/arch/x86/include/asm/xen/events.h b/arch/x86/include/asm/xen/events.h index 608a79d5a4669ebf3a9060f895d0f5f03ab3286c..e6911caf5bbf16ddc46430c44fcd4186258b713c 100644 --- a/arch/x86/include/asm/xen/events.h +++ b/arch/x86/include/asm/xen/events.h @@ -20,4 +20,15 @@ static inline int xen_irqs_disabled(struct pt_regs *regs) /* No need for a barrier -- XCHG is a barrier on x86. */ #define xchg_xen_ulong(ptr, val) xchg((ptr), (val)) +extern int xen_have_vector_callback; + +/* + * Events delivered via platform PCI interrupts are always + * routed to vcpu 0 and hence cannot be rebound. + */ +static inline bool xen_support_evtchn_rebind(void) +{ + return (!xen_hvm_domain() || xen_have_vector_callback); +} + #endif /* _ASM_X86_XEN_EVENTS_H */ diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index a12a047184ee4789d8fd041493862c543fa692ac..ccdc23d89b6038a8faac1b21eeace8c155077f69 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -43,6 +43,8 @@ #include #include +#include +#include #include #include @@ -214,10 +216,12 @@ privcmd_call(unsigned call, __HYPERCALL_DECLS; __HYPERCALL_5ARG(a1, a2, a3, a4, a5); - asm volatile("call *%[call]" + stac(); + asm volatile(CALL_NOSPEC : __HYPERCALL_5PARAM - : [call] "a" (&hypercall_page[call]) + : [thunk_target] "a" (&hypercall_page[call]) : __HYPERCALL_CLOBBER5); + clac(); return (long)__res; } diff --git a/arch/x86/include/uapi/asm/processor-flags.h b/arch/x86/include/uapi/asm/processor-flags.h index 567de50a4c2a59c1a85ed4ee6025498352227dc1..6768d1321016d372e58c0f6c59cba1553a3a12e8 100644 --- a/arch/x86/include/uapi/asm/processor-flags.h +++ b/arch/x86/include/uapi/asm/processor-flags.h @@ -77,7 +77,8 @@ #define X86_CR3_PWT _BITUL(X86_CR3_PWT_BIT) #define X86_CR3_PCD_BIT 4 /* Page Cache Disable */ #define X86_CR3_PCD _BITUL(X86_CR3_PCD_BIT) -#define X86_CR3_PCID_MASK _AC(0x00000fff,UL) /* PCID Mask */ +#define X86_CR3_PCID_NOFLUSH_BIT 63 /* Preserve old PCID */ +#define X86_CR3_PCID_NOFLUSH _BITULL(X86_CR3_PCID_NOFLUSH_BIT) /* * Intel CPU features in CR4 diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 931ced8ca345114397536ae1998a438a84889193..0a1e8a67cc998a5c2f0bca55a40a38b4a837e706 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -176,10 +176,15 @@ static int acpi_register_lapic(int id, u32 acpiid, u8 enabled) return -EINVAL; } + if (!enabled) { + ++disabled_cpus; + return -EINVAL; + } + if (boot_cpu_physical_apicid != -1U) ver = boot_cpu_apic_version; - cpu = __generic_processor_info(id, ver, enabled); + cpu = generic_processor_info(id, ver); if (cpu >= 0) early_per_cpu(x86_cpu_to_acpiid, cpu) = acpiid; @@ -330,20 +335,19 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e #ifdef CONFIG_X86_IO_APIC #define MP_ISA_BUS 0 +static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity, + u8 trigger, u32 gsi); + static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) { - int ioapic; - int pin; - struct mpc_intsrc mp_irq; - /* - * Convert 'gsi' to 'ioapic.pin'. + * Check bus_irq boundary. */ - ioapic = mp_find_ioapic(gsi); - if (ioapic < 0) + if (bus_irq >= NR_IRQS_LEGACY) { + pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq); return; - pin = mp_find_ioapic_pin(ioapic, gsi); + } /* * TBD: This check is for faulty timer entries, where the override @@ -353,16 +357,8 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, if ((bus_irq == 0) && (trigger == 3)) trigger = 1; - mp_irq.type = MP_INTSRC; - mp_irq.irqtype = mp_INT; - mp_irq.irqflag = (trigger << 2) | polarity; - mp_irq.srcbus = MP_ISA_BUS; - mp_irq.srcbusirq = bus_irq; /* IRQ */ - mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */ - mp_irq.dstirq = pin; /* INTIN# */ - - mp_save_irq(&mp_irq); - + if (mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi) < 0) + return; /* * Reset default identity mapping if gsi is also an legacy IRQ, * otherwise there will be more than one entry with the same GSI @@ -409,6 +405,34 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, return 0; } +static int __init mp_register_ioapic_irq(u8 bus_irq, u8 polarity, + u8 trigger, u32 gsi) +{ + struct mpc_intsrc mp_irq; + int ioapic, pin; + + /* Convert 'gsi' to 'ioapic.pin'(INTIN#) */ + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) { + pr_warn("Failed to find ioapic for gsi : %u\n", gsi); + return ioapic; + } + + pin = mp_find_ioapic_pin(ioapic, gsi); + + mp_irq.type = MP_INTSRC; + mp_irq.irqtype = mp_INT; + mp_irq.irqflag = (trigger << 2) | polarity; + mp_irq.srcbus = MP_ISA_BUS; + mp_irq.srcbusirq = bus_irq; + mp_irq.dstapic = mpc_ioapic_id(ioapic); + mp_irq.dstirq = pin; + + mp_save_irq(&mp_irq); + + return 0; +} + static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { @@ -453,7 +477,11 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK) polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; - mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + if (bus_irq < NR_IRQS_LEGACY) + mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + else + mp_register_ioapic_irq(bus_irq, polarity, trigger, gsi); + acpi_penalize_sci_irq(bus_irq, trigger, polarity); /* @@ -707,7 +735,7 @@ static void __init acpi_set_irq_model_ioapic(void) #ifdef CONFIG_ACPI_HOTPLUG_CPU #include -int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) { #ifdef CONFIG_ACPI_NUMA int nid; diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 5cb272a7a5a32eccbbee61a23c50ab9b5a80a0fb..10d5a3d6affc454fd0f4e46208929d4560b63bfa 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -340,9 +340,12 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf) static void __init_or_module optimize_nops(struct alt_instr *a, u8 *instr) { unsigned long flags; + int i; - if (instr[0] != 0x90) - return; + for (i = 0; i < a->padlen; i++) { + if (instr[i] != 0x90) + return; + } local_irq_save(flags); add_nops(instr + (a->instrlen - a->padlen), a->padlen); diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index f2234918e4944e559d082761985860107880c71d..c6583efdbdafdda65df008cf8804f755f1da859b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1863,14 +1863,14 @@ static void __smp_spurious_interrupt(u8 vector) "should never happen.\n", vector, smp_processor_id()); } -__visible void smp_spurious_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs) { entering_irq(); __smp_spurious_interrupt(~regs->orig_ax); exiting_irq(); } -__visible void smp_trace_spurious_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_trace_spurious_interrupt(struct pt_regs *regs) { u8 vector = ~regs->orig_ax; @@ -1921,14 +1921,14 @@ static void __smp_error_interrupt(struct pt_regs *regs) } -__visible void smp_error_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_error_interrupt(struct pt_regs *regs) { entering_irq(); __smp_error_interrupt(regs); exiting_irq(); } -__visible void smp_trace_error_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_trace_error_interrupt(struct pt_regs *regs) { entering_irq(); trace_error_apic_entry(ERROR_APIC_VECTOR); @@ -2070,7 +2070,7 @@ static int allocate_logical_cpuid(int apicid) return nr_logical_cpuids++; } -int __generic_processor_info(int apicid, int version, bool enabled) +int generic_processor_info(int apicid, int version) { int cpu, max = nr_cpu_ids; bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, @@ -2128,11 +2128,9 @@ int __generic_processor_info(int apicid, int version, bool enabled) if (num_processors >= nr_cpu_ids) { int thiscpu = max + disabled_cpus; - if (enabled) { - pr_warning("APIC: NR_CPUS/possible_cpus limit of %i " - "reached. Processor %d/0x%x ignored.\n", - max, thiscpu, apicid); - } + pr_warning("APIC: NR_CPUS/possible_cpus limit of %i " + "reached. Processor %d/0x%x ignored.\n", + max, thiscpu, apicid); disabled_cpus++; return -EINVAL; @@ -2184,23 +2182,13 @@ int __generic_processor_info(int apicid, int version, bool enabled) apic->x86_32_early_logical_apicid(cpu); #endif set_cpu_possible(cpu, true); - - if (enabled) { - num_processors++; - physid_set(apicid, phys_cpu_present_map); - set_cpu_present(cpu, true); - } else { - disabled_cpus++; - } + physid_set(apicid, phys_cpu_present_map); + set_cpu_present(cpu, true); + num_processors++; return cpu; } -int generic_processor_info(int apicid, int version) -{ - return __generic_processor_info(apicid, version, true); -} - int hard_smp_processor_id(void) { return read_apic_id(); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index d1e25564b3c19286d184c4a50184bb56fc04e601..cf89928dbd46dfb8a64c00dd831c5e0a9939e48a 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1876,6 +1876,7 @@ static struct irq_chip ioapic_chip __read_mostly = { .irq_ack = irq_chip_ack_parent, .irq_eoi = ioapic_ack_level, .irq_set_affinity = ioapic_set_affinity, + .irq_retrigger = irq_chip_retrigger_hierarchy, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -1887,6 +1888,7 @@ static struct irq_chip ioapic_ir_chip __read_mostly = { .irq_ack = irq_chip_ack_parent, .irq_eoi = ioapic_ir_ack_level, .irq_set_affinity = ioapic_set_affinity, + .irq_retrigger = irq_chip_retrigger_hierarchy, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -2114,7 +2116,7 @@ static inline void __init check_timer(void) int idx; idx = find_irq_entry(apic1, pin1, mp_INT); if (idx != -1 && irq_trigger(idx)) - unmask_ioapic_irq(irq_get_chip_data(0)); + unmask_ioapic_irq(irq_get_irq_data(0)); } irq_domain_deactivate_irq(irq_data); irq_domain_activate_irq(irq_data); diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 5d30c5e42bb13939b9164ac575d9202a26d772a7..f3557a1eb562fbe6e46b2e3db3289ca8535b1b6c 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -559,7 +559,7 @@ void send_cleanup_vector(struct irq_cfg *cfg) __send_cleanup_vector(data); } -asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) +asmlinkage __visible void __irq_entry smp_irq_move_cleanup_interrupt(void) { unsigned vector, me; diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 4a8697f7d4ef804921c7422fac02f28c4b8b0c2b..33b63670bf09e6d34c1f194cfe3600d9ea16dcb4 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -20,13 +20,11 @@ obj-y := intel_cacheinfo.o scattered.o topology.o obj-y += common.o obj-y += rdrand.o obj-y += match.o +obj-y += bugs.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o -obj-$(CONFIG_X86_32) += bugs.o -obj-$(CONFIG_X86_64) += bugs_64.o - obj-$(CONFIG_CPU_SUP_INTEL) += intel.o obj-$(CONFIG_CPU_SUP_AMD) += amd.o obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 2b4cf04239b6c011a9d9a5ef84bdca5ef073a69e..1b89f0c4251e5a1413674c60dbe35e7fbbeb9923 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -782,8 +782,32 @@ static void init_amd(struct cpuinfo_x86 *c) set_cpu_cap(c, X86_FEATURE_K8); if (cpu_has(c, X86_FEATURE_XMM2)) { - /* MFENCE stops RDTSC speculation */ - set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); + unsigned long long val; + int ret; + + /* + * A serializing LFENCE has less overhead than MFENCE, so + * use it for execution serialization. On families which + * don't have that MSR, LFENCE is already serializing. + * msr_set_bit() uses the safe accessors, too, even if the MSR + * is not present. + */ + msr_set_bit(MSR_F10H_DECFG, + MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT); + + /* + * Verify that the MSR write was successful (could be running + * under a hypervisor) and only then assume that LFENCE is + * serializing. + */ + ret = rdmsrl_safe(MSR_F10H_DECFG, &val); + if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) { + /* A serializing LFENCE stops RDTSC speculation */ + set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); + } else { + /* MFENCE stops RDTSC speculation */ + set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); + } } /* diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index bd17db15a2c1ef07412c73f064f282a3f55c9313..49d25ddf0e9f65d80fb2aba7297bbd91386352e6 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -9,6 +9,10 @@ */ #include #include +#include + +#include +#include #include #include #include @@ -16,15 +20,24 @@ #include #include #include +#include +#include + +static void __init spectre_v2_select_mitigation(void); void __init check_bugs(void) { identify_boot_cpu(); -#ifndef CONFIG_SMP - pr_info("CPU: "); - print_cpu_info(&boot_cpu_data); -#endif + if (!IS_ENABLED(CONFIG_SMP)) { + pr_info("CPU: "); + print_cpu_info(&boot_cpu_data); + } + + /* Select the proper spectre mitigation before patching alternatives */ + spectre_v2_select_mitigation(); + +#ifdef CONFIG_X86_32 /* * Check whether we are able to run this kernel safely on SMP. * @@ -40,4 +53,194 @@ void __init check_bugs(void) alternative_instructions(); fpu__init_check_bugs(); +#else /* CONFIG_X86_64 */ + alternative_instructions(); + + /* + * Make sure the first 2MB area is not mapped by huge pages + * There are typically fixed size MTRRs in there and overlapping + * MTRRs into large pages causes slow downs. + * + * Right now we don't do that with gbpages because there seems + * very little benefit for that case. + */ + if (!direct_gbpages) + set_memory_4k((unsigned long)__va(0), 1); +#endif +} + +/* The kernel command line selection */ +enum spectre_v2_mitigation_cmd { + SPECTRE_V2_CMD_NONE, + SPECTRE_V2_CMD_AUTO, + SPECTRE_V2_CMD_FORCE, + SPECTRE_V2_CMD_RETPOLINE, + SPECTRE_V2_CMD_RETPOLINE_GENERIC, + SPECTRE_V2_CMD_RETPOLINE_AMD, +}; + +static const char *spectre_v2_strings[] = { + [SPECTRE_V2_NONE] = "Vulnerable", + [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal generic ASM retpoline", + [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Vulnerable: Minimal AMD ASM retpoline", + [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", + [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", +}; + +#undef pr_fmt +#define pr_fmt(fmt) "Spectre V2 mitigation: " fmt + +static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; + +static void __init spec2_print_if_insecure(const char *reason) +{ + if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + pr_info("%s\n", reason); +} + +static void __init spec2_print_if_secure(const char *reason) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + pr_info("%s\n", reason); +} + +static inline bool retp_compiler(void) +{ + return __is_defined(RETPOLINE); +} + +static inline bool match_option(const char *arg, int arglen, const char *opt) +{ + int len = strlen(opt); + + return len == arglen && !strncmp(arg, opt, len); } + +static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) +{ + char arg[20]; + int ret; + + ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, + sizeof(arg)); + if (ret > 0) { + if (match_option(arg, ret, "off")) { + goto disable; + } else if (match_option(arg, ret, "on")) { + spec2_print_if_secure("force enabled on command line."); + return SPECTRE_V2_CMD_FORCE; + } else if (match_option(arg, ret, "retpoline")) { + spec2_print_if_insecure("retpoline selected on command line."); + return SPECTRE_V2_CMD_RETPOLINE; + } else if (match_option(arg, ret, "retpoline,amd")) { + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { + pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); + return SPECTRE_V2_CMD_AUTO; + } + spec2_print_if_insecure("AMD retpoline selected on command line."); + return SPECTRE_V2_CMD_RETPOLINE_AMD; + } else if (match_option(arg, ret, "retpoline,generic")) { + spec2_print_if_insecure("generic retpoline selected on command line."); + return SPECTRE_V2_CMD_RETPOLINE_GENERIC; + } else if (match_option(arg, ret, "auto")) { + return SPECTRE_V2_CMD_AUTO; + } + } + + if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2")) + return SPECTRE_V2_CMD_AUTO; +disable: + spec2_print_if_insecure("disabled on command line."); + return SPECTRE_V2_CMD_NONE; +} + +static void __init spectre_v2_select_mitigation(void) +{ + enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); + enum spectre_v2_mitigation mode = SPECTRE_V2_NONE; + + /* + * If the CPU is not affected and the command line mode is NONE or AUTO + * then nothing to do. + */ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) && + (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO)) + return; + + switch (cmd) { + case SPECTRE_V2_CMD_NONE: + return; + + case SPECTRE_V2_CMD_FORCE: + /* FALLTRHU */ + case SPECTRE_V2_CMD_AUTO: + goto retpoline_auto; + + case SPECTRE_V2_CMD_RETPOLINE_AMD: + if (IS_ENABLED(CONFIG_RETPOLINE)) + goto retpoline_amd; + break; + case SPECTRE_V2_CMD_RETPOLINE_GENERIC: + if (IS_ENABLED(CONFIG_RETPOLINE)) + goto retpoline_generic; + break; + case SPECTRE_V2_CMD_RETPOLINE: + if (IS_ENABLED(CONFIG_RETPOLINE)) + goto retpoline_auto; + break; + } + pr_err("kernel not compiled with retpoline; no mitigation available!"); + return; + +retpoline_auto: + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { + retpoline_amd: + if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) { + pr_err("LFENCE not serializing. Switching to generic retpoline\n"); + goto retpoline_generic; + } + mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : + SPECTRE_V2_RETPOLINE_MINIMAL_AMD; + setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); + setup_force_cpu_cap(X86_FEATURE_RETPOLINE); + } else { + retpoline_generic: + mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC : + SPECTRE_V2_RETPOLINE_MINIMAL; + setup_force_cpu_cap(X86_FEATURE_RETPOLINE); + } + + spectre_v2_enabled = mode; + pr_info("%s\n", spectre_v2_strings[mode]); +} + +#undef pr_fmt + +#ifdef CONFIG_SYSFS +ssize_t cpu_show_meltdown(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) + return sprintf(buf, "Not affected\n"); + if (boot_cpu_has(X86_FEATURE_KAISER)) + return sprintf(buf, "Mitigation: PTI\n"); + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) + return sprintf(buf, "Not affected\n"); + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]); +} +#endif diff --git a/arch/x86/kernel/cpu/bugs_64.c b/arch/x86/kernel/cpu/bugs_64.c deleted file mode 100644 index a972ac4c7e7df05238e78b08e093cded47640fcd..0000000000000000000000000000000000000000 --- a/arch/x86/kernel/cpu/bugs_64.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 1994 Linus Torvalds - * Copyright (C) 2000 SuSE - */ - -#include -#include -#include -#include -#include -#include -#include - -void __init check_bugs(void) -{ - identify_boot_cpu(); -#if !defined(CONFIG_SMP) - pr_info("CPU: "); - print_cpu_info(&boot_cpu_data); -#endif - alternative_instructions(); - - /* - * Make sure the first 2MB area is not mapped by huge pages - * There are typically fixed size MTRRs in there and overlapping - * MTRRs into large pages causes slow downs. - * - * Right now we don't do that with gbpages because there seems - * very little benefit for that case. - */ - if (!direct_gbpages) - set_memory_4k((unsigned long)__va(0), 1); -} diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 4eece91ada374d1dc25c39b763861c755354d060..7b9ae04ddf5d17e161d4665832cfdce9d4f8ed6a 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -93,7 +93,7 @@ static const struct cpu_dev default_cpu = { static const struct cpu_dev *this_cpu = &default_cpu; -DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { +DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(struct gdt_page, gdt_page) = { .gdt = { #ifdef CONFIG_X86_64 /* * We need valid kernel segments for data and code in long mode too @@ -163,6 +163,24 @@ static int __init x86_mpx_setup(char *s) } __setup("nompx", x86_mpx_setup); +#ifdef CONFIG_X86_64 +static int __init x86_pcid_setup(char *s) +{ + /* require an exact match without trailing characters */ + if (strlen(s)) + return 0; + + /* do not emit a message if the feature is not present */ + if (!boot_cpu_has(X86_FEATURE_PCID)) + return 1; + + setup_clear_cpu_cap(X86_FEATURE_PCID); + pr_info("nopcid: PCID feature disabled\n"); + return 1; +} +__setup("nopcid", x86_pcid_setup); +#endif + static int __init x86_noinvpcid_setup(char *s) { /* noinvpcid doesn't accept parameters */ @@ -306,6 +324,39 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c) } } +static void setup_pcid(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_PCID)) { + if (cpu_has(c, X86_FEATURE_PGE) || kaiser_enabled) { + cr4_set_bits(X86_CR4_PCIDE); + /* + * INVPCID has two "groups" of types: + * 1/2: Invalidate an individual address + * 3/4: Invalidate all contexts + * + * 1/2 take a PCID, but 3/4 do not. So, 3/4 + * ignore the PCID argument in the descriptor. + * But, we have to be careful not to call 1/2 + * with an actual non-zero PCID in them before + * we do the above cr4_set_bits(). + */ + if (cpu_has(c, X86_FEATURE_INVPCID)) + set_cpu_cap(c, X86_FEATURE_INVPCID_SINGLE); + } else { + /* + * flush_tlb_all(), as currently implemented, won't + * work if PCID is on but PGE is not. Since that + * combination doesn't exist on real hardware, there's + * no reason to try to fully support it, but it's + * polite to avoid corrupting data if we're on + * an improperly configured VM. + */ + clear_cpu_cap(c, X86_FEATURE_PCID); + } + } + kaiser_setup_pcid(); +} + /* * Protection Keys are not available in 32-bit mode. */ @@ -429,8 +480,8 @@ static const char *table_lookup_model(struct cpuinfo_x86 *c) return NULL; /* Not found */ } -__u32 cpu_caps_cleared[NCAPINTS]; -__u32 cpu_caps_set[NCAPINTS]; +__u32 cpu_caps_cleared[NCAPINTS + NBUGINTS]; +__u32 cpu_caps_set[NCAPINTS + NBUGINTS]; void load_percpu_segment(int cpu) { @@ -655,6 +706,16 @@ void cpu_detect(struct cpuinfo_x86 *c) } } +static void apply_forced_caps(struct cpuinfo_x86 *c) +{ + int i; + + for (i = 0; i < NCAPINTS + NBUGINTS; i++) { + c->x86_capability[i] &= ~cpu_caps_cleared[i]; + c->x86_capability[i] |= cpu_caps_set[i]; + } +} + void get_cpu_cap(struct cpuinfo_x86 *c) { u32 eax, ebx, ecx, edx; @@ -821,7 +882,22 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) } setup_force_cpu_cap(X86_FEATURE_ALWAYS); + + /* Assume for now that ALL x86 CPUs are insecure */ + setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN); + + setup_force_cpu_bug(X86_BUG_SPECTRE_V1); + setup_force_cpu_bug(X86_BUG_SPECTRE_V2); + fpu__init_system(c); + +#ifdef CONFIG_X86_32 + /* + * Regardless of whether PCID is enumerated, the SDM says + * that it can't be enabled in 32-bit mode. + */ + setup_clear_cpu_cap(X86_FEATURE_PCID); +#endif } void __init early_cpu_init(void) @@ -1035,10 +1111,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) this_cpu->c_identify(c); /* Clear/Set all flags overridden by options, after probe */ - for (i = 0; i < NCAPINTS; i++) { - c->x86_capability[i] &= ~cpu_caps_cleared[i]; - c->x86_capability[i] |= cpu_caps_set[i]; - } + apply_forced_caps(c); #ifdef CONFIG_X86_64 c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); @@ -1064,6 +1137,9 @@ static void identify_cpu(struct cpuinfo_x86 *c) setup_smep(c); setup_smap(c); + /* Set up PCID */ + setup_pcid(c); + /* * The vendor-specific functions might have changed features. * Now we do "generic changes." @@ -1097,10 +1173,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) * Clear/Set all flags overridden by options, need do it * before following smp all cpus cap AND. */ - for (i = 0; i < NCAPINTS; i++) { - c->x86_capability[i] &= ~cpu_caps_cleared[i]; - c->x86_capability[i] |= cpu_caps_set[i]; - } + apply_forced_caps(c); /* * On SMP, boot_cpu_data holds the common feature set between @@ -1325,7 +1398,7 @@ static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = { [DEBUG_STACK - 1] = DEBUG_STKSZ }; -static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks +DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(char, exception_stacks [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); /* May not be marked __init: used by software suspend */ @@ -1483,6 +1556,14 @@ void cpu_init(void) * try to read it. */ cr4_init_shadow(); + if (!kaiser_enabled) { + /* + * secondary_startup_64() deferred setting PGE in cr4: + * probe_page_size_mask() sets it on the boot cpu, + * but it needs to be set on each secondary cpu. + */ + cr4_set_bits(X86_CR4_PGE); + } /* * Load microcode on this cpu if a valid microcode is available. diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 631356c8cca4a552c042629c9a2a6744a3512ec9..f46071cb2c90f421e4433c6c59986c8ae52cc944 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -245,6 +245,9 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc if (m->status & MCI_STATUS_UC) { + if (ctx == IN_KERNEL) + return MCE_PANIC_SEVERITY; + /* * On older systems where overflow_recov flag is not present, we * should simply panic if an error overflow occurs. If @@ -255,10 +258,6 @@ static int mce_severity_amd(struct mce *m, int tolerant, char **msg, bool is_exc if (mce_flags.smca) return mce_severity_amd_smca(m, ctx); - /* software can try to contain */ - if (!(m->mcgstatus & MCG_STATUS_RIPV) && (ctx == IN_KERNEL)) - return MCE_PANIC_SEVERITY; - /* kill current process */ return MCE_AR_SEVERITY; } else { diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 22cda29d654edfbf0eedbf3f41f9242d5eb2d8a3..8ca5f8ad008eb2541b5745600572c1ad08b117c8 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -598,16 +598,14 @@ static void mce_read_aux(struct mce *m, int i) } } -static bool memory_error(struct mce *m) +bool mce_is_memory_error(struct mce *m) { - struct cpuinfo_x86 *c = &boot_cpu_data; - - if (c->x86_vendor == X86_VENDOR_AMD) { + if (m->cpuvendor == X86_VENDOR_AMD) { /* ErrCodeExt[20:16] */ u8 xec = (m->status >> 16) & 0x1f; return (xec == 0x0 || xec == 0x8); - } else if (c->x86_vendor == X86_VENDOR_INTEL) { + } else if (m->cpuvendor == X86_VENDOR_INTEL) { /* * Intel SDM Volume 3B - 15.9.2 Compound Error Codes * @@ -628,6 +626,7 @@ static bool memory_error(struct mce *m) return false; } +EXPORT_SYMBOL_GPL(mce_is_memory_error); DEFINE_PER_CPU(unsigned, mce_poll_count); @@ -691,7 +690,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b) severity = mce_severity(&m, mca_cfg.tolerant, NULL, false); - if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) + if (severity == MCE_DEFERRED_SEVERITY && mce_is_memory_error(&m)) if (m.status & MCI_STATUS_ADDRV) m.severity = severity; diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 3dfca7b302dc59e56f0770163ce9d989a18fe2e3..39526e1e3132dd1b098d8c4e0429a1aaeca35152 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -593,14 +593,14 @@ static inline void __smp_deferred_error_interrupt(void) deferred_error_int_vector(); } -asmlinkage __visible void smp_deferred_error_interrupt(void) +asmlinkage __visible void __irq_entry smp_deferred_error_interrupt(void) { entering_irq(); __smp_deferred_error_interrupt(); exiting_ack_irq(); } -asmlinkage __visible void smp_trace_deferred_error_interrupt(void) +asmlinkage __visible void __irq_entry smp_trace_deferred_error_interrupt(void) { entering_irq(); trace_deferred_error_apic_entry(DEFERRED_ERROR_VECTOR); @@ -955,6 +955,9 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank) const char *name = get_name(bank, NULL); int err = 0; + if (!dev) + return -ENODEV; + if (is_shared_bank(bank)) { nb = node_to_amd_nb(amd_get_nb_id(cpu)); diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 6b9dc4d18cccd1cd8fa6cf070b618bc878ad5a05..c460c91d0c8fd3ae89735874d695d6e03b5ed1df 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -431,14 +431,16 @@ static inline void __smp_thermal_interrupt(void) smp_thermal_vector(); } -asmlinkage __visible void smp_thermal_interrupt(struct pt_regs *regs) +asmlinkage __visible void __irq_entry +smp_thermal_interrupt(struct pt_regs *regs) { entering_irq(); __smp_thermal_interrupt(); exiting_ack_irq(); } -asmlinkage __visible void smp_trace_thermal_interrupt(struct pt_regs *regs) +asmlinkage __visible void __irq_entry +smp_trace_thermal_interrupt(struct pt_regs *regs) { entering_irq(); trace_thermal_apic_entry(THERMAL_APIC_VECTOR); diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c index fcf9ae9384f4cb4693d67cc8ee6433562dfc9f34..976042371b4b842a5088984689d6e1c8f2060ec6 100644 --- a/arch/x86/kernel/cpu/mcheck/threshold.c +++ b/arch/x86/kernel/cpu/mcheck/threshold.c @@ -24,14 +24,14 @@ static inline void __smp_threshold_interrupt(void) mce_threshold_vector(); } -asmlinkage __visible void smp_threshold_interrupt(void) +asmlinkage __visible void __irq_entry smp_threshold_interrupt(void) { entering_irq(); __smp_threshold_interrupt(); exiting_ack_irq(); } -asmlinkage __visible void smp_trace_threshold_interrupt(void) +asmlinkage __visible void __irq_entry smp_trace_threshold_interrupt(void) { entering_irq(); trace_threshold_apic_entry(THRESHOLD_APIC_VECTOR); diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 017bda12caaed9c46f60fccc90f05d861e58e1ba..b74bb29db6b94038598fb4f7931ba95a60d8d53b 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -592,6 +592,7 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, #define F14H_MPB_MAX_SIZE 1824 #define F15H_MPB_MAX_SIZE 4096 #define F16H_MPB_MAX_SIZE 3458 +#define F17H_MPB_MAX_SIZE 3200 switch (family) { case 0x14: @@ -603,6 +604,9 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, case 0x16: max_size = F16H_MPB_MAX_SIZE; break; + case 0x17: + max_size = F17H_MPB_MAX_SIZE; + break; default: max_size = F1XH_MPB_MAX_SIZE; break; diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index cdc0deab00c9ff3615da88a4591d8701a661768a..ac3e636ad586f66dcf2126506b1372f5d4cac38f 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -1046,6 +1047,27 @@ static int get_ucode_fw(void *to, const void *from, size_t n) return 0; } +static bool is_blacklisted(unsigned int cpu) +{ + struct cpuinfo_x86 *c = &cpu_data(cpu); + + /* + * Late loading on model 79 with microcode revision less than 0x0b000021 + * may result in a system hang. This behavior is documented in item + * BDF90, #334165 (Intel Xeon Processor E7-8800/4800 v4 Product Family). + */ + if (c->x86 == 6 && + c->x86_model == INTEL_FAM6_BROADWELL_X && + c->x86_mask == 0x01 && + c->microcode < 0x0b000021) { + pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); + pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); + return true; + } + + return false; +} + static enum ucode_state request_microcode_fw(int cpu, struct device *device, bool refresh_fw) { @@ -1054,6 +1076,9 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device, const struct firmware *firmware; enum ucode_state ret; + if (is_blacklisted(cpu)) + return UCODE_NFOUND; + sprintf(name, "intel-ucode/%02x-%02x-%02x", c->x86, c->x86_model, c->x86_mask); @@ -1078,6 +1103,9 @@ static int get_ucode_user(void *to, const void *from, size_t n) static enum ucode_state request_microcode_user(int cpu, const void __user *buf, size_t size) { + if (is_blacklisted(cpu)) + return UCODE_NFOUND; + return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user); } diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c index 04f89caef9c4926c40092aed725db848adc2379e..e33b38541be31dcc091fd97d1f4bd29a0ba7fe0e 100644 --- a/arch/x86/kernel/espfix_64.c +++ b/arch/x86/kernel/espfix_64.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * Note: we only need 6*8 = 48 bytes for the espfix stack, but round @@ -126,6 +127,15 @@ void __init init_espfix_bsp(void) /* Install the espfix pud into the kernel page directory */ pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)]; pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page); + /* + * Just copy the top-level PGD that is mapping the espfix + * area to ensure it is mapped into the shadow user page + * tables. + */ + if (kaiser_enabled) { + set_pgd(native_get_shadow_pgd(pgd_p), + __pgd(_KERNPG_TABLE | __pa((pud_t *)espfix_pud_page))); + } /* Randomize the locations */ init_espfix_random(); diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 2f2b8c7ccb857f636f745a5754810ea47e3d86df..6f0ab305dd5e117ce9f25651e630ea88dac2586f 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -101,6 +101,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c) * Boot time FPU feature detection code: */ unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; +EXPORT_SYMBOL_GPL(mxcsr_feature_mask); static void __init fpu__init_system_mxcsr(void) { diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index c114b132d121783545cd938f0f77979727d213ad..7052d9a65fe9b2d2d121d9561d101aaeae8a2332 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -130,11 +130,16 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, fpu__activate_fpstate_write(fpu); - if (boot_cpu_has(X86_FEATURE_XSAVES)) + if (boot_cpu_has(X86_FEATURE_XSAVES)) { ret = copyin_to_xsaves(kbuf, ubuf, xsave); - else + } else { ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); + /* xcomp_bv must be 0 when using uncompacted format */ + if (!ret && xsave->header.xcomp_bv) + ret = -EINVAL; + } + /* * In case of failure, mark all states as init: */ diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index a184c210efba117e320b9b1353b045f3363aa48d..3ec0d2d64601aa14716031ee9c187180289e651b 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -329,6 +329,10 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) } else { err = __copy_from_user(&fpu->state.xsave, buf_fx, state_size); + + /* xcomp_bv must be 0 when using uncompacted format */ + if (!err && state_size > offsetof(struct xregs_state, header) && fpu->state.xsave.header.xcomp_bv) + err = -EINVAL; } if (err || __copy_from_user(&env, buf, sizeof(env))) { diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 095ef7ddd6ae4d1c6d5476d6e63561963786e793..abfbb61b18b8ff3e7049ce2d6a35882cf331c4a9 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -1077,6 +1077,7 @@ int copyin_to_xsaves(const void *kbuf, const void __user *ubuf, * Add back in the features that came in from userspace: */ xsave->header.xfeatures |= xfeatures; + xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xsave->header.xfeatures; return 0; } diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 8639bb2ae05868ab65d88e44683f44c8651121f3..6bf09f5594b2526806842785f5e49b44e454c0e3 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -983,6 +983,18 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, unsigned long return_hooker = (unsigned long) &return_to_handler; + /* + * When resuming from suspend-to-ram, this function can be indirectly + * called from early CPU startup code while the CPU is in real mode, + * which would fail miserably. Make sure the stack pointer is a + * virtual address. + * + * This check isn't as accurate as virt_addr_valid(), but it should be + * good enough for this purpose, and it's fast. + */ + if (unlikely((long)__builtin_frame_address(0) >= 0)) + return; + if (unlikely(ftrace_graph_is_dead())) return; diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index b4421cc191b056727f8f8c0def78a750b319a1c4..67cd7c1b99daac6bbe3a7cc03673e610a5720fd8 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -190,8 +190,8 @@ ENTRY(secondary_startup_64) movq $(init_level4_pgt - __START_KERNEL_map), %rax 1: - /* Enable PAE mode and PGE */ - movl $(X86_CR4_PAE | X86_CR4_PGE), %ecx + /* Enable PAE and PSE, but defer PGE until kaiser_enabled is decided */ + movl $(X86_CR4_PAE | X86_CR4_PSE), %ecx movq %rcx, %cr4 /* Setup early boot stage 4 level pagetables. */ @@ -405,6 +405,27 @@ GLOBAL(early_recursion_flag) .balign PAGE_SIZE; \ GLOBAL(name) +#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * Each PGD needs to be 8k long and 8k aligned. We do not + * ever go out to userspace with these, so we do not + * strictly *need* the second page, but this allows us to + * have a single set_pgd() implementation that does not + * need to worry about whether it has 4k or 8k to work + * with. + * + * This ensures PGDs are 8k long: + */ +#define KAISER_USER_PGD_FILL 512 +/* This ensures they are 8k-aligned: */ +#define NEXT_PGD_PAGE(name) \ + .balign 2 * PAGE_SIZE; \ +GLOBAL(name) +#else +#define NEXT_PGD_PAGE(name) NEXT_PAGE(name) +#define KAISER_USER_PGD_FILL 0 +#endif + /* Automate the creation of 1 to 1 mapping pmd entries */ #define PMDS(START, PERM, COUNT) \ i = 0 ; \ @@ -414,9 +435,10 @@ GLOBAL(name) .endr __INITDATA -NEXT_PAGE(early_level4_pgt) +NEXT_PGD_PAGE(early_level4_pgt) .fill 511,8,0 .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE + .fill KAISER_USER_PGD_FILL,8,0 NEXT_PAGE(early_dynamic_pgts) .fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0 @@ -424,16 +446,18 @@ NEXT_PAGE(early_dynamic_pgts) .data #ifndef CONFIG_XEN -NEXT_PAGE(init_level4_pgt) +NEXT_PGD_PAGE(init_level4_pgt) .fill 512,8,0 + .fill KAISER_USER_PGD_FILL,8,0 #else -NEXT_PAGE(init_level4_pgt) +NEXT_PGD_PAGE(init_level4_pgt) .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE .org init_level4_pgt + L4_PAGE_OFFSET*8, 0 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE .org init_level4_pgt + L4_START_KERNEL*8, 0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE + .fill KAISER_USER_PGD_FILL,8,0 NEXT_PAGE(level3_ident_pgt) .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE @@ -444,6 +468,7 @@ NEXT_PAGE(level2_ident_pgt) */ PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD) #endif + .fill KAISER_USER_PGD_FILL,8,0 NEXT_PAGE(level3_kernel_pgt) .fill L3_START_KERNEL,8,0 diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 932348fbb6ea05aff88f004a0feeaa5092b0d1f6..9512529e8eabcd3ff8d6a4538774b022c6cfabda 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -354,7 +354,7 @@ static int hpet_resume(struct clock_event_device *evt, int timer) irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq)); irq_domain_activate_irq(irq_get_irq_data(hdev->irq)); - disable_irq(hdev->irq); + disable_hardirq(hdev->irq); irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); enable_irq(hdev->irq); } diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 9f669fdd20106cbb53b404e7085d31b4244bd7c7..8a7ad9fb22c15931bd1796e0cda2f46778935ff8 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -265,7 +265,7 @@ void __smp_x86_platform_ipi(void) x86_platform_ipi_callback(); } -__visible void smp_x86_platform_ipi(struct pt_regs *regs) +__visible void __irq_entry smp_x86_platform_ipi(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); @@ -316,7 +316,7 @@ __visible void smp_kvm_posted_intr_wakeup_ipi(struct pt_regs *regs) } #endif -__visible void smp_trace_x86_platform_ipi(struct pt_regs *regs) +__visible void __irq_entry smp_trace_x86_platform_ipi(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 1f38d9a4d9deaf707af2b7e658bd9e9022ba8d75..2763573ee1d2fea75a10eb7c0e78eb572e398268 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -19,6 +19,7 @@ #include #include +#include #ifdef CONFIG_DEBUG_STACKOVERFLOW @@ -54,17 +55,17 @@ DEFINE_PER_CPU(struct irq_stack *, softirq_stack); static void call_on_stack(void *func, void *stack) { asm volatile("xchgl %%ebx,%%esp \n" - "call *%%edi \n" + CALL_NOSPEC "movl %%ebx,%%esp \n" : "=b" (stack) : "0" (stack), - "D"(func) + [thunk_target] "D"(func) : "memory", "cc", "edx", "ecx", "eax"); } static inline void *current_stack(void) { - return (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1)); + return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1)); } static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) @@ -88,17 +89,17 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc) /* Save the next esp at the bottom of the stack */ prev_esp = (u32 *)irqstk; - *prev_esp = current_stack_pointer(); + *prev_esp = current_stack_pointer; if (unlikely(overflow)) call_on_stack(print_stack_overflow, isp); asm volatile("xchgl %%ebx,%%esp \n" - "call *%%edi \n" + CALL_NOSPEC "movl %%ebx,%%esp \n" : "=a" (arg1), "=b" (isp) : "0" (desc), "1" (isp), - "D" (desc->handle_irq) + [thunk_target] "D" (desc->handle_irq) : "memory", "cc", "ecx"); return 1; } @@ -139,7 +140,7 @@ void do_softirq_own_stack(void) /* Push the previous esp onto the stack */ prev_esp = (u32 *)irqstk; - *prev_esp = current_stack_pointer(); + *prev_esp = current_stack_pointer; call_on_stack(__do_softirq, isp); } diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c index 3512ba607361403e587f417cbce2775cdec428a1..275487872be2b35e7c6d01335fb08170b2cf7fa0 100644 --- a/arch/x86/kernel/irq_work.c +++ b/arch/x86/kernel/irq_work.c @@ -9,6 +9,7 @@ #include #include #include +#include static inline void __smp_irq_work_interrupt(void) { @@ -16,14 +17,14 @@ static inline void __smp_irq_work_interrupt(void) irq_work_run(); } -__visible void smp_irq_work_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_irq_work_interrupt(struct pt_regs *regs) { ipi_entering_ack_irq(); __smp_irq_work_interrupt(); exiting_irq(); } -__visible void smp_trace_irq_work_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_trace_irq_work_interrupt(struct pt_regs *regs) { ipi_entering_ack_irq(); trace_irq_work_entry(IRQ_WORK_VECTOR); diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index 1423ab1b0312269fd3130392a94a74db755cc2b5..f480b38a03c35b0e2ffa377d4d84aaa4f42f58c0 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -51,7 +51,7 @@ static struct irqaction irq2 = { .flags = IRQF_NO_THREAD, }; -DEFINE_PER_CPU(vector_irq_t, vector_irq) = { +DEFINE_PER_CPU_USER_MAPPED(vector_irq_t, vector_irq) = { [0 ... NR_VECTORS - 1] = VECTOR_UNUSED, }; diff --git a/arch/x86/kernel/kprobes/common.h b/arch/x86/kernel/kprobes/common.h index c6ee63f927ab721dd542b016bcfb22d65a55f114..d688826e5736a18c9f9343ebe278ec2b04bff66d 100644 --- a/arch/x86/kernel/kprobes/common.h +++ b/arch/x86/kernel/kprobes/common.h @@ -67,7 +67,7 @@ #endif /* Ensure if the instruction can be boostable */ -extern int can_boost(kprobe_opcode_t *instruction); +extern int can_boost(kprobe_opcode_t *instruction, void *addr); /* Recover instruction if given address is probed */ extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr); diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index d9d8d16b69db89df63b5ff33a4e597fcf4e5eba6..b55d07b9d5305ff2ba6bd9824237009969fe694e 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -166,12 +166,12 @@ NOKPROBE_SYMBOL(skip_prefixes); * Returns non-zero if opcode is boostable. * RIP relative instructions are adjusted at copying time in 64 bits mode */ -int can_boost(kprobe_opcode_t *opcodes) +int can_boost(kprobe_opcode_t *opcodes, void *addr) { kprobe_opcode_t opcode; kprobe_opcode_t *orig_opcodes = opcodes; - if (search_exception_tables((unsigned long)opcodes)) + if (search_exception_tables((unsigned long)addr)) return 0; /* Page fault may occur on this address. */ retry: @@ -416,7 +416,7 @@ static int arch_copy_kprobe(struct kprobe *p) * __copy_instruction can modify the displacement of the instruction, * but it doesn't affect boostable check. */ - if (can_boost(p->ainsn.insn)) + if (can_boost(p->ainsn.insn, p->addr)) p->ainsn.boostable = 0; else p->ainsn.boostable = -1; diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c index 5f8f0b3cc6740bc63a925c5f54e168baa8c39add..2c0b0b645a74b14dfd2b2aa00cc35678e86e5d0c 100644 --- a/arch/x86/kernel/kprobes/ftrace.c +++ b/arch/x86/kernel/kprobes/ftrace.c @@ -26,7 +26,7 @@ #include "common.h" static nokprobe_inline -int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, +void __skip_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb, unsigned long orig_ip) { /* @@ -41,20 +41,21 @@ int __skip_singlestep(struct kprobe *p, struct pt_regs *regs, __this_cpu_write(current_kprobe, NULL); if (orig_ip) regs->ip = orig_ip; - return 1; } int skip_singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - if (kprobe_ftrace(p)) - return __skip_singlestep(p, regs, kcb, 0); - else - return 0; + if (kprobe_ftrace(p)) { + __skip_singlestep(p, regs, kcb, 0); + preempt_enable_no_resched(); + return 1; + } + return 0; } NOKPROBE_SYMBOL(skip_singlestep); -/* Ftrace callback handler for kprobes */ +/* Ftrace callback handler for kprobes -- called under preepmt disabed */ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) { @@ -77,13 +78,17 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ regs->ip = ip + sizeof(kprobe_opcode_t); + /* To emulate trap based kprobes, preempt_disable here */ + preempt_disable(); __this_cpu_write(current_kprobe, p); kcb->kprobe_status = KPROBE_HIT_ACTIVE; - if (!p->pre_handler || !p->pre_handler(p, regs)) + if (!p->pre_handler || !p->pre_handler(p, regs)) { __skip_singlestep(p, regs, kcb, orig_ip); + preempt_enable_no_resched(); + } /* * If pre_handler returns !0, it sets regs->ip and - * resets current kprobe. + * resets current kprobe, and keep preempt count +1. */ } end: diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 3bb4c5f021f6a6e74af13fd6b974e6dd600b64c1..4d74f7386a6192e539c8be3d878a5d5c5fc5c8f0 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -178,7 +178,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src) while (len < RELATIVEJUMP_SIZE) { ret = __copy_instruction(dest + len, src + len); - if (!ret || !can_boost(dest + len)) + if (!ret || !can_boost(dest + len, src + len)) return -EINVAL; len += ret; } diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index edbbfc854e3998a038ffd8d94173dd4a2c9dfeee..77f17cbfe271b1b0834eb8fb27caba03a59a3cdd 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -141,7 +141,8 @@ void kvm_async_pf_task_wait(u32 token) n.token = token; n.cpu = smp_processor_id(); - n.halted = is_idle_task(current) || preempt_count() > 1; + n.halted = is_idle_task(current) || preempt_count() > 1 || + rcu_preempt_depth(); init_swait_queue_head(&n.wq); hlist_add_head(&n.link, &b->list); raw_spin_unlock(&b->lock); @@ -152,6 +153,8 @@ void kvm_async_pf_task_wait(u32 token) if (hlist_unhashed(&n.link)) break; + rcu_irq_exit(); + if (!n.halted) { local_irq_enable(); schedule(); @@ -160,11 +163,11 @@ void kvm_async_pf_task_wait(u32 token) /* * We cannot reschedule. So halt. */ - rcu_irq_exit(); native_safe_halt(); - rcu_irq_enter(); local_irq_disable(); } + + rcu_irq_enter(); } if (!n.halted) finish_swait(&n.wq, &wait); diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 6707039b9032d98ebdb21b37769d4e400fa80cd0..8bc68cfc0d33fcdc014e19c01b5f016c5afaa8a3 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -12,9 +12,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -33,11 +35,21 @@ static void flush_ldt(void *current_mm) set_ldt(pc->ldt->entries, pc->ldt->size); } +static void __free_ldt_struct(struct ldt_struct *ldt) +{ + if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE) + vfree(ldt->entries); + else + free_page((unsigned long)ldt->entries); + kfree(ldt); +} + /* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */ static struct ldt_struct *alloc_ldt_struct(int size) { struct ldt_struct *new_ldt; int alloc_size; + int ret; if (size > LDT_ENTRIES) return NULL; @@ -65,7 +77,13 @@ static struct ldt_struct *alloc_ldt_struct(int size) return NULL; } + ret = kaiser_add_mapping((unsigned long)new_ldt->entries, alloc_size, + __PAGE_KERNEL); new_ldt->size = size; + if (ret) { + __free_ldt_struct(new_ldt); + return NULL; + } return new_ldt; } @@ -91,12 +109,10 @@ static void free_ldt_struct(struct ldt_struct *ldt) if (likely(!ldt)) return; + kaiser_remove_mapping((unsigned long)ldt->entries, + ldt->size * LDT_ENTRY_SIZE); paravirt_free_ldt(ldt->entries, ldt->size); - if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE) - vfree(ldt->entries); - else - free_page((unsigned long)ldt->entries); - kfree(ldt); + __free_ldt_struct(ldt); } /* @@ -271,8 +287,8 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) return error; } -asmlinkage int sys_modify_ldt(int func, void __user *ptr, - unsigned long bytecount) +SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr , + unsigned long , bytecount) { int ret = -ENOSYS; @@ -290,5 +306,14 @@ asmlinkage int sys_modify_ldt(int func, void __user *ptr, ret = write_ldt(ptr, bytecount, 0); break; } - return ret; + /* + * The SYSCALL_DEFINE() macros give us an 'unsigned long' + * return type, but tht ABI for sys_modify_ldt() expects + * 'int'. This cast gives us an int-sized value in %rax + * for the return code. The 'unsigned' is necessary so + * the compiler does not try to sign-extend the negative + * return codes into the high half of the register when + * taking the value from int->long. + */ + return (unsigned int)ret; } diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S index 7b0d3da52fb42f288a947f1befe8886319b37ec5..287ec3bc141fc5192d2f4b09c7e24463952aa57a 100644 --- a/arch/x86/kernel/mcount_64.S +++ b/arch/x86/kernel/mcount_64.S @@ -8,7 +8,7 @@ #include #include #include - +#include .code64 .section .entry.text, "ax" @@ -290,8 +290,9 @@ trace: * ip and parent ip are used and the list function is called when * function tracing is enabled. */ - call *ftrace_trace_function + movq ftrace_trace_function, %r8 + CALL_NOSPEC %r8 restore_mcount_regs jmp fgraph_trace @@ -334,5 +335,5 @@ GLOBAL(return_to_handler) movq 8(%rsp), %rdx movq (%rsp), %rax addq $24, %rsp - jmp *%rdi + JMP_NOSPEC %rdi #endif diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c index bb3840cedb4f00c0479b8e97844816a83091ed31..ee43b36075c7f9b6e9b262887491593d531712d2 100644 --- a/arch/x86/kernel/paravirt_patch_64.c +++ b/arch/x86/kernel/paravirt_patch_64.c @@ -9,7 +9,6 @@ DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax"); DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax"); DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax"); DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3"); -DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)"); DEF_NATIVE(pv_cpu_ops, clts, "clts"); DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd"); @@ -59,7 +58,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf, PATCH_SITE(pv_mmu_ops, read_cr3); PATCH_SITE(pv_mmu_ops, write_cr3); PATCH_SITE(pv_cpu_ops, clts); - PATCH_SITE(pv_mmu_ops, flush_tlb_single); PATCH_SITE(pv_cpu_ops, wbinvd); #if defined(CONFIG_PARAVIRT_SPINLOCKS) case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock): diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 5d400ba1349df2c87bd40758578bd49122426b61..d47517941bbc03ee288848561c54b7f791a97e76 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -296,7 +296,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, /* were we called with bad_dma_address? */ badend = DMA_ERROR_CODE + (EMERGENCY_PAGES * PAGE_SIZE); - if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) { + if (unlikely(dma_addr < badend)) { WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA " "address 0x%Lx\n", dma_addr); return; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index fc7cf64587f2c8a85c744b22f7b320f2777798b2..54b2711f2dbc28041e3bb9e48ca6576f9521a7d7 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -41,7 +41,7 @@ * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = { +__visible DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct tss_struct, cpu_tss) = { .x86_tss = { .sp0 = TOP_OF_INIT_STACK, #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index b3760b3c1ca09734a4479f63f3787dac42275a24..0887d2ae3797906def2e8a51d83e6e1b5962c4a7 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -136,6 +136,123 @@ void release_thread(struct task_struct *dead_task) } } +enum which_selector { + FS, + GS +}; + +/* + * Saves the FS or GS base for an outgoing thread if FSGSBASE extensions are + * not available. The goal is to be reasonably fast on non-FSGSBASE systems. + * It's forcibly inlined because it'll generate better code and this function + * is hot. + */ +static __always_inline void save_base_legacy(struct task_struct *prev_p, + unsigned short selector, + enum which_selector which) +{ + if (likely(selector == 0)) { + /* + * On Intel (without X86_BUG_NULL_SEG), the segment base could + * be the pre-existing saved base or it could be zero. On AMD + * (with X86_BUG_NULL_SEG), the segment base could be almost + * anything. + * + * This branch is very hot (it's hit twice on almost every + * context switch between 64-bit programs), and avoiding + * the RDMSR helps a lot, so we just assume that whatever + * value is already saved is correct. This matches historical + * Linux behavior, so it won't break existing applications. + * + * To avoid leaking state, on non-X86_BUG_NULL_SEG CPUs, if we + * report that the base is zero, it needs to actually be zero: + * see the corresponding logic in load_seg_legacy. + */ + } else { + /* + * If the selector is 1, 2, or 3, then the base is zero on + * !X86_BUG_NULL_SEG CPUs and could be anything on + * X86_BUG_NULL_SEG CPUs. In the latter case, Linux + * has never attempted to preserve the base across context + * switches. + * + * If selector > 3, then it refers to a real segment, and + * saving the base isn't necessary. + */ + if (which == FS) + prev_p->thread.fsbase = 0; + else + prev_p->thread.gsbase = 0; + } +} + +static __always_inline void save_fsgs(struct task_struct *task) +{ + savesegment(fs, task->thread.fsindex); + savesegment(gs, task->thread.gsindex); + save_base_legacy(task, task->thread.fsindex, FS); + save_base_legacy(task, task->thread.gsindex, GS); +} + +static __always_inline void loadseg(enum which_selector which, + unsigned short sel) +{ + if (which == FS) + loadsegment(fs, sel); + else + load_gs_index(sel); +} + +static __always_inline void load_seg_legacy(unsigned short prev_index, + unsigned long prev_base, + unsigned short next_index, + unsigned long next_base, + enum which_selector which) +{ + if (likely(next_index <= 3)) { + /* + * The next task is using 64-bit TLS, is not using this + * segment at all, or is having fun with arcane CPU features. + */ + if (next_base == 0) { + /* + * Nasty case: on AMD CPUs, we need to forcibly zero + * the base. + */ + if (static_cpu_has_bug(X86_BUG_NULL_SEG)) { + loadseg(which, __USER_DS); + loadseg(which, next_index); + } else { + /* + * We could try to exhaustively detect cases + * under which we can skip the segment load, + * but there's really only one case that matters + * for performance: if both the previous and + * next states are fully zeroed, we can skip + * the load. + * + * (This assumes that prev_base == 0 has no + * false positives. This is the case on + * Intel-style CPUs.) + */ + if (likely(prev_index | next_index | prev_base)) + loadseg(which, next_index); + } + } else { + if (prev_index != next_index) + loadseg(which, next_index); + wrmsrl(which == FS ? MSR_FS_BASE : MSR_KERNEL_GS_BASE, + next_base); + } + } else { + /* + * The next task is using a real segment. Loading the selector + * is sufficient. + */ + loadseg(which, next_index); + } +} + int copy_thread_tls(unsigned long clone_flags, unsigned long sp, unsigned long arg, struct task_struct *p, unsigned long tls) { @@ -216,10 +333,19 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp, unsigned int _cs, unsigned int _ss, unsigned int _ds) { + WARN_ON_ONCE(regs != current_pt_regs()); + + if (static_cpu_has(X86_BUG_NULL_SEG)) { + /* Loading zero below won't clear the base. */ + loadsegment(fs, __USER_DS); + load_gs_index(__USER_DS); + } + loadsegment(fs, 0); loadsegment(es, _ds); loadsegment(ds, _ds); load_gs_index(0); + regs->ip = new_ip; regs->sp = new_sp; regs->cs = _cs; @@ -264,7 +390,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct fpu *next_fpu = &next->fpu; int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(cpu_tss, cpu); - unsigned prev_fsindex, prev_gsindex; fpu_switch_t fpu_switch; fpu_switch = switch_fpu_prepare(prev_fpu, next_fpu, cpu); @@ -274,8 +399,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) * * (e.g. xen_load_tls()) */ - savesegment(fs, prev_fsindex); - savesegment(gs, prev_gsindex); + save_fsgs(prev_p); /* * Load TLS before restoring any segments so that segment loads @@ -314,108 +438,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) if (unlikely(next->ds | prev->ds)) loadsegment(ds, next->ds); - /* - * Switch FS and GS. - * - * These are even more complicated than DS and ES: they have - * 64-bit bases are that controlled by arch_prctl. The bases - * don't necessarily match the selectors, as user code can do - * any number of things to cause them to be inconsistent. - * - * We don't promise to preserve the bases if the selectors are - * nonzero. We also don't promise to preserve the base if the - * selector is zero and the base doesn't match whatever was - * most recently passed to ARCH_SET_FS/GS. (If/when the - * FSGSBASE instructions are enabled, we'll need to offer - * stronger guarantees.) - * - * As an invariant, - * (fsbase != 0 && fsindex != 0) || (gsbase != 0 && gsindex != 0) is - * impossible. - */ - if (next->fsindex) { - /* Loading a nonzero value into FS sets the index and base. */ - loadsegment(fs, next->fsindex); - } else { - if (next->fsbase) { - /* Next index is zero but next base is nonzero. */ - if (prev_fsindex) - loadsegment(fs, 0); - wrmsrl(MSR_FS_BASE, next->fsbase); - } else { - /* Next base and index are both zero. */ - if (static_cpu_has_bug(X86_BUG_NULL_SEG)) { - /* - * We don't know the previous base and can't - * find out without RDMSR. Forcibly clear it. - */ - loadsegment(fs, __USER_DS); - loadsegment(fs, 0); - } else { - /* - * If the previous index is zero and ARCH_SET_FS - * didn't change the base, then the base is - * also zero and we don't need to do anything. - */ - if (prev->fsbase || prev_fsindex) - loadsegment(fs, 0); - } - } - } - /* - * Save the old state and preserve the invariant. - * NB: if prev_fsindex == 0, then we can't reliably learn the base - * without RDMSR because Intel user code can zero it without telling - * us and AMD user code can program any 32-bit value without telling - * us. - */ - if (prev_fsindex) - prev->fsbase = 0; - prev->fsindex = prev_fsindex; - - if (next->gsindex) { - /* Loading a nonzero value into GS sets the index and base. */ - load_gs_index(next->gsindex); - } else { - if (next->gsbase) { - /* Next index is zero but next base is nonzero. */ - if (prev_gsindex) - load_gs_index(0); - wrmsrl(MSR_KERNEL_GS_BASE, next->gsbase); - } else { - /* Next base and index are both zero. */ - if (static_cpu_has_bug(X86_BUG_NULL_SEG)) { - /* - * We don't know the previous base and can't - * find out without RDMSR. Forcibly clear it. - * - * This contains a pointless SWAPGS pair. - * Fixing it would involve an explicit check - * for Xen or a new pvop. - */ - load_gs_index(__USER_DS); - load_gs_index(0); - } else { - /* - * If the previous index is zero and ARCH_SET_GS - * didn't change the base, then the base is - * also zero and we don't need to do anything. - */ - if (prev->gsbase || prev_gsindex) - load_gs_index(0); - } - } - } - /* - * Save the old state and preserve the invariant. - * NB: if prev_gsindex == 0, then we can't reliably learn the base - * without RDMSR because Intel user code can zero it without telling - * us and AMD user code can program any 32-bit value without telling - * us. - */ - if (prev_gsindex) - prev->gsbase = 0; - prev->gsindex = prev_gsindex; + load_seg_legacy(prev->fsindex, prev->fsbase, + next->fsindex, next->fsbase, FS); + load_seg_legacy(prev->gsindex, prev->gsbase, + next->gsindex, next->gsbase, GS); switch_fpu_finish(next_fpu, fpu_switch); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 067f9813fd2cf7c15d5a1d297b537eedf6ca7959..ce020a69bba951774fff825b7e1042eb991148fa 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -106,6 +106,10 @@ void __noreturn machine_real_restart(unsigned int type) load_cr3(initial_page_table); #else write_cr3(real_mode_header->trampoline_pgd); + + /* Exiting long mode will fail if CR4.PCIDE is set. */ + if (static_cpu_has(X86_FEATURE_PCID)) + cr4_clear_bits(X86_CR4_PCIDE); #endif /* Jump to the identity-mapped low memory code */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9c337b0e8ba7c4ac5b82a3e4ad979c7d4011b4bf..6b55012d02a372d1c02116d3cdb1246368058a22 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -114,6 +114,7 @@ #include #include #include +#include /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB @@ -1019,6 +1020,12 @@ void __init setup_arch(char **cmdline_p) */ init_hypervisor_platform(); + /* + * This needs to happen right after XENPV is set on xen and + * kaiser_enabled is checked below in cleanup_highmap(). + */ + kaiser_check_boottime_disable(); + x86_init.resources.probe_roms(); /* after parse_early_param, so could debug it */ @@ -1053,6 +1060,13 @@ void __init setup_arch(char **cmdline_p) max_possible_pfn = max_pfn; + /* + * This call is required when the CPU does not support PAT. If + * mtrr_bp_init() invoked it already via pat_init() the call has no + * effect. + */ + init_cache_modes(); + /* * Define random base addresses for memory sections after max_pfn is * defined and before each memory section base is used. diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index c00cb64bc0a12e5f6f36c37215b05a3afd178db9..ca699677e288d52063b73f6b342eeb6727109170 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -259,7 +259,7 @@ static inline void __smp_reschedule_interrupt(void) scheduler_ipi(); } -__visible void smp_reschedule_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_reschedule_interrupt(struct pt_regs *regs) { irq_enter(); ack_APIC_irq(); @@ -270,7 +270,7 @@ __visible void smp_reschedule_interrupt(struct pt_regs *regs) */ } -__visible void smp_trace_reschedule_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_trace_reschedule_interrupt(struct pt_regs *regs) { /* * Need to call irq_enter() before calling the trace point. @@ -294,14 +294,15 @@ static inline void __smp_call_function_interrupt(void) inc_irq_stat(irq_call_count); } -__visible void smp_call_function_interrupt(struct pt_regs *regs) +__visible void __irq_entry smp_call_function_interrupt(struct pt_regs *regs) { ipi_entering_ack_irq(); __smp_call_function_interrupt(); exiting_irq(); } -__visible void smp_trace_call_function_interrupt(struct pt_regs *regs) +__visible void __irq_entry +smp_trace_call_function_interrupt(struct pt_regs *regs) { ipi_entering_ack_irq(); trace_call_function_entry(CALL_FUNCTION_VECTOR); @@ -316,14 +317,16 @@ static inline void __smp_call_function_single_interrupt(void) inc_irq_stat(irq_call_count); } -__visible void smp_call_function_single_interrupt(struct pt_regs *regs) +__visible void __irq_entry +smp_call_function_single_interrupt(struct pt_regs *regs) { ipi_entering_ack_irq(); __smp_call_function_single_interrupt(); exiting_irq(); } -__visible void smp_trace_call_function_single_interrupt(struct pt_regs *regs) +__visible void __irq_entry +smp_trace_call_function_single_interrupt(struct pt_regs *regs) { ipi_entering_ack_irq(); trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 36171bcd91f81c30982a0c0b826588ed19d0cde9..e803d72ef5253bc67f7d08e29f55ea9adcad5144 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -115,25 +115,16 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0xa, 0xf); spin_unlock_irqrestore(&rtc_lock, flags); - local_flush_tlb(); - pr_debug("1.\n"); *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = start_eip >> 4; - pr_debug("2.\n"); *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = start_eip & 0xf; - pr_debug("3.\n"); } static inline void smpboot_restore_warm_reset_vector(void) { unsigned long flags; - /* - * Install writable page 0 entry to set BIOS data area. - */ - local_flush_tlb(); - /* * Paranoid: Set warm reset code and vector here back * to default values. @@ -180,6 +171,12 @@ static void smp_callin(void) */ smp_store_cpu_info(cpuid); + /* + * The topology information must be up to date before + * calibrate_delay() and notify_cpu_starting(). + */ + set_cpu_sibling_map(raw_smp_processor_id()); + /* * Get our bogomips. * Update loops_per_jiffy in cpu_data. Previous call to @@ -190,11 +187,6 @@ static void smp_callin(void) cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy; pr_debug("Stack at about %p\n", &cpuid); - /* - * This must be done before setting cpu_online_mask - * or calling notify_cpu_starting. - */ - set_cpu_sibling_map(raw_smp_processor_id()); wmb(); notify_cpu_starting(cpuid); diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index a55ed63b9f91b0d45dbb476a22af9a19c4ab5fc8..1119414ab419a6ec67f310d03b12502f24bc1503 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -140,7 +140,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (end - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -183,7 +183,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/arch/x86/kernel/tracepoint.c b/arch/x86/kernel/tracepoint.c index 1c113db9ed573c3d8723fccc177431861df2bd19..2bb5ee464df3ea1855ee38e7232a38c3d10c5794 100644 --- a/arch/x86/kernel/tracepoint.c +++ b/arch/x86/kernel/tracepoint.c @@ -9,10 +9,12 @@ #include atomic_t trace_idt_ctr = ATOMIC_INIT(0); +__aligned(PAGE_SIZE) struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) trace_idt_table }; /* No need to be aligned, but done to keep all IDTs defined the same way. */ +__aligned(PAGE_SIZE) gate_desc trace_idt_table[NR_VECTORS] __page_aligned_bss; static int trace_irq_vector_refcount; diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index bd4e3d4d3625ceeb4e4e356371feb444cea94fb6..322f433fbc76b362050e1f962aff6237cf2dcb46 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -153,7 +153,7 @@ void ist_begin_non_atomic(struct pt_regs *regs) * from double_fault. */ BUG_ON((unsigned long)(current_top_of_stack() - - current_stack_pointer()) >= THREAD_SIZE); + current_stack_pointer) >= THREAD_SIZE); preempt_enable_no_resched(); } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index eea88fe5d969dd795e451f6f92e3e305bb458ea2..44bf5cf417d34fd5372868c4d4cf3969510982c5 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -694,6 +694,7 @@ unsigned long native_calibrate_tsc(void) crystal_khz = 24000; /* 24.0 MHz */ break; case INTEL_FAM6_SKYLAKE_X: + case INTEL_FAM6_ATOM_DENVERTON: crystal_khz = 25000; /* 25.0 MHz */ break; case INTEL_FAM6_ATOM_GOLDMONT: @@ -1381,12 +1382,10 @@ void __init tsc_init(void) unsigned long calibrate_delay_is_known(void) { int sibling, cpu = smp_processor_id(); - struct cpumask *mask = topology_core_cpumask(cpu); + int constant_tsc = cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC); + const struct cpumask *mask = topology_core_cpumask(cpu); - if (!tsc_disabled && !cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC)) - return 0; - - if (!mask) + if (tsc_disabled || !constant_tsc || !mask) return 0; sibling = cpumask_any_but(mask, cpu); diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 01f30e56f99e57c2e215b2925ffcc205ea651ee3..4b3012888ada93be7ba094ed82d0a520855b8cc2 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -191,7 +191,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) pte_unmap_unlock(pte, ptl); out: up_write(&mm->mmap_sem); - flush_tlb(); + flush_tlb_mm_range(mm, 0xA0000, 0xA0000 + 32*PAGE_SIZE, 0UL); } diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index afa7bbb596cd745be6494c53bd9764af503616e2..91af75e37306819f3897a95373ac51aecd73b01d 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -456,7 +456,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->ecx &= kvm_cpuid_7_0_ecx_x86_features; cpuid_mask(&entry->ecx, CPUID_7_ECX); /* PKU is not yet implemented for shadow paging. */ - if (!tdp_enabled) + if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE)) entry->ecx &= ~F(PKU); } else { entry->ebx = 0; @@ -765,18 +765,20 @@ int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid, static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i) { struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i]; - int j, nent = vcpu->arch.cpuid_nent; + struct kvm_cpuid_entry2 *ej; + int j = i; + int nent = vcpu->arch.cpuid_nent; e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT; /* when no next entry is found, the current entry[i] is reselected */ - for (j = i + 1; ; j = (j + 1) % nent) { - struct kvm_cpuid_entry2 *ej = &vcpu->arch.cpuid_entries[j]; - if (ej->function == e->function) { - ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; - return j; - } - } - return 0; /* silence gcc, even though control never reaches here */ + do { + j = (j + 1) % nent; + ej = &vcpu->arch.cpuid_entries[j]; + } while (ej->function != e->function); + + ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; + + return j; } /* find an entry with matching function, matching index (if needed), and that @@ -846,12 +848,6 @@ void kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) if (!best) best = check_cpuid_limit(vcpu, function, index); - /* - * Perfmon not yet supported for L2 guest. - */ - if (is_guest_mode(vcpu) && function == 0xa) - best = NULL; - if (best) { *eax = best->eax; *ebx = best->ebx; diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 35058c2c0eeabe0fd9dedd45999478d5cb61fabb..9368fecca3ee89de71b987313f4b370d7830dec0 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -144,6 +144,14 @@ static inline bool guest_cpuid_has_rtm(struct kvm_vcpu *vcpu) return best && (best->ebx & bit(X86_FEATURE_RTM)); } +static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry(vcpu, 7, 0); + return best && (best->ebx & bit(X86_FEATURE_MPX)); +} + static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 9f676adcdfc20bc9e7af0c421e31f7978cdbd263..c8f8dd8ca0a14baeee1255b0f6f8c3c851700515 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2395,9 +2395,21 @@ static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n) } static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, - u64 cr0, u64 cr4) + u64 cr0, u64 cr3, u64 cr4) { int bad; + u64 pcid; + + /* In order to later set CR4.PCIDE, CR3[11:0] must be zero. */ + pcid = 0; + if (cr4 & X86_CR4_PCIDE) { + pcid = cr3 & 0xfff; + cr3 &= ~0xfff; + } + + bad = ctxt->ops->set_cr(ctxt, 3, cr3); + if (bad) + return X86EMUL_UNHANDLEABLE; /* * First enable PAE, long mode needs it before CR0.PG = 1 is set. @@ -2416,6 +2428,12 @@ static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, bad = ctxt->ops->set_cr(ctxt, 4, cr4); if (bad) return X86EMUL_UNHANDLEABLE; + if (pcid) { + bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid); + if (bad) + return X86EMUL_UNHANDLEABLE; + } + } return X86EMUL_CONTINUE; @@ -2426,11 +2444,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase) struct desc_struct desc; struct desc_ptr dt; u16 selector; - u32 val, cr0, cr4; + u32 val, cr0, cr3, cr4; int i; cr0 = GET_SMSTATE(u32, smbase, 0x7ffc); - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8)); + cr3 = GET_SMSTATE(u32, smbase, 0x7ff8); ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED; ctxt->_eip = GET_SMSTATE(u32, smbase, 0x7ff0); @@ -2472,14 +2490,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase) ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8)); - return rsm_enter_protected_mode(ctxt, cr0, cr4); + return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); } static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) { struct desc_struct desc; struct desc_ptr dt; - u64 val, cr0, cr4; + u64 val, cr0, cr3, cr4; u32 base3; u16 selector; int i, r; @@ -2496,7 +2514,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1); cr0 = GET_SMSTATE(u64, smbase, 0x7f58); - ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u64, smbase, 0x7f50)); + cr3 = GET_SMSTATE(u64, smbase, 0x7f50); cr4 = GET_SMSTATE(u64, smbase, 0x7f48); ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00)); val = GET_SMSTATE(u64, smbase, 0x7ed0); @@ -2524,7 +2542,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase) dt.address = GET_SMSTATE(u64, smbase, 0x7e68); ctxt->ops->set_gdt(ctxt, &dt); - r = rsm_enter_protected_mode(ctxt, cr0, cr4); + r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); if (r != X86EMUL_CONTINUE) return r; @@ -2543,7 +2561,7 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) u64 smbase; int ret; - if ((ctxt->emul_flags & X86EMUL_SMM_MASK) == 0) + if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_MASK) == 0) return emulate_ud(ctxt); /* @@ -2592,11 +2610,11 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt) return X86EMUL_UNHANDLEABLE; } - if ((ctxt->emul_flags & X86EMUL_SMM_INSIDE_NMI_MASK) == 0) + if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_INSIDE_NMI_MASK) == 0) ctxt->ops->set_nmi_mask(ctxt, false); - ctxt->emul_flags &= ~X86EMUL_SMM_INSIDE_NMI_MASK; - ctxt->emul_flags &= ~X86EMUL_SMM_MASK; + ctxt->ops->set_hflags(ctxt, ctxt->ops->get_hflags(ctxt) & + ~(X86EMUL_SMM_INSIDE_NMI_MASK | X86EMUL_SMM_MASK)); return X86EMUL_CONTINUE; } @@ -2738,6 +2756,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) ctxt->eflags &= ~(X86_EFLAGS_VM | X86_EFLAGS_IF); } + ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0; return X86EMUL_CONTINUE; } @@ -5312,6 +5331,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) const struct x86_emulate_ops *ops = ctxt->ops; int rc = X86EMUL_CONTINUE; int saved_dst_type = ctxt->dst.type; + unsigned emul_flags; ctxt->mem_read.pos = 0; @@ -5326,6 +5346,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } + emul_flags = ctxt->ops->get_hflags(ctxt); if (unlikely(ctxt->d & (No64|Undefined|Sse|Mmx|Intercept|CheckPerm|Priv|Prot|String))) { if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) || @@ -5359,7 +5380,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) fetch_possible_mmx_operand(ctxt, &ctxt->dst); } - if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) { + if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_PRE_EXCEPT); if (rc != X86EMUL_CONTINUE) @@ -5388,7 +5409,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) goto done; } - if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { + if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_POST_EXCEPT); if (rc != X86EMUL_CONTINUE) @@ -5442,7 +5463,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) special_insn: - if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { + if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { rc = emulator_check_intercept(ctxt, ctxt->intercept, X86_ICPT_POST_MEMACCESS); if (rc != X86EMUL_CONTINUE) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 3f05c044720b7a6ab5258603a3577dd2054b9110..b24b3c6d686ea6426dcef858167ae9ec0090aa88 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -246,9 +246,14 @@ static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id) recalculate_apic_map(apic->vcpu->kvm); } +static inline u32 kvm_apic_calc_x2apic_ldr(u32 id) +{ + return ((id >> 4) << 16) | (1 << (id & 0xf)); +} + static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u32 id) { - u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf)); + u32 ldr = kvm_apic_calc_x2apic_ldr(id); kvm_lapic_set_reg(apic, APIC_ID, id); kvm_lapic_set_reg(apic, APIC_LDR, ldr); @@ -2029,6 +2034,7 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu, { if (apic_x2apic_mode(vcpu->arch.apic)) { u32 *id = (u32 *)(s->regs + APIC_ID); + u32 *ldr = (u32 *)(s->regs + APIC_LDR); if (vcpu->kvm->arch.x2apic_format) { if (*id != vcpu->vcpu_id) @@ -2039,6 +2045,10 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu, else *id <<= 24; } + + /* In x2APIC mode, the LDR is fixed and based on the id */ + if (set) + *ldr = kvm_apic_calc_x2apic_ldr(*id); } return 0; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index d9c7e986b4e4e7e0e7bd9bc28223485e42d7c3bb..0a324e120942db8a9a0aca17a9497cfd8b9393df 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3489,12 +3489,15 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch); } -static bool can_do_async_pf(struct kvm_vcpu *vcpu) +bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu) { if (unlikely(!lapic_in_kernel(vcpu) || kvm_event_needs_reinjection(vcpu))) return false; + if (is_guest_mode(vcpu)) + return false; + return kvm_x86_ops->interrupt_allowed(vcpu); } @@ -3510,7 +3513,7 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, if (!async) return false; /* *pfn has correct page already */ - if (!prefault && can_do_async_pf(vcpu)) { + if (!prefault && kvm_can_do_async_pf(vcpu)) { trace_kvm_try_async_get_page(gva, gfn); if (kvm_find_async_pf_gfn(vcpu, gfn)) { trace_kvm_async_pf_doublefault(gva, gfn); @@ -3645,13 +3648,6 @@ static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, static inline bool is_last_gpte(struct kvm_mmu *mmu, unsigned level, unsigned gpte) { - /* - * PT_PAGE_TABLE_LEVEL always terminates. The RHS has bit 7 set - * iff level <= PT_PAGE_TABLE_LEVEL, which for our purpose means - * level == PT_PAGE_TABLE_LEVEL; set PT_PAGE_SIZE_MASK in gpte then. - */ - gpte |= level - PT_PAGE_TABLE_LEVEL - 1; - /* * The RHS has bit 7 set iff level < mmu->last_nonleaf_level. * If it is clear, there are no large pages at this level, so clear @@ -3659,6 +3655,13 @@ static inline bool is_last_gpte(struct kvm_mmu *mmu, */ gpte &= level - mmu->last_nonleaf_level; + /* + * PT_PAGE_TABLE_LEVEL always terminates. The RHS has bit 7 set + * iff level <= PT_PAGE_TABLE_LEVEL, which for our purpose means + * level == PT_PAGE_TABLE_LEVEL; set PT_PAGE_SIZE_MASK in gpte then. + */ + gpte |= level - PT_PAGE_TABLE_LEVEL - 1; + return gpte & PT_PAGE_SIZE_MASK; } @@ -4166,6 +4169,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly) update_permission_bitmask(vcpu, context, true); update_pkru_bitmask(vcpu, context, true); + update_last_nonleaf_level(vcpu, context); reset_rsvds_bits_mask_ept(vcpu, context, execonly); reset_ept_shadow_zero_bits_mask(vcpu, context, execonly); } @@ -5048,13 +5052,13 @@ int kvm_mmu_module_init(void) { pte_list_desc_cache = kmem_cache_create("pte_list_desc", sizeof(struct pte_list_desc), - 0, 0, NULL); + 0, SLAB_ACCOUNT, NULL); if (!pte_list_desc_cache) goto nomem; mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header", sizeof(struct kvm_mmu_page), - 0, 0, NULL); + 0, SLAB_ACCOUNT, NULL); if (!mmu_page_header_cache) goto nomem; diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index ddc56e91f2e491ff26631ccc432b2cf15cec05a0..c92834c55c59ea43b0c34c57398ddb201b7d6281 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -75,6 +75,7 @@ enum { int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct); void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu); void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly); +bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu); static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) { diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index a01105485315ab56faffb79489f2eb55ba117c29..37363900297d3b4730424fdf6353fe8929c45c80 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -324,10 +324,11 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, --walker->level; index = PT_INDEX(addr, walker->level); - table_gfn = gpte_to_gfn(pte); offset = index * sizeof(pt_element_t); pte_gpa = gfn_to_gpa(table_gfn) + offset; + + BUG_ON(walker->level < 1); walker->table_gfn[walker->level - 1] = table_gfn; walker->pte_gpa[walker->level - 1] = pte_gpa; diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c index 9d4a8504a95a3ba687a5bd34b8ef3c58d4a5f2db..5ab4a364348e3c10987c33203be4ff6fa97e1e73 100644 --- a/arch/x86/kvm/pmu_intel.c +++ b/arch/x86/kvm/pmu_intel.c @@ -294,7 +294,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) ((u64)1 << edx.split.bit_width_fixed) - 1; } - pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) | + pmu->global_ctrl = ((1ull << pmu->nr_arch_gp_counters) - 1) | (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED); pmu->global_ctrl_mask = ~pmu->global_ctrl; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 8ca1eca5038d5ce50f6376393abb83df79c4524f..24af898fb3a69cb5a0f7e9019641bd2f847c1841 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include "trace.h" @@ -1382,6 +1383,9 @@ static void avic_vm_destroy(struct kvm *kvm) unsigned long flags; struct kvm_arch *vm_data = &kvm->arch; + if (!avic) + return; + avic_free_vm_id(vm_data->avic_vm_id); if (vm_data->avic_logical_id_table_page) @@ -2149,6 +2153,8 @@ static int ud_interception(struct vcpu_svm *svm) int er; er = emulate_instruction(&svm->vcpu, EMULTYPE_TRAP_UD); + if (er == EMULATE_USER_EXIT) + return 0; if (er != EMULATE_DONE) kvm_queue_exception(&svm->vcpu, UD_VECTOR); return 1; @@ -3583,6 +3589,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) u32 ecx = msr->index; u64 data = msr->data; switch (ecx) { + case MSR_IA32_CR_PAT: + if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data)) + return 1; + vcpu->arch.pat = data; + svm->vmcb->save.g_pat = data; + mark_dirty(svm->vmcb, VMCB_NPT); + break; case MSR_IA32_TSC: kvm_write_tsc(vcpu, msr); break; @@ -4856,6 +4869,25 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%[svm]) \n\t" "mov %%r14, %c[r14](%[svm]) \n\t" "mov %%r15, %c[r15](%[svm]) \n\t" +#endif + /* + * Clear host registers marked as clobbered to prevent + * speculative use. + */ + "xor %%" _ASM_BX ", %%" _ASM_BX " \n\t" + "xor %%" _ASM_CX ", %%" _ASM_CX " \n\t" + "xor %%" _ASM_DX ", %%" _ASM_DX " \n\t" + "xor %%" _ASM_SI ", %%" _ASM_SI " \n\t" + "xor %%" _ASM_DI ", %%" _ASM_DI " \n\t" +#ifdef CONFIG_X86_64 + "xor %%r8, %%r8 \n\t" + "xor %%r9, %%r9 \n\t" + "xor %%r10, %%r10 \n\t" + "xor %%r11, %%r11 \n\t" + "xor %%r12, %%r12 \n\t" + "xor %%r13, %%r13 \n\t" + "xor %%r14, %%r14 \n\t" + "xor %%r15, %%r15 \n\t" #endif "pop %%" _ASM_BP : @@ -4886,6 +4918,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #endif ); + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); + #ifdef CONFIG_X86_64 wrmsrl(MSR_GS_BASE, svm->host.gs_base); #else diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 43b55ef82bacab56d8668fa747e621a1d37d991e..3ca6d15994e454fffe5fb3127cb1892f53000222 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "trace.h" #include "pmu.h" @@ -857,8 +858,16 @@ static inline short vmcs_field_to_offset(unsigned long field) { BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX); - if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) || - vmcs_field_to_offset_table[field] == 0) + if (field >= ARRAY_SIZE(vmcs_field_to_offset_table)) + return -ENOENT; + + /* + * FIXME: Mitigation for CVE-2017-5753. To be replaced with a + * generic mechanism. + */ + asm("lfence"); + + if (vmcs_field_to_offset_table[field] == 0) return -ENOENT; return vmcs_field_to_offset_table[field]; @@ -1199,6 +1208,11 @@ static inline bool cpu_has_vmx_invvpid_global(void) return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT; } +static inline bool cpu_has_vmx_invvpid(void) +{ + return vmx_capability.vpid & VMX_VPID_INVVPID_BIT; +} + static inline bool cpu_has_vmx_ept(void) { return vmcs_config.cpu_based_2nd_exec_ctrl & @@ -2167,46 +2181,44 @@ static void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu) struct pi_desc old, new; unsigned int dest; - if (!kvm_arch_has_assigned_device(vcpu->kvm) || - !irq_remapping_cap(IRQ_POSTING_CAP) || - !kvm_vcpu_apicv_active(vcpu)) + /* + * In case of hot-plug or hot-unplug, we may have to undo + * vmx_vcpu_pi_put even if there is no assigned device. And we + * always keep PI.NDST up to date for simplicity: it makes the + * code easier, and CPU migration is not a fast path. + */ + if (!pi_test_sn(pi_desc) && vcpu->cpu == cpu) + return; + + /* + * First handle the simple case where no cmpxchg is necessary; just + * allow posting non-urgent interrupts. + * + * If the 'nv' field is POSTED_INTR_WAKEUP_VECTOR, do not change + * PI.NDST: pi_post_block will do it for us and the wakeup_handler + * expects the VCPU to be on the blocked_vcpu_list that matches + * PI.NDST. + */ + if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR || + vcpu->cpu == cpu) { + pi_clear_sn(pi_desc); return; + } + /* The full case. */ do { old.control = new.control = pi_desc->control; - /* - * If 'nv' field is POSTED_INTR_WAKEUP_VECTOR, there - * are two possible cases: - * 1. After running 'pre_block', context switch - * happened. For this case, 'sn' was set in - * vmx_vcpu_put(), so we need to clear it here. - * 2. After running 'pre_block', we were blocked, - * and woken up by some other guy. For this case, - * we don't need to do anything, 'pi_post_block' - * will do everything for us. However, we cannot - * check whether it is case #1 or case #2 here - * (maybe, not needed), so we also clear sn here, - * I think it is not a big deal. - */ - if (pi_desc->nv != POSTED_INTR_WAKEUP_VECTOR) { - if (vcpu->cpu != cpu) { - dest = cpu_physical_id(cpu); - - if (x2apic_enabled()) - new.ndst = dest; - else - new.ndst = (dest << 8) & 0xFF00; - } + dest = cpu_physical_id(cpu); - /* set 'NV' to 'notification vector' */ - new.nv = POSTED_INTR_VECTOR; - } + if (x2apic_enabled()) + new.ndst = dest; + else + new.ndst = (dest << 8) & 0xFF00; - /* Allow posting non-urgent interrupts */ new.sn = 0; - } while (cmpxchg(&pi_desc->control, old.control, - new.control) != old.control); + } while (cmpxchg64(&pi_desc->control, old.control, + new.control) != old.control); } static void decache_tsc_multiplier(struct vcpu_vmx *vmx) @@ -2455,7 +2467,7 @@ static int nested_vmx_check_exception(struct kvm_vcpu *vcpu, unsigned nr) if (!(vmcs12->exception_bitmap & (1u << nr))) return 0; - nested_vmx_vmexit(vcpu, to_vmx(vcpu)->exit_reason, + nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, vmcs_read32(VM_EXIT_INTR_INFO), vmcs_readl(EXIT_QUALIFICATION)); return 1; @@ -2987,7 +2999,8 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP); break; case MSR_IA32_BNDCFGS: - if (!kvm_mpx_supported()) + if (!kvm_mpx_supported() || + (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu))) return 1; msr_info->data = vmcs_read64(GUEST_BNDCFGS); break; @@ -3069,7 +3082,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vmcs_writel(GUEST_SYSENTER_ESP, data); break; case MSR_IA32_BNDCFGS: - if (!kvm_mpx_supported()) + if (!kvm_mpx_supported() || + (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu))) + return 1; + if (is_noncanonical_address(data & PAGE_MASK) || + (data & MSR_IA32_BNDCFGS_RSVD)) return 1; vmcs_write64(GUEST_BNDCFGS, data); break; @@ -3813,6 +3830,12 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu) __vmx_flush_tlb(vcpu, to_vmx(vcpu)->vpid); } +static void vmx_flush_tlb_ept_only(struct kvm_vcpu *vcpu) +{ + if (enable_ept) + vmx_flush_tlb(vcpu); +} + static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu) { ulong cr0_guest_owned_bits = vcpu->arch.cr0_guest_owned_bits; @@ -4756,21 +4779,30 @@ static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu) { #ifdef CONFIG_SMP if (vcpu->mode == IN_GUEST_MODE) { - struct vcpu_vmx *vmx = to_vmx(vcpu); - /* - * Currently, we don't support urgent interrupt, - * all interrupts are recognized as non-urgent - * interrupt, so we cannot post interrupts when - * 'SN' is set. + * The vector of interrupt to be delivered to vcpu had + * been set in PIR before this function. + * + * Following cases will be reached in this block, and + * we always send a notification event in all cases as + * explained below. + * + * Case 1: vcpu keeps in non-root mode. Sending a + * notification event posts the interrupt to vcpu. + * + * Case 2: vcpu exits to root mode and is still + * runnable. PIR will be synced to vIRR before the + * next vcpu entry. Sending a notification event in + * this case has no effect, as vcpu is not in root + * mode. * - * If the vcpu is in guest mode, it means it is - * running instead of being scheduled out and - * waiting in the run queue, and that's the only - * case when 'SN' is set currently, warning if - * 'SN' is set. + * Case 3: vcpu exits to root mode and is blocked. + * vcpu_block() has already synced PIR to vIRR and + * never blocks vcpu if vIRR is not cleared. Therefore, + * a blocked vcpu here does not wait for any requested + * interrupts in PIR, and sending a notification event + * which has no effect is safe here. */ - WARN_ON_ONCE(pi_test_sn(&vmx->pi_desc)); apic->send_IPI_mask(get_cpu_mask(vcpu->cpu), POSTED_INTR_VECTOR); @@ -5490,6 +5522,8 @@ static int handle_exception(struct kvm_vcpu *vcpu) return 1; } er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD); + if (er == EMULATE_USER_EXIT) + return 0; if (er != EMULATE_DONE) kvm_queue_exception(vcpu, UD_VECTOR); return 1; @@ -6399,12 +6433,7 @@ static __init int hardware_setup(void) memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE); memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE); - /* - * Allow direct access to the PC debug port (it is often used for I/O - * delays, but the vmexits simply slow things down). - */ memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE); - clear_bit(0x80, vmx_io_bitmap_a); memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE); @@ -6419,8 +6448,10 @@ static __init int hardware_setup(void) if (boot_cpu_has(X86_FEATURE_NX)) kvm_enable_efer_bits(EFER_NX); - if (!cpu_has_vmx_vpid()) + if (!cpu_has_vmx_vpid() || !cpu_has_vmx_invvpid() || + !(cpu_has_vmx_invvpid_single() || cpu_has_vmx_invvpid_global())) enable_vpid = 0; + if (!cpu_has_vmx_shadow_vmcs()) enable_shadow_vmcs = 0; if (enable_shadow_vmcs) @@ -6474,7 +6505,6 @@ static __init int hardware_setup(void) vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false); vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false); vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false); - vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true); memcpy(vmx_msr_bitmap_legacy_x2apic, vmx_msr_bitmap_legacy, PAGE_SIZE); @@ -7195,9 +7225,8 @@ static int handle_vmoff(struct kvm_vcpu *vcpu) static int handle_vmclear(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 zero = 0; gpa_t vmptr; - struct vmcs12 *vmcs12; - struct page *page; if (!nested_vmx_check_permission(vcpu)) return 1; @@ -7208,22 +7237,9 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) if (vmptr == vmx->nested.current_vmptr) nested_release_vmcs12(vmx); - page = nested_get_page(vcpu, vmptr); - if (page == NULL) { - /* - * For accurate processor emulation, VMCLEAR beyond available - * physical memory should do nothing at all. However, it is - * possible that a nested vmx bug, not a guest hypervisor bug, - * resulted in this case, so let's shut down before doing any - * more damage: - */ - kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); - return 1; - } - vmcs12 = kmap(page); - vmcs12->launch_state = 0; - kunmap(page); - nested_release_page(page); + kvm_vcpu_write_guest(vcpu, + vmptr + offsetof(struct vmcs12, launch_state), + &zero, sizeof(zero)); nested_free_vmcs02(vmx, vmptr); @@ -8051,8 +8067,6 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) case EXIT_REASON_TASK_SWITCH: return true; case EXIT_REASON_CPUID: - if (kvm_register_read(vcpu, VCPU_REGS_RAX) == 0xa) - return false; return true; case EXIT_REASON_HLT: return nested_cpu_has(vmcs12, CPU_BASED_HLT_EXITING); @@ -8137,6 +8151,9 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES); case EXIT_REASON_PREEMPTION_TIMER: return false; + case EXIT_REASON_PML_FULL: + /* We don't expose PML support to L1. */ + return false; default: return true; } @@ -8499,6 +8516,7 @@ static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set) } else { sec_exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE; sec_exec_control |= SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; + vmx_flush_tlb_ept_only(vcpu); } vmcs_write32(SECONDARY_VM_EXEC_CONTROL, sec_exec_control); @@ -8524,8 +8542,10 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu, hpa_t hpa) */ if (!is_guest_mode(vcpu) || !nested_cpu_has2(get_vmcs12(&vmx->vcpu), - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { vmcs_write64(APIC_ACCESS_ADDR, hpa); + vmx_flush_tlb_ept_only(vcpu); + } } static void vmx_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr) @@ -8937,6 +8957,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) /* Save guest registers, load host registers, keep flags */ "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t" "pop %0 \n\t" + "setbe %c[fail](%0)\n\t" "mov %%" _ASM_AX ", %c[rax](%0) \n\t" "mov %%" _ASM_BX ", %c[rbx](%0) \n\t" __ASM_SIZE(pop) " %c[rcx](%0) \n\t" @@ -8953,12 +8974,23 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r13, %c[r13](%0) \n\t" "mov %%r14, %c[r14](%0) \n\t" "mov %%r15, %c[r15](%0) \n\t" + "xor %%r8d, %%r8d \n\t" + "xor %%r9d, %%r9d \n\t" + "xor %%r10d, %%r10d \n\t" + "xor %%r11d, %%r11d \n\t" + "xor %%r12d, %%r12d \n\t" + "xor %%r13d, %%r13d \n\t" + "xor %%r14d, %%r14d \n\t" + "xor %%r15d, %%r15d \n\t" #endif "mov %%cr2, %%" _ASM_AX " \n\t" "mov %%" _ASM_AX ", %c[cr2](%0) \n\t" + "xor %%eax, %%eax \n\t" + "xor %%ebx, %%ebx \n\t" + "xor %%esi, %%esi \n\t" + "xor %%edi, %%edi \n\t" "pop %%" _ASM_BP "; pop %%" _ASM_DX " \n\t" - "setbe %c[fail](%0) \n\t" ".pushsection .rodata \n\t" ".global vmx_return \n\t" "vmx_return: " _ASM_PTR " 2b \n\t" @@ -8995,6 +9027,9 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) #endif ); + /* Eliminate branch target predictions from guest mode */ + vmexit_fill_RSB(); + /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */ if (debugctlmsr) update_debugctlmsr(debugctlmsr); @@ -9182,6 +9217,13 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED; + /* + * Enforce invariant: pi_desc.nv is always either POSTED_INTR_VECTOR + * or POSTED_INTR_WAKEUP_VECTOR. + */ + vmx->pi_desc.nv = POSTED_INTR_VECTOR; + vmx->pi_desc.sn = 1; + return &vmx->vcpu; free_vmcs: @@ -9541,10 +9583,8 @@ static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu, return false; page = nested_get_page(vcpu, vmcs12->msr_bitmap); - if (!page) { - WARN_ON(1); + if (!page) return false; - } msr_bitmap_l1 = (unsigned long *)kmap(page); if (!msr_bitmap_l1) { nested_release_page_clean(page); @@ -9991,6 +10031,11 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, page_to_phys(vmx->nested.virtual_apic_page)); vmcs_write32(TPR_THRESHOLD, vmcs12->tpr_threshold); + } else { +#ifdef CONFIG_X86_64 + exec_control |= CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING; +#endif } if (cpu_has_vmx_msr_bitmap() && @@ -10073,9 +10118,24 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) } + if (enable_pml) { + /* + * Conceptually we want to copy the PML address and index from + * vmcs01 here, and then back to vmcs01 on nested vmexit. But, + * since we always flush the log on each vmexit, this happens + * to be equivalent to simply resetting the fields in vmcs02. + */ + ASSERT(vmx->pml_pg); + vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg)); + vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1); + } + if (nested_cpu_has_ept(vmcs12)) { kvm_mmu_unload(vcpu); nested_ept_init_mmu_context(vcpu); + } else if (nested_cpu_has2(vmcs12, + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { + vmx_flush_tlb_ept_only(vcpu); } if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) @@ -10654,7 +10714,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, * (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask(); */ vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); - kvm_set_cr4(vcpu, vmcs12->host_cr4); + vmx_set_cr4(vcpu, vmcs12->host_cr4); nested_ept_uninit_mmu_context(vcpu); @@ -10679,6 +10739,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip); vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base); vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base); + vmcs_write32(GUEST_IDTR_LIMIT, 0xFFFF); + vmcs_write32(GUEST_GDTR_LIMIT, 0xFFFF); /* If not VM_EXIT_CLEAR_BNDCFGS, the L2 value propagates to L1. */ if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS) @@ -10814,6 +10876,10 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, vmx->nested.change_vmcs01_virtual_x2apic_mode = false; vmx_set_virtual_x2apic_mode(vcpu, vcpu->arch.apic_base & X2APIC_ENABLE); + } else if (!nested_cpu_has_ept(vmcs12) && + nested_cpu_has2(vmcs12, + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { + vmx_flush_tlb_ept_only(vcpu); } /* This is needed for same reason as it was needed in prepare_vmcs02 */ @@ -10863,8 +10929,10 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, */ static void vmx_leave_nested(struct kvm_vcpu *vcpu) { - if (is_guest_mode(vcpu)) + if (is_guest_mode(vcpu)) { + to_vmx(vcpu)->nested.nested_run_pending = 0; nested_vmx_vmexit(vcpu, -1, 0, 0); + } free_nested(to_vmx(vcpu)); } @@ -10983,6 +11051,37 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm, kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask); } +static void __pi_post_block(struct kvm_vcpu *vcpu) +{ + struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); + struct pi_desc old, new; + unsigned int dest; + + do { + old.control = new.control = pi_desc->control; + WARN(old.nv != POSTED_INTR_WAKEUP_VECTOR, + "Wakeup handler not enabled while the VCPU is blocked\n"); + + dest = cpu_physical_id(vcpu->cpu); + + if (x2apic_enabled()) + new.ndst = dest; + else + new.ndst = (dest << 8) & 0xFF00; + + /* set 'NV' to 'notification vector' */ + new.nv = POSTED_INTR_VECTOR; + } while (cmpxchg64(&pi_desc->control, old.control, + new.control) != old.control); + + if (!WARN_ON_ONCE(vcpu->pre_pcpu == -1)) { + spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu)); + list_del(&vcpu->blocked_vcpu_list); + spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu)); + vcpu->pre_pcpu = -1; + } +} + /* * This routine does the following things for vCPU which is going * to be blocked if VT-d PI is enabled. @@ -10998,7 +11097,6 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm, */ static int pi_pre_block(struct kvm_vcpu *vcpu) { - unsigned long flags; unsigned int dest; struct pi_desc old, new; struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); @@ -11008,34 +11106,20 @@ static int pi_pre_block(struct kvm_vcpu *vcpu) !kvm_vcpu_apicv_active(vcpu)) return 0; - vcpu->pre_pcpu = vcpu->cpu; - spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock, - vcpu->pre_pcpu), flags); - list_add_tail(&vcpu->blocked_vcpu_list, - &per_cpu(blocked_vcpu_on_cpu, - vcpu->pre_pcpu)); - spin_unlock_irqrestore(&per_cpu(blocked_vcpu_on_cpu_lock, - vcpu->pre_pcpu), flags); + WARN_ON(irqs_disabled()); + local_irq_disable(); + if (!WARN_ON_ONCE(vcpu->pre_pcpu != -1)) { + vcpu->pre_pcpu = vcpu->cpu; + spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu)); + list_add_tail(&vcpu->blocked_vcpu_list, + &per_cpu(blocked_vcpu_on_cpu, + vcpu->pre_pcpu)); + spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, vcpu->pre_pcpu)); + } do { old.control = new.control = pi_desc->control; - /* - * We should not block the vCPU if - * an interrupt is posted for it. - */ - if (pi_test_on(pi_desc) == 1) { - spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock, - vcpu->pre_pcpu), flags); - list_del(&vcpu->blocked_vcpu_list); - spin_unlock_irqrestore( - &per_cpu(blocked_vcpu_on_cpu_lock, - vcpu->pre_pcpu), flags); - vcpu->pre_pcpu = -1; - - return 1; - } - WARN((pi_desc->sn == 1), "Warning: SN field of posted-interrupts " "is set before blocking\n"); @@ -11057,10 +11141,15 @@ static int pi_pre_block(struct kvm_vcpu *vcpu) /* set 'NV' to 'wakeup vector' */ new.nv = POSTED_INTR_WAKEUP_VECTOR; - } while (cmpxchg(&pi_desc->control, old.control, - new.control) != old.control); + } while (cmpxchg64(&pi_desc->control, old.control, + new.control) != old.control); - return 0; + /* We should not block the vCPU if an interrupt is posted for it. */ + if (pi_test_on(pi_desc) == 1) + __pi_post_block(vcpu); + + local_irq_enable(); + return (vcpu->pre_pcpu == -1); } static int vmx_pre_block(struct kvm_vcpu *vcpu) @@ -11076,44 +11165,13 @@ static int vmx_pre_block(struct kvm_vcpu *vcpu) static void pi_post_block(struct kvm_vcpu *vcpu) { - struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); - struct pi_desc old, new; - unsigned int dest; - unsigned long flags; - - if (!kvm_arch_has_assigned_device(vcpu->kvm) || - !irq_remapping_cap(IRQ_POSTING_CAP) || - !kvm_vcpu_apicv_active(vcpu)) + if (vcpu->pre_pcpu == -1) return; - do { - old.control = new.control = pi_desc->control; - - dest = cpu_physical_id(vcpu->cpu); - - if (x2apic_enabled()) - new.ndst = dest; - else - new.ndst = (dest << 8) & 0xFF00; - - /* Allow posting non-urgent interrupts */ - new.sn = 0; - - /* set 'NV' to 'notification vector' */ - new.nv = POSTED_INTR_VECTOR; - } while (cmpxchg(&pi_desc->control, old.control, - new.control) != old.control); - - if(vcpu->pre_pcpu != -1) { - spin_lock_irqsave( - &per_cpu(blocked_vcpu_on_cpu_lock, - vcpu->pre_pcpu), flags); - list_del(&vcpu->blocked_vcpu_list); - spin_unlock_irqrestore( - &per_cpu(blocked_vcpu_on_cpu_lock, - vcpu->pre_pcpu), flags); - vcpu->pre_pcpu = -1; - } + WARN_ON(irqs_disabled()); + local_irq_disable(); + __pi_post_block(vcpu); + local_irq_enable(); } static void vmx_post_block(struct kvm_vcpu *vcpu) @@ -11141,7 +11199,7 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq, struct kvm_lapic_irq irq; struct kvm_vcpu *vcpu; struct vcpu_data vcpu_info; - int idx, ret = -EINVAL; + int idx, ret = 0; if (!kvm_arch_has_assigned_device(kvm) || !irq_remapping_cap(IRQ_POSTING_CAP) || @@ -11150,7 +11208,12 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq, idx = srcu_read_lock(&kvm->irq_srcu); irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); - BUG_ON(guest_irq >= irq_rt->nr_rt_entries); + if (guest_irq >= irq_rt->nr_rt_entries || + hlist_empty(&irq_rt->map[guest_irq])) { + pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n", + guest_irq, irq_rt->nr_rt_entries); + goto out; + } hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { if (e->type != KVM_IRQ_ROUTING_MSI) @@ -11193,12 +11256,8 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq, if (set) ret = irq_set_vcpu_affinity(host_irq, &vcpu_info); - else { - /* suppress notification event before unposting */ - pi_set_sn(vcpu_to_pi_desc(vcpu)); + else ret = irq_set_vcpu_affinity(host_irq, NULL); - pi_clear_sn(vcpu_to_pi_desc(vcpu)); - } if (ret < 0) { printk(KERN_INFO "%s: failed to update PI IRTE\n", diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e5bc139d1ba7ecddefc0aadeee9939e1ce8ca66e..d3f80cccb9aac43b95ef0d406998965738e1e6f8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -773,7 +773,8 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return 1; /* PCID can not be enabled when cr3[11:0]!=000H or EFER.LMA=0 */ - if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_MASK) || !is_long_mode(vcpu)) + if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_ASID_MASK) || + !is_long_mode(vcpu)) return 1; } @@ -1735,6 +1736,7 @@ static u64 __get_kvmclock_ns(struct kvm *kvm) { struct kvm_arch *ka = &kvm->arch; struct pvclock_vcpu_time_info hv_clock; + u64 ret; spin_lock(&ka->pvclock_gtod_sync_lock); if (!ka->use_master_clock) { @@ -1746,10 +1748,17 @@ static u64 __get_kvmclock_ns(struct kvm *kvm) hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; spin_unlock(&ka->pvclock_gtod_sync_lock); + /* both __this_cpu_read() and rdtsc() should be on the same cpu */ + get_cpu(); + kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL, &hv_clock.tsc_shift, &hv_clock.tsc_to_system_mul); - return __pvclock_read_cycles(&hv_clock, rdtsc()); + ret = __pvclock_read_cycles(&hv_clock, rdtsc()); + + put_cpu(); + + return ret; } u64 get_kvmclock_ns(struct kvm *kvm) @@ -1789,6 +1798,9 @@ static void kvm_setup_pvclock_page(struct kvm_vcpu *v) */ BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0); + if (guest_hv_clock.version & 1) + ++guest_hv_clock.version; /* first time write, random junk */ + vcpu->hv_clock.version = guest_hv_clock.version + 1; kvm_write_guest_cached(v->kvm, &vcpu->pv_time, &vcpu->hv_clock, @@ -3051,6 +3063,12 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR)) return -EINVAL; + /* INITs are latched while in SMM */ + if (events->flags & KVM_VCPUEVENT_VALID_SMM && + (events->smi.smm || events->smi.pending) && + vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) + return -EINVAL; + process_nmi(vcpu); vcpu->arch.exception.pending = events->exception.injected; vcpu->arch.exception.nr = events->exception.nr; @@ -3225,11 +3243,14 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, } } +#define XSAVE_MXCSR_OFFSET 24 + static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, struct kvm_xsave *guest_xsave) { u64 xstate_bv = *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)]; + u32 mxcsr = *(u32 *)&guest_xsave->region[XSAVE_MXCSR_OFFSET / sizeof(u32)]; if (boot_cpu_has(X86_FEATURE_XSAVE)) { /* @@ -3237,11 +3258,13 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, * CPUID leaf 0xD, index 0, EDX:EAX. This is for compatibility * with old userspace. */ - if (xstate_bv & ~kvm_supported_xcr0()) + if (xstate_bv & ~kvm_supported_xcr0() || + mxcsr & ~mxcsr_feature_mask) return -EINVAL; load_xsave(vcpu, (u8 *)guest_xsave->region); } else { - if (xstate_bv & ~XFEATURE_MASK_FPSSE) + if (xstate_bv & ~XFEATURE_MASK_FPSSE || + mxcsr & ~mxcsr_feature_mask) return -EINVAL; memcpy(&vcpu->arch.guest_fpu.state.fxsave, guest_xsave->region, sizeof(struct fxregs_state)); @@ -4241,7 +4264,7 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v) addr, n, v)) && kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, n, v)) break; - trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v); + trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, v); handled += n; addr += n; len -= n; @@ -4494,7 +4517,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes) { if (vcpu->mmio_read_completed) { trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes, - vcpu->mmio_fragments[0].gpa, *(u64 *)val); + vcpu->mmio_fragments[0].gpa, val); vcpu->mmio_read_completed = 0; return 1; } @@ -4516,14 +4539,14 @@ static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa, static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val) { - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val); + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, val); return vcpu_mmio_write(vcpu, gpa, bytes, val); } static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, void *val, int bytes) { - trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0); + trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, NULL); return X86EMUL_IO_NEEDED; } @@ -4744,16 +4767,20 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, static int kernel_pio(struct kvm_vcpu *vcpu, void *pd) { - /* TODO: String I/O for in kernel device */ - int r; + int r = 0, i; - if (vcpu->arch.pio.in) - r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port, - vcpu->arch.pio.size, pd); - else - r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, - vcpu->arch.pio.port, vcpu->arch.pio.size, - pd); + for (i = 0; i < vcpu->arch.pio.count; i++) { + if (vcpu->arch.pio.in) + r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port, + vcpu->arch.pio.size, pd); + else + r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, + vcpu->arch.pio.port, vcpu->arch.pio.size, + pd); + if (r) + break; + pd += vcpu->arch.pio.size; + } return r; } @@ -4791,6 +4818,8 @@ static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt, if (vcpu->arch.pio.count) goto data_avail; + memset(vcpu->arch.pio_data, 0, size * count); + ret = emulator_pio_in_out(vcpu, size, port, val, count, true); if (ret) { data_avail: @@ -4974,6 +5003,8 @@ static bool emulator_get_segment(struct x86_emulate_ctxt *ctxt, u16 *selector, if (var.unusable) { memset(desc, 0, sizeof(*desc)); + if (base3) + *base3 = 0; return false; } @@ -5129,6 +5160,16 @@ static void emulator_set_nmi_mask(struct x86_emulate_ctxt *ctxt, bool masked) kvm_x86_ops->set_nmi_mask(emul_to_vcpu(ctxt), masked); } +static unsigned emulator_get_hflags(struct x86_emulate_ctxt *ctxt) +{ + return emul_to_vcpu(ctxt)->arch.hflags; +} + +static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_flags) +{ + kvm_set_hflags(emul_to_vcpu(ctxt), emul_flags); +} + static const struct x86_emulate_ops emulate_ops = { .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, @@ -5168,6 +5209,8 @@ static const struct x86_emulate_ops emulate_ops = { .intercept = emulator_intercept, .get_cpuid = emulator_get_cpuid, .set_nmi_mask = emulator_set_nmi_mask, + .get_hflags = emulator_get_hflags, + .set_hflags = emulator_set_hflags, }; static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) @@ -5211,6 +5254,8 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); ctxt->eflags = kvm_get_rflags(vcpu); + ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0; + ctxt->eip = kvm_rip_read(vcpu); ctxt->mode = (!is_protmode(vcpu)) ? X86EMUL_MODE_REAL : (ctxt->eflags & X86_EFLAGS_VM) ? X86EMUL_MODE_VM86 : @@ -5220,7 +5265,6 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) BUILD_BUG_ON(HF_GUEST_MASK != X86EMUL_GUEST_MASK); BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK); BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK); - ctxt->emul_flags = vcpu->arch.hflags; init_decode_cache(ctxt); vcpu->arch.emulate_regs_need_sync_from_vcpu = false; @@ -5427,37 +5471,26 @@ static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7, return dr6; } -static void kvm_vcpu_check_singlestep(struct kvm_vcpu *vcpu, unsigned long rflags, int *r) +static void kvm_vcpu_do_singlestep(struct kvm_vcpu *vcpu, int *r) { struct kvm_run *kvm_run = vcpu->run; - /* - * rflags is the old, "raw" value of the flags. The new value has - * not been saved yet. - * - * This is correct even for TF set by the guest, because "the - * processor will not generate this exception after the instruction - * that sets the TF flag". - */ - if (unlikely(rflags & X86_EFLAGS_TF)) { - if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { - kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1 | - DR6_RTM; - kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip; - kvm_run->debug.arch.exception = DB_VECTOR; - kvm_run->exit_reason = KVM_EXIT_DEBUG; - *r = EMULATE_USER_EXIT; - } else { - vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF; - /* - * "Certain debug exceptions may clear bit 0-3. The - * remaining contents of the DR6 register are never - * cleared by the processor". - */ - vcpu->arch.dr6 &= ~15; - vcpu->arch.dr6 |= DR6_BS | DR6_RTM; - kvm_queue_exception(vcpu, DB_VECTOR); - } + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1 | DR6_RTM; + kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip; + kvm_run->debug.arch.exception = DB_VECTOR; + kvm_run->exit_reason = KVM_EXIT_DEBUG; + *r = EMULATE_USER_EXIT; + } else { + vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF; + /* + * "Certain debug exceptions may clear bit 0-3. The + * remaining contents of the DR6 register are never + * cleared by the processor". + */ + vcpu->arch.dr6 &= ~15; + vcpu->arch.dr6 |= DR6_BS | DR6_RTM; + kvm_queue_exception(vcpu, DB_VECTOR); } } @@ -5547,6 +5580,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, emulation_type)) return EMULATE_DONE; + if (ctxt->have_exception && inject_emulated_exception(vcpu)) + return EMULATE_DONE; if (emulation_type & EMULTYPE_SKIP) return EMULATE_FAIL; return handle_emulation_failure(vcpu); @@ -5611,11 +5646,10 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long rflags = kvm_x86_ops->get_rflags(vcpu); toggle_interruptibility(vcpu, ctxt->interruptibility); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; - if (vcpu->arch.hflags != ctxt->emul_flags) - kvm_set_hflags(vcpu, ctxt->emul_flags); kvm_rip_write(vcpu, ctxt->eip); - if (r == EMULATE_DONE) - kvm_vcpu_check_singlestep(vcpu, rflags, &r); + if (r == EMULATE_DONE && + (ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP))) + kvm_vcpu_do_singlestep(vcpu, &r); if (!ctxt->have_exception || exception_type(ctxt->exception.vector) == EXCPT_TRAP) __kvm_set_rflags(vcpu, ctxt->eflags); @@ -6086,7 +6120,8 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt) kvm_x86_ops->patch_hypercall(vcpu, instruction); - return emulator_write_emulated(ctxt, rip, instruction, 3, NULL); + return emulator_write_emulated(ctxt, rip, instruction, 3, + &ctxt->exception); } static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu) @@ -6492,6 +6527,20 @@ static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu) kvm_x86_ops->tlb_flush(vcpu); } +void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, + unsigned long start, unsigned long end) +{ + unsigned long apic_address; + + /* + * The physical address of apic access page is stored in the VMCS. + * Update it when it becomes invalid. + */ + apic_address = gfn_to_hva(kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT); + if (start <= apic_address && apic_address < end) + kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD); +} + void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu) { struct page *page = NULL; @@ -7084,7 +7133,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) #endif kvm_rip_write(vcpu, regs->rip); - kvm_set_rflags(vcpu, regs->rflags); + kvm_set_rflags(vcpu, regs->rflags | X86_EFLAGS_FIXED); vcpu->arch.exception.pending = false; @@ -7162,6 +7211,12 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, mp_state->mp_state != KVM_MP_STATE_RUNNABLE) return -EINVAL; + /* INITs are latched while in SMM */ + if ((is_smm(vcpu) || vcpu->arch.smi_pending) && + (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED || + mp_state->mp_state == KVM_MP_STATE_INIT_RECEIVED)) + return -EINVAL; + if (mp_state->mp_state == KVM_MP_STATE_SIPI_RECEIVED) { vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; set_bit(KVM_APIC_SIPI, &vcpu->arch.apic->pending_events); @@ -8389,11 +8444,11 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, { struct x86_exception fault; - trace_kvm_async_pf_ready(work->arch.token, work->gva); if (work->wakeup_all) work->arch.token = ~0; /* broadcast wakeup */ else kvm_del_async_pf_gfn(vcpu, work->arch.gfn); + trace_kvm_async_pf_ready(work->arch.token, work->gva); if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) && !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) { @@ -8413,8 +8468,7 @@ bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu) if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED)) return true; else - return !kvm_event_needs_reinjection(vcpu) && - kvm_x86_ops->interrupt_allowed(vcpu); + return kvm_can_do_async_pf(vcpu); } void kvm_arch_start_assignment(struct kvm *kvm) diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 34a74131a12c58ef9f38712261900093b53220f1..6bf1898ddf49077618e14504da84b794f910415b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -25,6 +25,7 @@ lib-y += memcpy_$(BITS).o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o +lib-$(CONFIG_RETPOLINE) += retpoline.o obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S index 4d34bb548b41ebdddc20fcf464aad4cb44c6a763..46e71a74e6129b861c233ccf86f452b485e62d59 100644 --- a/arch/x86/lib/checksum_32.S +++ b/arch/x86/lib/checksum_32.S @@ -29,7 +29,8 @@ #include #include #include - +#include + /* * computes a partial checksum, e.g. for TCP/UDP fragments */ @@ -156,7 +157,7 @@ ENTRY(csum_partial) negl %ebx lea 45f(%ebx,%ebx,2), %ebx testl %esi, %esi - jmp *%ebx + JMP_NOSPEC %ebx # Handle 2-byte-aligned regions 20: addw (%esi), %ax @@ -439,7 +440,7 @@ ENTRY(csum_partial_copy_generic) andl $-32,%edx lea 3f(%ebx,%ebx), %ebx testl %esi, %esi - jmp *%ebx + JMP_NOSPEC %ebx 1: addl $64,%esi addl $64,%edi SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) diff --git a/arch/x86/lib/cmdline.c b/arch/x86/lib/cmdline.c index 5cc78bf572325fb1c5b5d6f854bfe878c55dfeb3..3261abb21ef4f5e0d9c9239cc86651ee96b0a74a 100644 --- a/arch/x86/lib/cmdline.c +++ b/arch/x86/lib/cmdline.c @@ -104,7 +104,112 @@ __cmdline_find_option_bool(const char *cmdline, int max_cmdline_size, return 0; /* Buffer overrun */ } +/* + * Find a non-boolean option (i.e. option=argument). In accordance with + * standard Linux practice, if this option is repeated, this returns the + * last instance on the command line. + * + * @cmdline: the cmdline string + * @max_cmdline_size: the maximum size of cmdline + * @option: option string to look for + * @buffer: memory buffer to return the option argument + * @bufsize: size of the supplied memory buffer + * + * Returns the length of the argument (regardless of if it was + * truncated to fit in the buffer), or -1 on not found. + */ +static int +__cmdline_find_option(const char *cmdline, int max_cmdline_size, + const char *option, char *buffer, int bufsize) +{ + char c; + int pos = 0, len = -1; + const char *opptr = NULL; + char *bufptr = buffer; + enum { + st_wordstart = 0, /* Start of word/after whitespace */ + st_wordcmp, /* Comparing this word */ + st_wordskip, /* Miscompare, skip */ + st_bufcpy, /* Copying this to buffer */ + } state = st_wordstart; + + if (!cmdline) + return -1; /* No command line */ + + /* + * This 'pos' check ensures we do not overrun + * a non-NULL-terminated 'cmdline' + */ + while (pos++ < max_cmdline_size) { + c = *(char *)cmdline++; + if (!c) + break; + + switch (state) { + case st_wordstart: + if (myisspace(c)) + break; + + state = st_wordcmp; + opptr = option; + /* fall through */ + + case st_wordcmp: + if ((c == '=') && !*opptr) { + /* + * We matched all the way to the end of the + * option we were looking for, prepare to + * copy the argument. + */ + len = 0; + bufptr = buffer; + state = st_bufcpy; + break; + } else if (c == *opptr++) { + /* + * We are currently matching, so continue + * to the next character on the cmdline. + */ + break; + } + state = st_wordskip; + /* fall through */ + + case st_wordskip: + if (myisspace(c)) + state = st_wordstart; + break; + + case st_bufcpy: + if (myisspace(c)) { + state = st_wordstart; + } else { + /* + * Increment len, but don't overrun the + * supplied buffer and leave room for the + * NULL terminator. + */ + if (++len < bufsize) + *bufptr++ = c; + } + break; + } + } + + if (bufsize) + *bufptr = '\0'; + + return len; +} + int cmdline_find_option_bool(const char *cmdline, const char *option) { return __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option); } + +int cmdline_find_option(const char *cmdline, const char *option, char *buffer, + int bufsize) +{ + return __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option, + buffer, bufsize); +} diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index d376e4b48f881b89170802ab7b6aa072c458ed8f..04c067bafe248a86cb807e37d3bbe1189faf70d5 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -84,7 +84,7 @@ ENTRY(copy_user_generic_unrolled) movl %edx,%ecx andl $63,%edx shrl $6,%ecx - jz 17f + jz .L_copy_short_string 1: movq (%rsi),%r8 2: movq 1*8(%rsi),%r9 3: movq 2*8(%rsi),%r10 @@ -105,7 +105,8 @@ ENTRY(copy_user_generic_unrolled) leaq 64(%rdi),%rdi decl %ecx jnz 1b -17: movl %edx,%ecx +.L_copy_short_string: + movl %edx,%ecx andl $7,%edx shrl $3,%ecx jz 20f @@ -221,6 +222,8 @@ EXPORT_SYMBOL(copy_user_generic_string) */ ENTRY(copy_user_enhanced_fast_string) ASM_STAC + cmpl $64,%edx + jb .L_copy_short_string /* less then 64 bytes, avoid the costly 'rep' */ movl %edx,%ecx 1: rep movsb diff --git a/arch/x86/lib/memcpy_32.c b/arch/x86/lib/memcpy_32.c index cad12634d6bd8f5564b71bf7fc33d7354f149a9a..2eab7d0bfeddc6ddccee9c1318188418ebe0585e 100644 --- a/arch/x86/lib/memcpy_32.c +++ b/arch/x86/lib/memcpy_32.c @@ -6,7 +6,7 @@ __visible void *memcpy(void *to, const void *from, size_t n) { -#ifdef CONFIG_X86_USE_3DNOW +#if defined(CONFIG_X86_USE_3DNOW) && !defined(CONFIG_FORTIFY_SOURCE) return __memcpy3d(to, from, n); #else return __memcpy(to, from, n); diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S new file mode 100644 index 0000000000000000000000000000000000000000..cb45c6cb465f4b1ddea6b1a36a26f8ed3abd79db --- /dev/null +++ b/arch/x86/lib/retpoline.S @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include +#include +#include +#include +#include + +.macro THUNK reg + .section .text.__x86.indirect_thunk.\reg + +ENTRY(__x86_indirect_thunk_\reg) + CFI_STARTPROC + JMP_NOSPEC %\reg + CFI_ENDPROC +ENDPROC(__x86_indirect_thunk_\reg) +.endm + +/* + * Despite being an assembler file we can't just use .irp here + * because __KSYM_DEPS__ only uses the C preprocessor and would + * only see one instance of "__x86_indirect_thunk_\reg" rather + * than one per register with the correct names. So we do it + * the simple and nasty way... + */ +#define EXPORT_THUNK(reg) EXPORT_SYMBOL(__x86_indirect_thunk_ ## reg) +#define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg) + +GENERATE_THUNK(_ASM_AX) +GENERATE_THUNK(_ASM_BX) +GENERATE_THUNK(_ASM_CX) +GENERATE_THUNK(_ASM_DX) +GENERATE_THUNK(_ASM_SI) +GENERATE_THUNK(_ASM_DI) +GENERATE_THUNK(_ASM_BP) +GENERATE_THUNK(_ASM_SP) +#ifdef CONFIG_64BIT +GENERATE_THUNK(r8) +GENERATE_THUNK(r9) +GENERATE_THUNK(r10) +GENERATE_THUNK(r11) +GENERATE_THUNK(r12) +GENERATE_THUNK(r13) +GENERATE_THUNK(r14) +GENERATE_THUNK(r15) +#endif diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 767be7c760340bd33b7e4a18b9a8f3a71d9db33e..1754e094bc288014e1e173fe0858ebb6d9b5f1b3 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -896,7 +896,7 @@ EndTable GrpTable: Grp3_1 0: TEST Eb,Ib -1: +1: TEST Eb,Ib 2: NOT Eb 3: NEG Eb 4: MUL AL,Eb diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 96d2b847e09ea504fc3ac824d347651a3bc880b9..c548b46100cbf6d7a4f05a922a7dab4586451986 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -37,5 +37,5 @@ obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_X86_INTEL_MPX) += mpx.o obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o -obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o - +obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o +obj-$(CONFIG_PAGE_TABLE_ISOLATION) += kaiser.o diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9f72ca3b2669a62f5d512a01367d7af16a5e1ba3..8b5ff88aa4f883c05f8888ee1170e48a781fc1e5 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -191,8 +191,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really * faulted on a pte with its pkey=4. */ -static void fill_sig_info_pkey(int si_code, siginfo_t *info, - struct vm_area_struct *vma) +static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey) { /* This is effectively an #ifdef */ if (!boot_cpu_has(X86_FEATURE_OSPKE)) @@ -208,7 +207,7 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info, * valid VMA, so we should never reach this without a * valid VMA. */ - if (!vma) { + if (!pkey) { WARN_ONCE(1, "PKU fault with no VMA passed in"); info->si_pkey = 0; return; @@ -218,13 +217,12 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info, * absolutely guranteed to be 100% accurate because of * the race explained above. */ - info->si_pkey = vma_pkey(vma); + info->si_pkey = *pkey; } static void force_sig_info_fault(int si_signo, int si_code, unsigned long address, - struct task_struct *tsk, struct vm_area_struct *vma, - int fault) + struct task_struct *tsk, u32 *pkey, int fault) { unsigned lsb = 0; siginfo_t info; @@ -239,7 +237,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, lsb = PAGE_SHIFT; info.si_addr_lsb = lsb; - fill_sig_info_pkey(si_code, &info, vma); + fill_sig_info_pkey(si_code, &info, pkey); force_sig_info(si_signo, &info, tsk); } @@ -718,8 +716,6 @@ no_context(struct pt_regs *regs, unsigned long error_code, struct task_struct *tsk = current; unsigned long flags; int sig; - /* No context means no VMA to pass down */ - struct vm_area_struct *vma = NULL; /* Are we prepared to handle this kernel fault? */ if (fixup_exception(regs, X86_TRAP_PF)) { @@ -744,7 +740,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, /* XXX: hwpoison faults will set the wrong code. */ force_sig_info_fault(signal, si_code, address, - tsk, vma, 0); + tsk, NULL, 0); } /* @@ -853,8 +849,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code, static void __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, - unsigned long address, struct vm_area_struct *vma, - int si_code) + unsigned long address, u32 *pkey, int si_code) { struct task_struct *tsk = current; @@ -902,7 +897,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, tsk->thread.error_code = error_code; tsk->thread.trap_nr = X86_TRAP_PF; - force_sig_info_fault(SIGSEGV, si_code, address, tsk, vma, 0); + force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0); return; } @@ -915,9 +910,9 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, static noinline void bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, - unsigned long address, struct vm_area_struct *vma) + unsigned long address, u32 *pkey) { - __bad_area_nosemaphore(regs, error_code, address, vma, SEGV_MAPERR); + __bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR); } static void @@ -925,6 +920,10 @@ __bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address, struct vm_area_struct *vma, int si_code) { struct mm_struct *mm = current->mm; + u32 pkey; + + if (vma) + pkey = vma_pkey(vma); /* * Something tried to access memory that isn't in our memory map.. @@ -932,7 +931,8 @@ __bad_area(struct pt_regs *regs, unsigned long error_code, */ up_read(&mm->mmap_sem); - __bad_area_nosemaphore(regs, error_code, address, vma, si_code); + __bad_area_nosemaphore(regs, error_code, address, + (vma) ? &pkey : NULL, si_code); } static noinline void @@ -975,7 +975,7 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code, static void do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, - struct vm_area_struct *vma, unsigned int fault) + u32 *pkey, unsigned int fault) { struct task_struct *tsk = current; int code = BUS_ADRERR; @@ -1002,13 +1002,12 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, code = BUS_MCEERR_AR; } #endif - force_sig_info_fault(SIGBUS, code, address, tsk, vma, fault); + force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault); } static noinline void mm_fault_error(struct pt_regs *regs, unsigned long error_code, - unsigned long address, struct vm_area_struct *vma, - unsigned int fault) + unsigned long address, u32 *pkey, unsigned int fault) { if (fatal_signal_pending(current) && !(error_code & PF_USER)) { no_context(regs, error_code, address, 0, 0); @@ -1032,9 +1031,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, } else { if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| VM_FAULT_HWPOISON_LARGE)) - do_sigbus(regs, error_code, address, vma, fault); + do_sigbus(regs, error_code, address, pkey, fault); else if (fault & VM_FAULT_SIGSEGV) - bad_area_nosemaphore(regs, error_code, address, vma); + bad_area_nosemaphore(regs, error_code, address, pkey); else BUG(); } @@ -1220,6 +1219,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, struct mm_struct *mm; int fault, major = 0; unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; + u32 pkey; tsk = current; mm = tsk->mm; @@ -1393,7 +1393,17 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, * make sure we exit gracefully rather than endlessly redo * the fault. Since we never set FAULT_FLAG_RETRY_NOWAIT, if * we get VM_FAULT_RETRY back, the mmap_sem has been unlocked. + * + * Note that handle_userfault() may also release and reacquire mmap_sem + * (and not return with VM_FAULT_RETRY), when returning to userland to + * repeat the page fault later with a VM_FAULT_NOPAGE retval + * (potentially after handling any pending signal during the return to + * userland). The return to userland is identified whenever + * FAULT_FLAG_USER|FAULT_FLAG_KILLABLE are both set in flags. + * Thus we have to be careful about not touching vma after handling the + * fault, so we read the pkey beforehand. */ + pkey = vma_pkey(vma); fault = handle_mm_fault(vma, address, flags); major |= fault & VM_FAULT_MAJOR; @@ -1422,7 +1432,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, up_read(&mm->mmap_sem); if (unlikely(fault & VM_FAULT_ERROR)) { - mm_fault_error(regs, error_code, address, vma, fault); + mm_fault_error(regs, error_code, address, &pkey, fault); return; } diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 2ae8584b44c73d7c93b30b80ca643109f6e5bcf5..fe342e8ed5299c40a1270c1f9a020d0b69289811 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -144,7 +144,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 889e7619a0914d87ad49dbb5b960933e5dd316ad..f92bdb9f4e4688c500b3bbfa85069e41cb56b76c 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -177,7 +177,7 @@ static void __init probe_page_size_mask(void) cr4_set_bits_and_update_boot(X86_CR4_PSE); /* Enable PGE if available */ - if (boot_cpu_has(X86_FEATURE_PGE)) { + if (boot_cpu_has(X86_FEATURE_PGE) && !kaiser_enabled) { cr4_set_bits_and_update_boot(X86_CR4_PGE); __supported_pte_mask |= _PAGE_GLOBAL; } else @@ -764,13 +764,11 @@ void __init zone_sizes_init(void) } DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { -#ifdef CONFIG_SMP .active_mm = &init_mm, .state = 0, -#endif .cr4 = ~0UL, /* fail hard if we screw up cr4 shadow initialization */ }; -EXPORT_SYMBOL_GPL(cpu_tlbstate); +EXPORT_PER_CPU_SYMBOL(cpu_tlbstate); void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache) { diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 14b9dd71d9e864e218b28f82c95df8f011cc0c91..7df8e3a79dc0cb6b31e7ff9d27f03b2b5949f675 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -94,10 +94,10 @@ __setup("noexec32=", nonx32_setup); */ void sync_global_pgds(unsigned long start, unsigned long end, int removed) { - unsigned long address; + unsigned long addr; - for (address = start; address <= end; address += PGDIR_SIZE) { - const pgd_t *pgd_ref = pgd_offset_k(address); + for (addr = start; addr <= end; addr = ALIGN(addr + 1, PGDIR_SIZE)) { + const pgd_t *pgd_ref = pgd_offset_k(addr); struct page *page; /* @@ -113,7 +113,7 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed) pgd_t *pgd; spinlock_t *pgt_lock; - pgd = (pgd_t *)page_address(page) + pgd_index(address); + pgd = (pgd_t *)page_address(page) + pgd_index(addr); /* the pgt_lock only for Xen */ pgt_lock = &pgd_page_get_mm(page)->page_table_lock; spin_lock(pgt_lock); @@ -324,6 +324,16 @@ void __init cleanup_highmap(void) continue; if (vaddr < (unsigned long) _text || vaddr > end) set_pmd(pmd, __pmd(0)); + else if (kaiser_enabled) { + /* + * level2_kernel_pgt is initialized with _PAGE_GLOBAL: + * clear that now. This is not important, so long as + * CR4.PGE remains clear, but it removes an anomaly. + * Physical mapping setup below avoids _PAGE_GLOBAL + * by use of massage_pgprot() inside pfn_pte() etc. + */ + set_pmd(pmd, pmd_clear_flags(*pmd, _PAGE_GLOBAL)); + } } } @@ -689,7 +699,7 @@ static void __meminit free_pagetable(struct page *page, int order) if (PageReserved(page)) { __ClearPageReserved(page); - magic = (unsigned long)page->lru.next; + magic = (unsigned long)page->freelist; if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) { while (nr_pages--) put_page_bootmem(page++); diff --git a/arch/x86/mm/kaiser.c b/arch/x86/mm/kaiser.c new file mode 100644 index 0000000000000000000000000000000000000000..a8ade08a9bf5e222be78a64ae4c1ec2b0976766a --- /dev/null +++ b/arch/x86/mm/kaiser.c @@ -0,0 +1,483 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "Kernel/User page tables isolation: " fmt + +#include +#include /* to verify its kaiser declarations */ +#include +#include +#include +#include +#include + +int kaiser_enabled __read_mostly = 1; +EXPORT_SYMBOL(kaiser_enabled); /* for inlined TLB flush functions */ + +__visible +DEFINE_PER_CPU_USER_MAPPED(unsigned long, unsafe_stack_register_backup); + +/* + * These can have bit 63 set, so we can not just use a plain "or" + * instruction to get their value or'd into CR3. It would take + * another register. So, we use a memory reference to these instead. + * + * This is also handy because systems that do not support PCIDs + * just end up or'ing a 0 into their CR3, which does no harm. + */ +DEFINE_PER_CPU(unsigned long, x86_cr3_pcid_user); + +/* + * At runtime, the only things we map are some things for CPU + * hotplug, and stacks for new processes. No two CPUs will ever + * be populating the same addresses, so we only need to ensure + * that we protect between two CPUs trying to allocate and + * populate the same page table page. + * + * Only take this lock when doing a set_p[4um]d(), but it is not + * needed for doing a set_pte(). We assume that only the *owner* + * of a given allocation will be doing this for _their_ + * allocation. + * + * This ensures that once a system has been running for a while + * and there have been stacks all over and these page tables + * are fully populated, there will be no further acquisitions of + * this lock. + */ +static DEFINE_SPINLOCK(shadow_table_allocation_lock); + +/* + * Returns -1 on error. + */ +static inline unsigned long get_pa_from_mapping(unsigned long vaddr) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset_k(vaddr); + /* + * We made all the kernel PGDs present in kaiser_init(). + * We expect them to stay that way. + */ + BUG_ON(pgd_none(*pgd)); + /* + * PGDs are either 512GB or 128TB on all x86_64 + * configurations. We don't handle these. + */ + BUG_ON(pgd_large(*pgd)); + + pud = pud_offset(pgd, vaddr); + if (pud_none(*pud)) { + WARN_ON_ONCE(1); + return -1; + } + + if (pud_large(*pud)) + return (pud_pfn(*pud) << PAGE_SHIFT) | (vaddr & ~PUD_PAGE_MASK); + + pmd = pmd_offset(pud, vaddr); + if (pmd_none(*pmd)) { + WARN_ON_ONCE(1); + return -1; + } + + if (pmd_large(*pmd)) + return (pmd_pfn(*pmd) << PAGE_SHIFT) | (vaddr & ~PMD_PAGE_MASK); + + pte = pte_offset_kernel(pmd, vaddr); + if (pte_none(*pte)) { + WARN_ON_ONCE(1); + return -1; + } + + return (pte_pfn(*pte) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK); +} + +/* + * This is a relatively normal page table walk, except that it + * also tries to allocate page tables pages along the way. + * + * Returns a pointer to a PTE on success, or NULL on failure. + */ +static pte_t *kaiser_pagetable_walk(unsigned long address, bool user) +{ + pmd_t *pmd; + pud_t *pud; + pgd_t *pgd = native_get_shadow_pgd(pgd_offset_k(address)); + gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); + unsigned long prot = _KERNPG_TABLE; + + if (pgd_none(*pgd)) { + WARN_ONCE(1, "All shadow pgds should have been populated"); + return NULL; + } + BUILD_BUG_ON(pgd_large(*pgd) != 0); + + if (user) { + /* + * The vsyscall page is the only page that will have + * _PAGE_USER set. Catch everything else. + */ + BUG_ON(address != VSYSCALL_ADDR); + + set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER)); + prot = _PAGE_TABLE; + } + + pud = pud_offset(pgd, address); + /* The shadow page tables do not use large mappings: */ + if (pud_large(*pud)) { + WARN_ON(1); + return NULL; + } + if (pud_none(*pud)) { + unsigned long new_pmd_page = __get_free_page(gfp); + if (!new_pmd_page) + return NULL; + spin_lock(&shadow_table_allocation_lock); + if (pud_none(*pud)) { + set_pud(pud, __pud(prot | __pa(new_pmd_page))); + __inc_zone_page_state(virt_to_page((void *) + new_pmd_page), NR_KAISERTABLE); + } else + free_page(new_pmd_page); + spin_unlock(&shadow_table_allocation_lock); + } + + pmd = pmd_offset(pud, address); + /* The shadow page tables do not use large mappings: */ + if (pmd_large(*pmd)) { + WARN_ON(1); + return NULL; + } + if (pmd_none(*pmd)) { + unsigned long new_pte_page = __get_free_page(gfp); + if (!new_pte_page) + return NULL; + spin_lock(&shadow_table_allocation_lock); + if (pmd_none(*pmd)) { + set_pmd(pmd, __pmd(prot | __pa(new_pte_page))); + __inc_zone_page_state(virt_to_page((void *) + new_pte_page), NR_KAISERTABLE); + } else + free_page(new_pte_page); + spin_unlock(&shadow_table_allocation_lock); + } + + return pte_offset_kernel(pmd, address); +} + +static int kaiser_add_user_map(const void *__start_addr, unsigned long size, + unsigned long flags) +{ + int ret = 0; + pte_t *pte; + unsigned long start_addr = (unsigned long )__start_addr; + unsigned long address = start_addr & PAGE_MASK; + unsigned long end_addr = PAGE_ALIGN(start_addr + size); + unsigned long target_address; + + /* + * It is convenient for callers to pass in __PAGE_KERNEL etc, + * and there is no actual harm from setting _PAGE_GLOBAL, so + * long as CR4.PGE is not set. But it is nonetheless troubling + * to see Kaiser itself setting _PAGE_GLOBAL (now that "nokaiser" + * requires that not to be #defined to 0): so mask it off here. + */ + flags &= ~_PAGE_GLOBAL; + if (!(__supported_pte_mask & _PAGE_NX)) + flags &= ~_PAGE_NX; + + for (; address < end_addr; address += PAGE_SIZE) { + target_address = get_pa_from_mapping(address); + if (target_address == -1) { + ret = -EIO; + break; + } + pte = kaiser_pagetable_walk(address, flags & _PAGE_USER); + if (!pte) { + ret = -ENOMEM; + break; + } + if (pte_none(*pte)) { + set_pte(pte, __pte(flags | target_address)); + } else { + pte_t tmp; + set_pte(&tmp, __pte(flags | target_address)); + WARN_ON_ONCE(!pte_same(*pte, tmp)); + } + } + return ret; +} + +static int kaiser_add_user_map_ptrs(const void *start, const void *end, unsigned long flags) +{ + unsigned long size = end - start; + + return kaiser_add_user_map(start, size, flags); +} + +/* + * Ensure that the top level of the (shadow) page tables are + * entirely populated. This ensures that all processes that get + * forked have the same entries. This way, we do not have to + * ever go set up new entries in older processes. + * + * Note: we never free these, so there are no updates to them + * after this. + */ +static void __init kaiser_init_all_pgds(void) +{ + pgd_t *pgd; + int i = 0; + + pgd = native_get_shadow_pgd(pgd_offset_k((unsigned long )0)); + for (i = PTRS_PER_PGD / 2; i < PTRS_PER_PGD; i++) { + pgd_t new_pgd; + pud_t *pud = pud_alloc_one(&init_mm, + PAGE_OFFSET + i * PGDIR_SIZE); + if (!pud) { + WARN_ON(1); + break; + } + inc_zone_page_state(virt_to_page(pud), NR_KAISERTABLE); + new_pgd = __pgd(_KERNPG_TABLE |__pa(pud)); + /* + * Make sure not to stomp on some other pgd entry. + */ + if (!pgd_none(pgd[i])) { + WARN_ON(1); + continue; + } + set_pgd(pgd + i, new_pgd); + } +} + +#define kaiser_add_user_map_early(start, size, flags) do { \ + int __ret = kaiser_add_user_map(start, size, flags); \ + WARN_ON(__ret); \ +} while (0) + +#define kaiser_add_user_map_ptrs_early(start, end, flags) do { \ + int __ret = kaiser_add_user_map_ptrs(start, end, flags); \ + WARN_ON(__ret); \ +} while (0) + +void __init kaiser_check_boottime_disable(void) +{ + bool enable = true; + char arg[5]; + int ret; + + if (boot_cpu_has(X86_FEATURE_XENPV)) + goto silent_disable; + + ret = cmdline_find_option(boot_command_line, "pti", arg, sizeof(arg)); + if (ret > 0) { + if (!strncmp(arg, "on", 2)) + goto enable; + + if (!strncmp(arg, "off", 3)) + goto disable; + + if (!strncmp(arg, "auto", 4)) + goto skip; + } + + if (cmdline_find_option_bool(boot_command_line, "nopti")) + goto disable; + +skip: + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + goto disable; + +enable: + if (enable) + setup_force_cpu_cap(X86_FEATURE_KAISER); + + return; + +disable: + pr_info("disabled\n"); + +silent_disable: + kaiser_enabled = 0; + setup_clear_cpu_cap(X86_FEATURE_KAISER); +} + +/* + * If anything in here fails, we will likely die on one of the + * first kernel->user transitions and init will die. But, we + * will have most of the kernel up by then and should be able to + * get a clean warning out of it. If we BUG_ON() here, we run + * the risk of being before we have good console output. + */ +void __init kaiser_init(void) +{ + int cpu; + + if (!kaiser_enabled) + return; + + kaiser_init_all_pgds(); + + /* + * Note that this sets _PAGE_USER and it needs to happen when the + * pagetable hierarchy gets created, i.e., early. Otherwise + * kaiser_pagetable_walk() will encounter initialized PTEs in the + * hierarchy and not set the proper permissions, leading to the + * pagefaults with page-protection violations when trying to read the + * vsyscall page. For example. + */ + if (vsyscall_enabled()) + kaiser_add_user_map_early((void *)VSYSCALL_ADDR, + PAGE_SIZE, + __PAGE_KERNEL_VSYSCALL); + + for_each_possible_cpu(cpu) { + void *percpu_vaddr = __per_cpu_user_mapped_start + + per_cpu_offset(cpu); + unsigned long percpu_sz = __per_cpu_user_mapped_end - + __per_cpu_user_mapped_start; + kaiser_add_user_map_early(percpu_vaddr, percpu_sz, + __PAGE_KERNEL); + } + + /* + * Map the entry/exit text section, which is needed at + * switches from user to and from kernel. + */ + kaiser_add_user_map_ptrs_early(__entry_text_start, __entry_text_end, + __PAGE_KERNEL_RX); + +#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN) + kaiser_add_user_map_ptrs_early(__irqentry_text_start, + __irqentry_text_end, + __PAGE_KERNEL_RX); +#endif + kaiser_add_user_map_early((void *)idt_descr.address, + sizeof(gate_desc) * NR_VECTORS, + __PAGE_KERNEL_RO); +#ifdef CONFIG_TRACING + kaiser_add_user_map_early(&trace_idt_descr, + sizeof(trace_idt_descr), + __PAGE_KERNEL); + kaiser_add_user_map_early(&trace_idt_table, + sizeof(gate_desc) * NR_VECTORS, + __PAGE_KERNEL); +#endif + kaiser_add_user_map_early(&debug_idt_descr, sizeof(debug_idt_descr), + __PAGE_KERNEL); + kaiser_add_user_map_early(&debug_idt_table, + sizeof(gate_desc) * NR_VECTORS, + __PAGE_KERNEL); + + pr_info("enabled\n"); +} + +/* Add a mapping to the shadow mapping, and synchronize the mappings */ +int kaiser_add_mapping(unsigned long addr, unsigned long size, unsigned long flags) +{ + if (!kaiser_enabled) + return 0; + return kaiser_add_user_map((const void *)addr, size, flags); +} + +void kaiser_remove_mapping(unsigned long start, unsigned long size) +{ + extern void unmap_pud_range_nofree(pgd_t *pgd, + unsigned long start, unsigned long end); + unsigned long end = start + size; + unsigned long addr, next; + pgd_t *pgd; + + if (!kaiser_enabled) + return; + pgd = native_get_shadow_pgd(pgd_offset_k(start)); + for (addr = start; addr < end; pgd++, addr = next) { + next = pgd_addr_end(addr, end); + unmap_pud_range_nofree(pgd, addr, next); + } +} + +/* + * Page table pages are page-aligned. The lower half of the top + * level is used for userspace and the top half for the kernel. + * This returns true for user pages that need to get copied into + * both the user and kernel copies of the page tables, and false + * for kernel pages that should only be in the kernel copy. + */ +static inline bool is_userspace_pgd(pgd_t *pgdp) +{ + return ((unsigned long)pgdp % PAGE_SIZE) < (PAGE_SIZE / 2); +} + +pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd) +{ + if (!kaiser_enabled) + return pgd; + /* + * Do we need to also populate the shadow pgd? Check _PAGE_USER to + * skip cases like kexec and EFI which make temporary low mappings. + */ + if (pgd.pgd & _PAGE_USER) { + if (is_userspace_pgd(pgdp)) { + native_get_shadow_pgd(pgdp)->pgd = pgd.pgd; + /* + * Even if the entry is *mapping* userspace, ensure + * that userspace can not use it. This way, if we + * get out to userspace running on the kernel CR3, + * userspace will crash instead of running. + */ + if (__supported_pte_mask & _PAGE_NX) + pgd.pgd |= _PAGE_NX; + } + } else if (!pgd.pgd) { + /* + * pgd_clear() cannot check _PAGE_USER, and is even used to + * clear corrupted pgd entries: so just rely on cases like + * kexec and EFI never to be using pgd_clear(). + */ + if (!WARN_ON_ONCE((unsigned long)pgdp & PAGE_SIZE) && + is_userspace_pgd(pgdp)) + native_get_shadow_pgd(pgdp)->pgd = pgd.pgd; + } + return pgd; +} + +void kaiser_setup_pcid(void) +{ + unsigned long user_cr3 = KAISER_SHADOW_PGD_OFFSET; + + if (this_cpu_has(X86_FEATURE_PCID)) + user_cr3 |= X86_CR3_PCID_USER_NOFLUSH; + /* + * These variables are used by the entry/exit + * code to change PCID and pgd and TLB flushing. + */ + this_cpu_write(x86_cr3_pcid_user, user_cr3); +} + +/* + * Make a note that this cpu will need to flush USER tlb on return to user. + * If cpu does not have PCID, then the NOFLUSH bit will never have been set. + */ +void kaiser_flush_tlb_on_return_to_user(void) +{ + if (this_cpu_has(X86_FEATURE_PCID)) + this_cpu_write(x86_cr3_pcid_user, + X86_CR3_PCID_USER_FLUSH | KAISER_SHADOW_PGD_OFFSET); +} +EXPORT_SYMBOL(kaiser_flush_tlb_on_return_to_user); diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index aed206475aa7c04892443646efa6e88a9e5f4d24..319183d936024d8292fcb3739c58381cac1a73b7 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -189,6 +189,6 @@ void __meminit init_trampoline(void) *pud_tramp = *pud; } - set_pgd(&trampoline_pgd_entry, - __pgd(_KERNPG_TABLE | __pa(pud_page_tramp))); + /* Avoid set_pgd(), in case it's complicated by CONFIG_PAGE_TABLE_ISOLATION */ + trampoline_pgd_entry = __pgd(_KERNPG_TABLE | __pa(pud_page_tramp)); } diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index e4f800999b32dc94d5ba1a1283591649a818fbb7..a75103e7f9632dc9f8864f8834e4ed275857de17 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -293,7 +293,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs) * We were not able to extract an address from the instruction, * probably because there was something invalid in it. */ - if (info->si_addr == (void *)-1) { + if (info->si_addr == (void __user *)-1) { err = -EINVAL; goto err_out; } @@ -525,15 +525,7 @@ int mpx_handle_bd_fault(void) if (!kernel_managing_mpx_tables(current->mm)) return -EINVAL; - if (do_mpx_bt_fault()) { - force_sig(SIGSEGV, current); - /* - * The force_sig() is essentially "handling" this - * exception, so we do not pass up the error - * from do_mpx_bt_fault(). - */ - } - return 0; + return do_mpx_bt_fault(); } /* diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 6b7ce6279133edc52912c7032d521c79aac6ae34..aca6295350f30df220c63a282cede3ccd660096d 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -100,5 +100,6 @@ void __init initmem_init(void) printk(KERN_DEBUG "High memory starts at vaddr %08lx\n", (ulong) pfn_to_kaddr(highstart_pfn)); + __vmalloc_start_set = true; setup_bootmem_allocator(); } diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index e3353c97d0862d2a20bdd060fc229af2de8324bb..73dcb0e18c1b81c30f4330d5472d017fe02842fa 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -52,6 +52,7 @@ static DEFINE_SPINLOCK(cpa_lock); #define CPA_FLUSHTLB 1 #define CPA_ARRAY 2 #define CPA_PAGES_ARRAY 4 +#define CPA_FREE_PAGETABLES 8 #ifdef CONFIG_PROC_FS static unsigned long direct_pages_count[PG_LEVEL_NUM]; @@ -729,10 +730,13 @@ static int split_large_page(struct cpa_data *cpa, pte_t *kpte, return 0; } -static bool try_to_free_pte_page(pte_t *pte) +static bool try_to_free_pte_page(struct cpa_data *cpa, pte_t *pte) { int i; + if (!(cpa->flags & CPA_FREE_PAGETABLES)) + return false; + for (i = 0; i < PTRS_PER_PTE; i++) if (!pte_none(pte[i])) return false; @@ -741,10 +745,13 @@ static bool try_to_free_pte_page(pte_t *pte) return true; } -static bool try_to_free_pmd_page(pmd_t *pmd) +static bool try_to_free_pmd_page(struct cpa_data *cpa, pmd_t *pmd) { int i; + if (!(cpa->flags & CPA_FREE_PAGETABLES)) + return false; + for (i = 0; i < PTRS_PER_PMD; i++) if (!pmd_none(pmd[i])) return false; @@ -753,7 +760,9 @@ static bool try_to_free_pmd_page(pmd_t *pmd) return true; } -static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end) +static bool unmap_pte_range(struct cpa_data *cpa, pmd_t *pmd, + unsigned long start, + unsigned long end) { pte_t *pte = pte_offset_kernel(pmd, start); @@ -764,22 +773,23 @@ static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end) pte++; } - if (try_to_free_pte_page((pte_t *)pmd_page_vaddr(*pmd))) { + if (try_to_free_pte_page(cpa, (pte_t *)pmd_page_vaddr(*pmd))) { pmd_clear(pmd); return true; } return false; } -static void __unmap_pmd_range(pud_t *pud, pmd_t *pmd, +static void __unmap_pmd_range(struct cpa_data *cpa, pud_t *pud, pmd_t *pmd, unsigned long start, unsigned long end) { - if (unmap_pte_range(pmd, start, end)) - if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) + if (unmap_pte_range(cpa, pmd, start, end)) + if (try_to_free_pmd_page(cpa, (pmd_t *)pud_page_vaddr(*pud))) pud_clear(pud); } -static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) +static void unmap_pmd_range(struct cpa_data *cpa, pud_t *pud, + unsigned long start, unsigned long end) { pmd_t *pmd = pmd_offset(pud, start); @@ -790,7 +800,7 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) unsigned long next_page = (start + PMD_SIZE) & PMD_MASK; unsigned long pre_end = min_t(unsigned long, end, next_page); - __unmap_pmd_range(pud, pmd, start, pre_end); + __unmap_pmd_range(cpa, pud, pmd, start, pre_end); start = pre_end; pmd++; @@ -803,7 +813,8 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) if (pmd_large(*pmd)) pmd_clear(pmd); else - __unmap_pmd_range(pud, pmd, start, start + PMD_SIZE); + __unmap_pmd_range(cpa, pud, pmd, + start, start + PMD_SIZE); start += PMD_SIZE; pmd++; @@ -813,17 +824,19 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) * 4K leftovers? */ if (start < end) - return __unmap_pmd_range(pud, pmd, start, end); + return __unmap_pmd_range(cpa, pud, pmd, start, end); /* * Try again to free the PMD page if haven't succeeded above. */ if (!pud_none(*pud)) - if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) + if (try_to_free_pmd_page(cpa, (pmd_t *)pud_page_vaddr(*pud))) pud_clear(pud); } -static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) +static void __unmap_pud_range(struct cpa_data *cpa, pgd_t *pgd, + unsigned long start, + unsigned long end) { pud_t *pud = pud_offset(pgd, start); @@ -834,7 +847,7 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) unsigned long next_page = (start + PUD_SIZE) & PUD_MASK; unsigned long pre_end = min_t(unsigned long, end, next_page); - unmap_pmd_range(pud, start, pre_end); + unmap_pmd_range(cpa, pud, start, pre_end); start = pre_end; pud++; @@ -848,7 +861,7 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) if (pud_large(*pud)) pud_clear(pud); else - unmap_pmd_range(pud, start, start + PUD_SIZE); + unmap_pmd_range(cpa, pud, start, start + PUD_SIZE); start += PUD_SIZE; pud++; @@ -858,7 +871,7 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) * 2M leftovers? */ if (start < end) - unmap_pmd_range(pud, start, end); + unmap_pmd_range(cpa, pud, start, end); /* * No need to try to free the PUD page because we'll free it in @@ -866,6 +879,24 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) */ } +static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) +{ + struct cpa_data cpa = { + .flags = CPA_FREE_PAGETABLES, + }; + + __unmap_pud_range(&cpa, pgd, start, end); +} + +void unmap_pud_range_nofree(pgd_t *pgd, unsigned long start, unsigned long end) +{ + struct cpa_data cpa = { + .flags = 0, + }; + + __unmap_pud_range(&cpa, pgd, start, end); +} + static int alloc_pte_page(pmd_t *pmd) { pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 83e701f160a9128dc72316376d8b6a66233e223c..89d7907c42188b30c05143f9ac52a752e07b026d 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -36,14 +36,14 @@ #undef pr_fmt #define pr_fmt(fmt) "" fmt -static bool boot_cpu_done; - -static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT); -static void init_cache_modes(void); +static bool __read_mostly boot_cpu_done; +static bool __read_mostly pat_disabled = !IS_ENABLED(CONFIG_X86_PAT); +static bool __read_mostly pat_initialized; +static bool __read_mostly init_cm_done; void pat_disable(const char *reason) { - if (!__pat_enabled) + if (pat_disabled) return; if (boot_cpu_done) { @@ -51,10 +51,8 @@ void pat_disable(const char *reason) return; } - __pat_enabled = 0; + pat_disabled = true; pr_info("x86/PAT: %s\n", reason); - - init_cache_modes(); } static int __init nopat(char *str) @@ -66,7 +64,7 @@ early_param("nopat", nopat); bool pat_enabled(void) { - return !!__pat_enabled; + return pat_initialized; } EXPORT_SYMBOL_GPL(pat_enabled); @@ -204,6 +202,8 @@ static void __init_cache_modes(u64 pat) update_cache_mode_entry(i, cache); } pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg); + + init_cm_done = true; } #define PAT(x, y) ((u64)PAT_ ## y << ((x)*8)) @@ -224,6 +224,7 @@ static void pat_bsp_init(u64 pat) } wrmsrl(MSR_IA32_CR_PAT, pat); + pat_initialized = true; __init_cache_modes(pat); } @@ -241,10 +242,9 @@ static void pat_ap_init(u64 pat) wrmsrl(MSR_IA32_CR_PAT, pat); } -static void init_cache_modes(void) +void init_cache_modes(void) { u64 pat = 0; - static int init_cm_done; if (init_cm_done) return; @@ -286,8 +286,6 @@ static void init_cache_modes(void) } __init_cache_modes(pat); - - init_cm_done = 1; } /** @@ -305,10 +303,8 @@ void pat_init(void) u64 pat; struct cpuinfo_x86 *c = &boot_cpu_data; - if (!pat_enabled()) { - init_cache_modes(); + if (pat_disabled) return; - } if ((c->x86_vendor == X86_VENDOR_INTEL) && (((c->x86 == 0x6) && (c->x86_model <= 0xd)) || diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 3feec5af4e67c096b9bd663edc4a94fb587f67bb..209b9465e97a9ad4583087afbe3cd0b508b1990d 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -344,14 +344,15 @@ static inline void _pgd_free(pgd_t *pgd) kmem_cache_free(pgd_cache, pgd); } #else + static inline pgd_t *_pgd_alloc(void) { - return (pgd_t *)__get_free_page(PGALLOC_GFP); + return (pgd_t *)__get_free_pages(PGALLOC_GFP, PGD_ALLOCATION_ORDER); } static inline void _pgd_free(pgd_t *pgd) { - free_page((unsigned long)pgd); + free_pages((unsigned long)pgd, PGD_ALLOCATION_ORDER); } #endif /* CONFIG_X86_PAE */ diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index a7655f6caf7dbd641dfea7c3e60581e01df594cb..578973ade71b016c3537dc7a864a60753b5e36a7 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -6,16 +6,17 @@ #include #include #include +#include #include #include #include #include #include -#include +#include /* - * Smarter SMP flushing macros. + * TLB flushing, formerly SMP-only * c/o Linus Torvalds. * * These mean you can really definitely utterly forget about @@ -28,14 +29,42 @@ * Implement flush IPI by CALL_FUNCTION_VECTOR, Alex Shi */ -#ifdef CONFIG_SMP - struct flush_tlb_info { struct mm_struct *flush_mm; unsigned long flush_start; unsigned long flush_end; }; +static void load_new_mm_cr3(pgd_t *pgdir) +{ + unsigned long new_mm_cr3 = __pa(pgdir); + + if (kaiser_enabled) { + /* + * We reuse the same PCID for different tasks, so we must + * flush all the entries for the PCID out when we change tasks. + * Flush KERN below, flush USER when returning to userspace in + * kaiser's SWITCH_USER_CR3 (_SWITCH_TO_USER_CR3) macro. + * + * invpcid_flush_single_context(X86_CR3_PCID_ASID_USER) could + * do it here, but can only be used if X86_FEATURE_INVPCID is + * available - and many machines support pcid without invpcid. + * + * If X86_CR3_PCID_KERN_FLUSH actually added something, then it + * would be needed in the write_cr3() below - if PCIDs enabled. + */ + BUILD_BUG_ON(X86_CR3_PCID_KERN_FLUSH); + kaiser_flush_tlb_on_return_to_user(); + } + + /* + * Caution: many callers of this function expect + * that load_cr3() is serializing and orders TLB + * fills with respect to the mm_cpumask writes. + */ + write_cr3(new_mm_cr3); +} + /* * We cannot call mmdrop() because we are in interrupt context, * instead update mm->cpu_vm_mask. @@ -47,7 +76,7 @@ void leave_mm(int cpu) BUG(); if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) { cpumask_clear_cpu(cpu, mm_cpumask(active_mm)); - load_cr3(swapper_pg_dir); + load_new_mm_cr3(swapper_pg_dir); /* * This gets called in the idle path where RCU * functions differently. Tracing normally @@ -59,8 +88,6 @@ void leave_mm(int cpu) } EXPORT_SYMBOL_GPL(leave_mm); -#endif /* CONFIG_SMP */ - void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { @@ -83,7 +110,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * mapped in the new pgd, we'll double-fault. Forcibly * map it. */ - unsigned int stack_pgd_index = pgd_index(current_stack_pointer()); + unsigned int stack_pgd_index = pgd_index(current_stack_pointer); pgd_t *pgd = next->pgd + stack_pgd_index; @@ -91,10 +118,8 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, set_pgd(pgd, init_mm.pgd[stack_pgd_index]); } -#ifdef CONFIG_SMP this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); this_cpu_write(cpu_tlbstate.active_mm, next); -#endif cpumask_set_cpu(cpu, mm_cpumask(next)); @@ -126,7 +151,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * ordering guarantee we need. * */ - load_cr3(next->pgd); + load_new_mm_cr3(next->pgd); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); @@ -152,9 +177,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, if (unlikely(prev->context.ldt != next->context.ldt)) load_mm_ldt(next); #endif - } -#ifdef CONFIG_SMP - else { + } else { this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next); @@ -175,17 +198,14 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * As above, load_cr3() is serializing and orders TLB * fills with respect to the mm_cpumask write. */ - load_cr3(next->pgd); + load_new_mm_cr3(next->pgd); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); load_mm_cr4(next); load_mm_ldt(next); } } -#endif } -#ifdef CONFIG_SMP - /* * The flush IPI assumes that a thread switch happens in this order: * [cpu0: the cpu that switches] @@ -263,8 +283,6 @@ void native_flush_tlb_others(const struct cpumask *cpumask, { struct flush_tlb_info info; - if (end == 0) - end = start + PAGE_SIZE; info.flush_mm = mm; info.flush_start = start; info.flush_end = end; @@ -289,23 +307,6 @@ void native_flush_tlb_others(const struct cpumask *cpumask, smp_call_function_many(cpumask, flush_tlb_func, &info, 1); } -void flush_tlb_current_task(void) -{ - struct mm_struct *mm = current->mm; - - preempt_disable(); - - count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); - - /* This is an implicit full barrier that synchronizes with switch_mm. */ - local_flush_tlb(); - - trace_tlb_flush(TLB_LOCAL_SHOOTDOWN, TLB_FLUSH_ALL); - if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) - flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL); - preempt_enable(); -} - /* * See Documentation/x86/tlb.txt for details. We choose 33 * because it is large enough to cover the vast majority (at @@ -326,6 +327,12 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long base_pages_to_flush = TLB_FLUSH_ALL; preempt_disable(); + + if ((end != TLB_FLUSH_ALL) && !(vmflag & VM_HUGETLB)) + base_pages_to_flush = (end - start) >> PAGE_SHIFT; + if (base_pages_to_flush > tlb_single_page_flush_ceiling) + base_pages_to_flush = TLB_FLUSH_ALL; + if (current->active_mm != mm) { /* Synchronize with switch_mm. */ smp_mb(); @@ -342,15 +349,11 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, goto out; } - if ((end != TLB_FLUSH_ALL) && !(vmflag & VM_HUGETLB)) - base_pages_to_flush = (end - start) >> PAGE_SHIFT; - /* * Both branches below are implicit full barriers (MOV to CR or * INVLPG) that synchronize with switch_mm. */ - if (base_pages_to_flush > tlb_single_page_flush_ceiling) { - base_pages_to_flush = TLB_FLUSH_ALL; + if (base_pages_to_flush == TLB_FLUSH_ALL) { count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL); local_flush_tlb(); } else { @@ -371,33 +374,6 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, preempt_enable(); } -void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) -{ - struct mm_struct *mm = vma->vm_mm; - - preempt_disable(); - - if (current->active_mm == mm) { - if (current->mm) { - /* - * Implicit full barrier (INVLPG) that synchronizes - * with switch_mm. - */ - __flush_tlb_one(start); - } else { - leave_mm(smp_processor_id()); - - /* Synchronize with switch_mm. */ - smp_mb(); - } - } - - if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids) - flush_tlb_others(mm_cpumask(mm), mm, start, 0UL); - - preempt_enable(); -} - static void do_flush_tlb_all(void *info) { count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED); @@ -482,5 +458,3 @@ static int __init create_tlb_single_page_flush_ceiling(void) return 0; } late_initcall(create_tlb_single_page_flush_ceiling); - -#endif /* CONFIG_SMP */ diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 350f7096baac82893bc076fd6db4d04a685d7104..7913b692195901384087073a3f9f5a2d542802a6 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -212,8 +212,8 @@ static void arch_perfmon_setup_counters(void) eax.full = cpuid_eax(0xa); /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */ - if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 && - __this_cpu_read(cpu_info.x86_model) == 15) { + if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model == 15) { eax.split.version_id = 2; eax.split.num_counters = 2; eax.split.bit_width = 40; diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c index bb461cfd01abc78cdc45c6e69f013128e04ccdb4..526536c81ddc41d395fd971d909a3b687e46d989 100644 --- a/arch/x86/pci/broadcom_bus.c +++ b/arch/x86/pci/broadcom_bus.c @@ -97,7 +97,7 @@ static int __init broadcom_postcore_init(void) * We should get host bridge information from ACPI unless the BIOS * doesn't support it. */ - if (acpi_os_get_root_pointer()) + if (!acpi_disabled && acpi_os_get_root_pointer()) return 0; #endif diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 6d52b94f4bb915d119e16da1628743b93fa7af39..20fa7c84109d5ddff278b993cd0bb9de709dba00 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -571,3 +571,35 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, pci_invalid_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar); + +/* + * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff] + * + * Using the [mem 0x7fa00000-0x7fbfffff] region, e.g., by assigning it to + * the 00:1c.0 Root Port, causes a conflict with [io 0x1804], which is used + * for soft poweroff and suspend-to-RAM. + * + * As far as we know, this is related to the address space, not to the Root + * Port itself. Attaching the quirk to the Root Port is a convenience, but + * it could probably also be a standalone DMI quirk. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=103211 + */ +static void quirk_apple_mbp_poweroff(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + + if ((!dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,4") && + !dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,5")) || + pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x1c, 0)) + return; + + res = request_mem_region(0x7fa00000, 0x200000, + "MacBook Pro poweroff workaround"); + if (res) + dev_info(dev, "claimed %s %pR\n", res->name, res); + else + dev_info(dev, "can't work around MacBook Pro poweroff issue\n"); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff); diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index a00a6c07bb6fed993b8668ea2d937a81078a737f..4ea9f290c19f8be16bb121ab6595d8bbeb5a024b 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -447,7 +447,7 @@ void __init xen_msi_init(void) int __init pci_xen_hvm_init(void) { - if (!xen_feature(XENFEAT_hvm_pirqs)) + if (!xen_have_vector_callback || !xen_feature(XENFEAT_hvm_pirqs)) return 0; #ifdef CONFIG_ACPI diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 2f25a363068cf9723e8b418e8c1942a6d3ca4029..dcb2d9d185a2292f10753dcd00d1afe99c830ff7 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -142,7 +142,7 @@ int __init efi_alloc_page_tables(void) return 0; gfp_mask = GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO; - efi_pgd = (pgd_t *)__get_free_page(gfp_mask); + efi_pgd = (pgd_t *)__get_free_pages(gfp_mask, PGD_ALLOCATION_ORDER); if (!efi_pgd) return -ENOMEM; diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index cdfe8c62895981029b8f69218b717b05d0b8961a..393a0c0288d159f39ff9020281128b30b2a3873d 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -358,6 +358,9 @@ void __init efi_free_boot_services(void) free_bootmem_late(start, size); } + if (!num_entries) + return; + new_size = efi.memmap.desc_size * num_entries; new_phys = efi_memmap_alloc(num_entries); if (!new_phys) { diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile index dd6cfa4ad3ac35713da9c93951bd65bd70106a58..75029d0cfa15b3d40534fdd55a1fc6997f9d42bb 100644 --- a/arch/x86/platform/intel-mid/device_libs/Makefile +++ b/arch/x86/platform/intel-mid/device_libs/Makefile @@ -15,7 +15,7 @@ obj-$(subst m,y,$(CONFIG_INTEL_MID_POWER_BUTTON)) += platform_msic_power_btn.o obj-$(subst m,y,$(CONFIG_GPIO_INTEL_PMIC)) += platform_pmic_gpio.o obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o # SPI Devices -obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_spidev.o +obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_mrfld_spidev.o # I2C Devices obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o diff --git a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c similarity index 91% rename from arch/x86/platform/intel-mid/device_libs/platform_spidev.c rename to arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c index 30c601b399ee70907c47d31e5dab3d4802c9218b..27186ad654c97846a42ef61f850d48affd602048 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c @@ -11,6 +11,7 @@ * of the License. */ +#include #include #include #include @@ -34,6 +35,9 @@ static void __init *spidev_platform_data(void *info) { struct spi_board_info *spi_info = info; + if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER) + return ERR_PTR(-ENODEV); + spi_info->mode = SPI_MODE_0; spi_info->controller_data = &spidev_spi_chip; diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c index 3f1f1c77d0903a9a4e435979586d026b30c66741..10bad1e55fcc5caa136f8ae6c04b233ad68f9a5f 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c @@ -19,7 +19,7 @@ #include #include -#define TANGIER_EXT_TIMER0_MSI 15 +#define TANGIER_EXT_TIMER0_MSI 12 static struct platform_device wdt_dev = { .name = "intel_mid_wdt", diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 9e42842e924a6470015be1c1fd1e9af57942d740..0f0175186f1bf2c37867833166494846e25a5b6d 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -1848,7 +1848,6 @@ static void pq_init(int node, int pnode) ops.write_payload_first(pnode, first); ops.write_payload_last(pnode, last); - ops.write_g_sw_ack(pnode, 0xffffUL); /* in effect, all msg_type's are set to MSG_NOOP */ memset(pqp, 0, sizeof(struct bau_pq_entry) * DEST_Q_SIZE); diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index 555b9fa0ad43cbd4148b2fb268692d4b2de167c4..7dbdb780264df9258d98829f8a11496cd58bb7ab 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -8,6 +8,7 @@ PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib targets += purgatory.ro +KASAN_SANITIZE := n KCOV_INSTRUMENT := n # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 0c2fae8d929df154ff0324994df5f5341f2d4c52..73eb7fd4aec48d02e367b87ec1326da6c4022bde 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -992,11 +992,12 @@ static void emit_relocs(int as_text, int use_real_mode) die("Segment relocations found but --realmode not specified\n"); /* Order the relocations for more efficient processing */ - sort_relocs(&relocs16); sort_relocs(&relocs32); #if ELF_BITS == 64 sort_relocs(&relocs32neg); sort_relocs(&relocs64); +#else + sort_relocs(&relocs16); #endif /* Print the relocations */ diff --git a/arch/x86/um/ldt.c b/arch/x86/um/ldt.c index 836a1eb5df436bdad88fe3b4ae59b512f9573b19..3ee234b6234dd6eaf0a3e61b8d4d99677a5a7078 100644 --- a/arch/x86/um/ldt.c +++ b/arch/x86/um/ldt.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -369,7 +370,9 @@ void free_ldt(struct mm_context *mm) mm->arch.ldt.entry_count = 0; } -int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr , + unsigned long , bytecount) { - return do_modify_ldt_skas(func, ptr, bytecount); + /* See non-um modify_ldt() for why we do this cast */ + return (unsigned int)do_modify_ldt_skas(func, ptr, bytecount); } diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index e30202b1716efb4243372d02e61f5f8269203419..7c1601798169a5aa2e08bbf96336ec9531a4eac4 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -125,7 +125,7 @@ int poke_user(struct task_struct *child, long addr, long data) else if ((addr >= offsetof(struct user, u_debugreg[0])) && (addr <= offsetof(struct user, u_debugreg[7]))) { addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; + addr = addr >> 3; if ((addr == 4) || (addr == 5)) return -EIO; child->thread.arch.debugregs[addr] = data; diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bdd85568540382ebe3b5683534fb2ab7144e39a3..2bea87cc0ff2340c271ebbdb3e81ba0f983640d6 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -137,6 +137,8 @@ struct shared_info xen_dummy_shared_info; void *xen_initial_gdt; RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); +__read_mostly int xen_have_vector_callback; +EXPORT_SYMBOL_GPL(xen_have_vector_callback); static int xen_cpu_up_prepare(unsigned int cpu); static int xen_cpu_up_online(unsigned int cpu); @@ -442,6 +444,12 @@ static void __init xen_init_cpuid_mask(void) ~((1 << X86_FEATURE_MTRR) | /* disable MTRR */ (1 << X86_FEATURE_ACC)); /* thermal monitoring */ + /* + * Xen PV would need some work to support PCID: CR3 handling as well + * as xen_flush_tlb_others() would need updating. + */ + cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_PCID % 32)); /* disable PCID */ + if (!xen_initial_domain()) cpuid_leaf1_edx_mask &= ~((1 << X86_FEATURE_ACPI)); /* disable ACPI */ @@ -1521,7 +1529,10 @@ static void __init xen_pvh_early_guest_init(void) if (!xen_feature(XENFEAT_auto_translated_physmap)) return; - BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector)); + if (!xen_feature(XENFEAT_hvm_callback_vector)) + return; + + xen_have_vector_callback = 1; xen_pvh_early_cpu_init(0, false); xen_pvh_set_cr_flags(0); @@ -1860,7 +1871,9 @@ static int xen_cpu_up_prepare(unsigned int cpu) xen_vcpu_setup(cpu); } - if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock)) + if (xen_pv_domain() || + (xen_have_vector_callback && + xen_feature(XENFEAT_hvm_safe_pvclock))) xen_setup_timer(cpu); rc = xen_smp_intr_init(cpu); @@ -1876,7 +1889,9 @@ static int xen_cpu_dead(unsigned int cpu) { xen_smp_intr_free(cpu); - if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock)) + if (xen_pv_domain() || + (xen_have_vector_callback && + xen_feature(XENFEAT_hvm_safe_pvclock))) xen_teardown_timer(cpu); return 0; @@ -1915,8 +1930,8 @@ static void __init xen_hvm_guest_init(void) xen_panic_handler_init(); - BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector)); - + if (xen_feature(XENFEAT_hvm_callback_vector)) + xen_have_vector_callback = 1; xen_hvm_smp_init(); WARN_ON(xen_cpuhp_setup()); xen_unplug_emulated_devices(); @@ -1954,7 +1969,7 @@ bool xen_hvm_need_lapic(void) return false; if (!xen_hvm_domain()) return false; - if (xen_feature(XENFEAT_hvm_pirqs)) + if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback) return false; return true; } diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 7d5afdb417cc5e47a590f8f650e3fdcb96d544ac..418f1b8576cf3d7554f5ac2b2096d989a581f96d 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2028,7 +2028,8 @@ static unsigned long __init xen_read_phys_ulong(phys_addr_t addr) /* * Translate a virtual address to a physical one without relying on mapped - * page tables. + * page tables. Don't rely on big pages being aligned in (guest) physical + * space! */ static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr) { @@ -2049,7 +2050,7 @@ static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr) sizeof(pud))); if (!pud_present(pud)) return 0; - pa = pud_pfn(pud) << PAGE_SHIFT; + pa = pud_val(pud) & PTE_PFN_MASK; if (pud_large(pud)) return pa + (vaddr & ~PUD_MASK); @@ -2057,7 +2058,7 @@ static phys_addr_t __init xen_early_virt_to_phys(unsigned long vaddr) sizeof(pmd))); if (!pmd_present(pmd)) return 0; - pa = pmd_pfn(pmd) << PAGE_SHIFT; + pa = pmd_val(pmd) & PTE_PFN_MASK; if (pmd_large(pmd)) return pa + (vaddr & ~PMD_MASK); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 311acad7dad2abdc8501c70866674ed4f5858495..137afbbd05903baa700d9cce5d9707fac07f0062 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -765,6 +765,8 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus) void __init xen_hvm_smp_init(void) { + if (!xen_have_vector_callback) + return; smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus; smp_ops.smp_send_reschedule = xen_smp_send_reschedule; smp_ops.cpu_die = xen_cpu_die; diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 33d8f6a7829d75c6673a8287d8a9d4be68401d9e..67356d29d74d033f07ede538eb14fe8cefcc056a 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -432,6 +432,11 @@ static void xen_hvm_setup_cpu_clockevents(void) void __init xen_hvm_init_time_ops(void) { + /* vector callback is needed otherwise we cannot receive interrupts + * on cpu > 0 and at this point we don't know how many cpus are + * available */ + if (!xen_have_vector_callback) + return; if (!xen_feature(XENFEAT_hvm_safe_pvclock)) { printk(KERN_INFO "Xen doesn't support pvclock on HVM," "disable pv timer\n"); diff --git a/arch/xtensa/include/asm/irq.h b/arch/xtensa/include/asm/irq.h index f71f88ea7646dcc798067e984dddefa8a659037d..19707db966f1393017bcf9528ff64d2951089d20 100644 --- a/arch/xtensa/include/asm/irq.h +++ b/arch/xtensa/include/asm/irq.h @@ -29,7 +29,8 @@ static inline void variant_irq_disable(unsigned int irq) { } # define PLATFORM_NR_IRQS 0 #endif #define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS -#define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS) +#define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS + 1) +#define XTENSA_PIC_LINUX_IRQ(hwirq) ((hwirq) + 1) #if VARIANT_NR_IRQS == 0 static inline void variant_init_irq(void) { } diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h index 81435d995e1183d07ed0aac8903503e174a5c21e..fc7ca28412065ccd45cec8d577e6aa6d7cbef5a4 100644 --- a/arch/xtensa/include/uapi/asm/socket.h +++ b/arch/xtensa/include/uapi/asm/socket.h @@ -101,4 +101,6 @@ #define SO_CNX_ADVICE 53 +#define SO_COOKIE 57 + #endif /* _XTENSA_SOCKET_H */ diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index 4ac3d23161cf782484da4f0c89b9394e1911a07f..441694464b1e41cb2c6d30c4f6d806ae32ea31cd 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c @@ -34,11 +34,6 @@ asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs) { int irq = irq_find_mapping(NULL, hwirq); - if (hwirq >= NR_IRQS) { - printk(KERN_EMERG "%s: cannot handle IRQ %d\n", - __func__, hwirq); - } - #ifdef CONFIG_DEBUG_STACKOVERFLOW /* Debugging check for stack overflow: is there less than 1KB free? */ { diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c index 83cf49685373867080689b163bc5fcf3ed89f3c7..3aaaae18417c4e4b6ab758709d996f9dfeedef46 100644 --- a/arch/xtensa/kernel/syscall.c +++ b/arch/xtensa/kernel/syscall.c @@ -87,7 +87,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, /* At this point: (!vmm || addr < vmm->vm_end). */ if (TASK_SIZE - len < addr) return -ENOMEM; - if (!vmm || addr + len <= vmm->vm_start) + if (!vmm || addr + len <= vm_start_gap(vmm)) return addr; addr = vmm->vm_end; if (flags & MAP_SHARED) diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 4d2872fd9bb5ebf89bb15127841e5ae28e8d9b58..a71d2739fa8288c39af870eb40fe921553080db6 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -94,13 +94,11 @@ unsigned long __sync_fetch_and_or_4(unsigned long *p, unsigned long v) } EXPORT_SYMBOL(__sync_fetch_and_or_4); -#ifdef CONFIG_NET /* * Networking support */ EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); -#endif /* CONFIG_NET */ /* * Architecture-specific symbols diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c index 1a804a2f9a5be6212c57febc01f6d28f47b8c91a..3c75c4e597da8f086f65de51201e0d37d6672733 100644 --- a/arch/xtensa/mm/cache.c +++ b/arch/xtensa/mm/cache.c @@ -103,6 +103,7 @@ void clear_user_highpage(struct page *page, unsigned long vaddr) clear_page_alias(kvaddr, paddr); preempt_enable(); } +EXPORT_SYMBOL(clear_user_highpage); void copy_user_highpage(struct page *dst, struct page *src, unsigned long vaddr, struct vm_area_struct *vma) @@ -119,10 +120,7 @@ void copy_user_highpage(struct page *dst, struct page *src, copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr); preempt_enable(); } - -#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */ - -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +EXPORT_SYMBOL(copy_user_highpage); /* * Any time the kernel writes to a user page cache page, or it is about to @@ -176,7 +174,7 @@ void flush_dcache_page(struct page *page) /* There shouldn't be an entry in the cache for this page anymore. */ } - +EXPORT_SYMBOL(flush_dcache_page); /* * For now, flush the whole cache. FIXME?? @@ -188,6 +186,7 @@ void local_flush_cache_range(struct vm_area_struct *vma, __flush_invalidate_dcache_all(); __invalidate_icache_all(); } +EXPORT_SYMBOL(local_flush_cache_range); /* * Remove any entry in the cache for this page. @@ -207,8 +206,9 @@ void local_flush_cache_page(struct vm_area_struct *vma, unsigned long address, __flush_invalidate_dcache_page_alias(virt, phys); __invalidate_icache_page_alias(virt, phys); } +EXPORT_SYMBOL(local_flush_cache_page); -#endif +#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */ void update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep) @@ -225,7 +225,7 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep) flush_tlb_page(vma, addr); -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +#if (DCACHE_WAY_SIZE > PAGE_SIZE) if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) { unsigned long phys = page_to_phys(page); @@ -256,7 +256,7 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep) * flush_dcache_page() on the page. */ -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +#if (DCACHE_WAY_SIZE > PAGE_SIZE) void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h index dbeea2b440a1b50bd3e6a1eea85dcb7626244a91..1fda7e20dfcbff79849e5aae29ac8a6529c43e39 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h @@ -24,16 +24,18 @@ /* Interrupt configuration. */ -#define PLATFORM_NR_IRQS 10 +#define PLATFORM_NR_IRQS 0 /* Default assignment of LX60 devices to external interrupts. */ #ifdef CONFIG_XTENSA_MX #define DUART16552_INTNUM XCHAL_EXTINT3_NUM #define OETH_IRQ XCHAL_EXTINT4_NUM +#define C67X00_IRQ XCHAL_EXTINT8_NUM #else #define DUART16552_INTNUM XCHAL_EXTINT0_NUM #define OETH_IRQ XCHAL_EXTINT1_NUM +#define C67X00_IRQ XCHAL_EXTINT5_NUM #endif /* @@ -63,5 +65,5 @@ #define C67X00_PADDR (XCHAL_KIO_PADDR + 0x0D0D0000) #define C67X00_SIZE 0x10 -#define C67X00_IRQ 5 + #endif /* __XTENSA_XTAVNET_HARDWARE_H */ diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c index 779be723eb2bdd4fa03c6b30abd553e948df9991..42285f35d3135a0a6d58b5b9e2eea7f5fcaa4019 100644 --- a/arch/xtensa/platforms/xtfpga/setup.c +++ b/arch/xtensa/platforms/xtfpga/setup.c @@ -175,8 +175,8 @@ static struct resource ethoc_res[] = { .flags = IORESOURCE_MEM, }, [2] = { /* IRQ number */ - .start = OETH_IRQ, - .end = OETH_IRQ, + .start = XTENSA_PIC_LINUX_IRQ(OETH_IRQ), + .end = XTENSA_PIC_LINUX_IRQ(OETH_IRQ), .flags = IORESOURCE_IRQ, }, }; @@ -213,8 +213,8 @@ static struct resource c67x00_res[] = { .flags = IORESOURCE_MEM, }, [1] = { /* IRQ number */ - .start = C67X00_IRQ, - .end = C67X00_IRQ, + .start = XTENSA_PIC_LINUX_IRQ(C67X00_IRQ), + .end = XTENSA_PIC_LINUX_IRQ(C67X00_IRQ), .flags = IORESOURCE_IRQ, }, }; @@ -247,7 +247,7 @@ static struct resource serial_resource = { static struct plat_serial8250_port serial_platform_data[] = { [0] = { .mapbase = DUART16552_PADDR, - .irq = DUART16552_INTNUM, + .irq = XTENSA_PIC_LINUX_IRQ(DUART16552_INTNUM), .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, .iotype = XCHAL_HAVE_BE ? UPIO_MEM32BE : UPIO_MEM32, diff --git a/block/badblocks.c b/block/badblocks.c index 6ebcef28231486ae2b9dcefadfe61412b2112f11..2fe6c117ac962b3d235b9c0f2250f9e1b3c6daf4 100644 --- a/block/badblocks.c +++ b/block/badblocks.c @@ -178,7 +178,7 @@ int badblocks_set(struct badblocks *bb, sector_t s, int sectors, if (bb->shift < 0) /* badblocks are disabled */ - return 0; + return 1; if (bb->shift) { /* round the start down, and the end up */ diff --git a/block/bio.c b/block/bio.c index 655c9016052a101abdbd1b93eb94913e0f577262..e14a897073d3f17913ef575898cece689745b16c 100644 --- a/block/bio.c +++ b/block/bio.c @@ -589,7 +589,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_opf = bio_src->bi_opf; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; - + bio->bi_dio_inode = bio_src->bi_dio_inode; bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); @@ -1171,8 +1171,8 @@ struct bio *bio_copy_user_iov(struct request_queue *q, */ bmd->is_our_pages = map_data ? 0 : 1; memcpy(bmd->iov, iter->iov, sizeof(struct iovec) * iter->nr_segs); - iov_iter_init(&bmd->iter, iter->type, bmd->iov, - iter->nr_segs, iter->count); + bmd->iter = *iter; + bmd->iter.iov = bmd->iov; ret = -ENOMEM; bio = bio_kmalloc(gfp_mask, nr_pages); @@ -1266,6 +1266,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, int ret, offset; struct iov_iter i; struct iovec iov; + struct bio_vec *bvec; iov_for_each(iov, i, *iter) { unsigned long uaddr = (unsigned long) iov.iov_base; @@ -1310,7 +1311,12 @@ struct bio *bio_map_user_iov(struct request_queue *q, ret = get_user_pages_fast(uaddr, local_nr_pages, (iter->type & WRITE) != WRITE, &pages[cur_page]); - if (ret < local_nr_pages) { + if (unlikely(ret < local_nr_pages)) { + for (j = cur_page; j < page_limit; j++) { + if (!pages[j]) + break; + put_page(pages[j]); + } ret = -EFAULT; goto out_unmap; } @@ -1318,6 +1324,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, offset = offset_in_page(uaddr); for (j = cur_page; j < page_limit; j++) { unsigned int bytes = PAGE_SIZE - offset; + unsigned short prev_bi_vcnt = bio->bi_vcnt; if (len <= 0) break; @@ -1332,6 +1339,13 @@ struct bio *bio_map_user_iov(struct request_queue *q, bytes) break; + /* + * check if vector was merged with previous + * drop page reference if needed + */ + if (bio->bi_vcnt == prev_bi_vcnt) + put_page(pages[j]); + len -= bytes; offset = 0; } @@ -1364,10 +1378,8 @@ struct bio *bio_map_user_iov(struct request_queue *q, return bio; out_unmap: - for (j = 0; j < nr_pages; j++) { - if (!pages[j]) - break; - put_page(pages[j]); + bio_for_each_segment_all(bvec, bio, j) { + put_page(bvec->bv_page); } out: kfree(pages); diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index b08ccbb9393a75800a3299f90537f6ee881b00f0..8ba0af780e880e1c6ed72d772ba77dea5a79f436 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -185,7 +185,8 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, } wb_congested = wb_congested_get_create(&q->backing_dev_info, - blkcg->css.id, GFP_NOWAIT); + blkcg->css.id, + GFP_NOWAIT | __GFP_NOWARN); if (!wb_congested) { ret = -ENOMEM; goto err_put_css; @@ -193,7 +194,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, /* allocate */ if (!new_blkg) { - new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT); + new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT | __GFP_NOWARN); if (unlikely(!new_blkg)) { ret = -ENOMEM; goto err_put_congested; @@ -1022,7 +1023,7 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css) } spin_lock_init(&blkcg->lock); - INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT); + INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN); INIT_HLIST_HEAD(&blkcg->blkg_list); #ifdef CONFIG_CGROUP_WRITEBACK INIT_LIST_HEAD(&blkcg->cgwb_list); @@ -1240,7 +1241,7 @@ int blkcg_activate_policy(struct request_queue *q, if (blkg->pd[pol->plid]) continue; - pd = pol->pd_alloc_fn(GFP_NOWAIT, q->node); + pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q->node); if (!pd) swap(pd, pd_prealloc); if (!pd) { diff --git a/block/blk-core.c b/block/blk-core.c index 710c93ba11fed7b5b1d7c46d4038dfc93633f7ff..37b814a01529867ee069daf47ab071a4c9b156f7 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -235,7 +235,7 @@ EXPORT_SYMBOL(blk_start_queue_async); **/ void blk_start_queue(struct request_queue *q) { - WARN_ON(!irqs_disabled()); + WARN_ON(!in_interrupt() && !irqs_disabled()); queue_flag_clear(QUEUE_FLAG_STOPPED, q); __blk_run_queue(q); @@ -284,6 +284,7 @@ EXPORT_SYMBOL(blk_stop_queue); void blk_sync_queue(struct request_queue *q) { del_timer_sync(&q->timeout); + cancel_work_sync(&q->timeout_work); if (q->mq_ops) { struct blk_mq_hw_ctx *hctx; @@ -528,8 +529,8 @@ void blk_set_queue_dying(struct request_queue *q) blk_queue_for_each_rl(rl, q) { if (rl->rq_pool) { - wake_up(&rl->wait[BLK_RW_SYNC]); - wake_up(&rl->wait[BLK_RW_ASYNC]); + wake_up_all(&rl->wait[BLK_RW_SYNC]); + wake_up_all(&rl->wait[BLK_RW_ASYNC]); } } } @@ -722,6 +723,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, laptop_mode_timer_fn, (unsigned long) q); setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); + INIT_WORK(&q->timeout_work, NULL); INIT_LIST_HEAD(&q->queue_head); INIT_LIST_HEAD(&q->timeout_list); INIT_LIST_HEAD(&q->icq_list); @@ -1438,6 +1440,9 @@ void __blk_put_request(struct request_queue *q, struct request *req) /* this is a bio leak */ WARN_ON(req->bio != NULL); + /* this is a bio leak if the bio is not tagged with BIO_DONTFREE */ + WARN_ON(req->bio && !bio_flagged(req->bio, BIO_DONTFREE)); + /* * Request may not have originated from ll_rw_blk. if not, * it didn't come out of our reserved rq pools @@ -2619,6 +2624,15 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) blk_account_io_completion(req, nr_bytes); total_bytes = 0; + + /* + * Check for this if flagged, Req based dm needs to perform + * post processing, hence dont end bios or request.DM + * layer takes care. + */ + if (bio_flagged(req->bio, BIO_DONTFREE)) + return false; + while (req->bio) { struct bio *bio = req->bio; unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes); diff --git a/block/blk-integrity.c b/block/blk-integrity.c index d69c5c79f98e71059827265531aba75a63458f74..478f572cb1e7d6bb78c4dcbbf650012107c6e1a0 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -412,12 +412,13 @@ void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE | template->flags; - bi->interval_exp = ilog2(queue_logical_block_size(disk->queue)); + bi->interval_exp = template->interval_exp ? : + ilog2(queue_logical_block_size(disk->queue)); bi->profile = template->profile ? template->profile : &nop_profile; bi->tuple_size = template->tuple_size; bi->tag_size = template->tag_size; - blk_integrity_revalidate(disk); + disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES; } EXPORT_SYMBOL(blk_integrity_register); @@ -430,26 +431,11 @@ EXPORT_SYMBOL(blk_integrity_register); */ void blk_integrity_unregister(struct gendisk *disk) { - blk_integrity_revalidate(disk); + disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES; memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity)); } EXPORT_SYMBOL(blk_integrity_unregister); -void blk_integrity_revalidate(struct gendisk *disk) -{ - struct blk_integrity *bi = &disk->queue->integrity; - - if (!(disk->flags & GENHD_FL_UP)) - return; - - if (bi->profile) - disk->queue->backing_dev_info.capabilities |= - BDI_CAP_STABLE_WRITES; - else - disk->queue->backing_dev_info.capabilities &= - ~BDI_CAP_STABLE_WRITES; -} - void blk_integrity_add(struct gendisk *disk) { if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype, diff --git a/block/blk-merge.c b/block/blk-merge.c index 2642e5fc8b69a03494b62638d4eca98ee07b7edc..0272face519977b4187b9c056be36cdb436772e2 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -6,7 +6,7 @@ #include #include #include - +#include #include #include "blk.h" @@ -492,6 +492,64 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, } EXPORT_SYMBOL(blk_rq_map_sg); +/* + * map a request to scatterlist without combining PHY CONT + * blocks, return number of sg entries setup. Caller + * must make sure sg can hold rq->nr_phys_segments entries + */ +int blk_rq_map_sg_no_cluster(struct request_queue *q, struct request *rq, + struct scatterlist *sglist) +{ + struct bio_vec bvec, bvprv = { NULL }; + struct req_iterator iter; + struct scatterlist *sg; + int nsegs, cluster = 0; + + nsegs = 0; + + /* + * for each bio in rq + */ + sg = NULL; + rq_for_each_segment(bvec, rq, iter) { + __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg, + &nsegs, &cluster); + } /* segments in rq */ + + + if (!sg) + return nsegs; + + if (unlikely(rq->cmd_flags & REQ_COPY_USER) && + (blk_rq_bytes(rq) & q->dma_pad_mask)) { + unsigned int pad_len = + (q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1; + + sg->length += pad_len; + rq->extra_len += pad_len; + } + + if (q->dma_drain_size && q->dma_drain_needed(rq)) { + if (rq->cmd_flags & REQ_OP_WRITE) + memset(q->dma_drain_buffer, 0, q->dma_drain_size); + + sg->page_link &= ~0x02; + sg = sg_next(sg); + sg_set_page(sg, virt_to_page(q->dma_drain_buffer), + q->dma_drain_size, + ((unsigned long)q->dma_drain_buffer) & + (PAGE_SIZE - 1)); + nsegs++; + rq->extra_len += q->dma_drain_size; + } + + if (sg) + sg_mark_end(sg); + + return nsegs; +} +EXPORT_SYMBOL(blk_rq_map_sg_no_cluster); + static inline int ll_new_hw_segment(struct request_queue *q, struct request *req, struct bio *bio) @@ -667,6 +725,11 @@ static void blk_account_io_merge(struct request *req) } } +static bool crypto_not_mergeable(const struct bio *bio, const struct bio *nxt) +{ + return (!pfk_allow_merge_bio(bio, nxt)); +} + /* * Has to be called with the request spinlock acquired */ @@ -694,6 +757,8 @@ static int attempt_merge(struct request_queue *q, struct request *req, !blk_write_same_mergeable(req->bio, next->bio)) return 0; + if (crypto_not_mergeable(req->bio, next->bio)) + return 0; /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn @@ -804,6 +869,8 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) !blk_write_same_mergeable(rq->bio, bio)) return false; + if (crypto_not_mergeable(rq->bio, bio)) + return false; return true; } diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c index 19b1d9c5f07e15107abb94241a5b8b24273ec681..df02fafef21437ac0d0a73bfb0e7a62614ad97c0 100644 --- a/block/blk-mq-cpumap.c +++ b/block/blk-mq-cpumap.c @@ -35,37 +35,19 @@ int blk_mq_map_queues(struct blk_mq_tag_set *set) { unsigned int *map = set->mq_map; unsigned int nr_queues = set->nr_hw_queues; - const struct cpumask *online_mask = cpu_online_mask; - unsigned int i, nr_cpus, nr_uniq_cpus, queue, first_sibling; + unsigned int i, queue, first_sibling; cpumask_var_t cpus; - if (!alloc_cpumask_var(&cpus, GFP_ATOMIC)) - return -ENOMEM; - - cpumask_clear(cpus); - nr_cpus = nr_uniq_cpus = 0; - for_each_cpu(i, online_mask) { - nr_cpus++; - first_sibling = get_first_sibling(i); - if (!cpumask_test_cpu(first_sibling, cpus)) - nr_uniq_cpus++; - cpumask_set_cpu(i, cpus); - } - queue = 0; for_each_possible_cpu(i) { - if (!cpumask_test_cpu(i, online_mask)) { - map[i] = 0; - continue; - } - /* * Easy case - we have equal or more hardware queues. Or * there are no thread siblings to take into account. Do * 1:1 if enough, or sequential mapping if less. */ - if (nr_queues >= nr_cpus || nr_cpus == nr_uniq_cpus) { - map[i] = cpu_to_queue_index(nr_cpus, nr_queues, queue); + if (nr_queues >= nr_cpu_ids) { + map[i] = cpu_to_queue_index(nr_cpu_ids, nr_queues, + queue); queue++; continue; } @@ -77,7 +59,7 @@ int blk_mq_map_queues(struct blk_mq_tag_set *set) */ first_sibling = get_first_sibling(i); if (first_sibling == i) { - map[i] = cpu_to_queue_index(nr_uniq_cpus, nr_queues, + map[i] = cpu_to_queue_index(nr_cpu_ids, nr_queues, queue); queue++; } else diff --git a/block/blk-mq-pci.c b/block/blk-mq-pci.c index 966c2169762eb4d951011531e101fb1b3809d7e8..ee9d3d958fbe1a16eab68256e9e1dadff87b07e1 100644 --- a/block/blk-mq-pci.c +++ b/block/blk-mq-pci.c @@ -36,12 +36,18 @@ int blk_mq_pci_map_queues(struct blk_mq_tag_set *set, struct pci_dev *pdev) for (queue = 0; queue < set->nr_hw_queues; queue++) { mask = pci_irq_get_affinity(pdev, queue); if (!mask) - return -EINVAL; + goto fallback; for_each_cpu(cpu, mask) set->mq_map[cpu] = queue; } return 0; + +fallback: + WARN_ON_ONCE(set->nr_hw_queues > 1); + for_each_possible_cpu(cpu) + set->mq_map[cpu] = 0; + return 0; } EXPORT_SYMBOL_GPL(blk_mq_pci_map_queues); diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c index 01fb455d3377472c6201d6755716b961e5b9620a..8c0894e0713b99b66ae6840f27a85ce776dd77ad 100644 --- a/block/blk-mq-sysfs.c +++ b/block/blk-mq-sysfs.c @@ -429,7 +429,7 @@ void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx) kobject_init(&hctx->kobj, &blk_mq_hw_ktype); } -static void blk_mq_sysfs_init(struct request_queue *q) +void blk_mq_sysfs_init(struct request_queue *q) { struct blk_mq_ctx *ctx; int cpu; @@ -449,8 +449,6 @@ int blk_mq_register_dev(struct device *dev, struct request_queue *q) blk_mq_disable_hotplug(); - blk_mq_sysfs_init(q); - ret = kobject_add(&q->mq_kobj, kobject_get(&dev->kobj), "%s", "mq"); if (ret < 0) goto out; diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index dcf5ce3ba4bff3068486d8596c5941e9f382d228..4bc701b32ce24c6ddda10fcbb266e5d07f41cd74 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -311,6 +311,9 @@ int blk_mq_reinit_tagset(struct blk_mq_tag_set *set) for (i = 0; i < set->nr_hw_queues; i++) { struct blk_mq_tags *tags = set->tags[i]; + if (!tags) + continue; + for (j = 0; j < tags->nr_tags; j++) { if (!tags->rqs[j]) continue; diff --git a/block/blk-mq.c b/block/blk-mq.c index 7b597ec4e9c52b41c46efdd17268d687a294ffb1..74ff73fa7b61b10cea4ec7621712a93425df4085 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1707,16 +1707,11 @@ static void blk_mq_init_cpu_queues(struct request_queue *q, struct blk_mq_ctx *__ctx = per_cpu_ptr(q->queue_ctx, i); struct blk_mq_hw_ctx *hctx; - memset(__ctx, 0, sizeof(*__ctx)); __ctx->cpu = i; spin_lock_init(&__ctx->lock); INIT_LIST_HEAD(&__ctx->rq_list); __ctx->queue = q; - /* If the cpu isn't online, the cpu is mapped to first hctx */ - if (!cpu_online(i)) - continue; - hctx = blk_mq_map_queue(q, i); /* @@ -1750,14 +1745,11 @@ static void blk_mq_map_swqueue(struct request_queue *q, * Map software to hardware queues */ for_each_possible_cpu(i) { - /* If the cpu isn't online, the cpu is mapped to first hctx */ - if (!cpumask_test_cpu(i, online_mask)) - continue; - ctx = per_cpu_ptr(q->queue_ctx, i); hctx = blk_mq_map_queue(q, i); - cpumask_set_cpu(i, hctx->cpumask); + if (cpumask_test_cpu(i, online_mask)) + cpumask_set_cpu(i, hctx->cpumask); ctx->index_hw = hctx->nr_ctx; hctx->ctxs[hctx->nr_ctx++] = ctx; } @@ -1793,9 +1785,16 @@ static void blk_mq_map_swqueue(struct request_queue *q, /* * Initialize batch roundrobin counts + * Set next_cpu for only those hctxs that have an online CPU + * in their cpumask field. For hctxs that belong to few online + * and few offline CPUs, this will always provide one CPU from + * online ones. For hctxs belonging to all offline CPUs, their + * cpumask will be updated in reinit_notify. */ - hctx->next_cpu = cpumask_first(hctx->cpumask); - hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH; + if (cpumask_first(hctx->cpumask) < nr_cpu_ids) { + hctx->next_cpu = cpumask_first(hctx->cpumask); + hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH; + } } } @@ -1970,6 +1969,9 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, if (!q->queue_ctx) goto err_exit; + /* init q->mq_kobj and sw queues' kobjects */ + blk_mq_sysfs_init(q); + q->queue_hw_ctx = kzalloc_node(nr_cpu_ids * sizeof(*(q->queue_hw_ctx)), GFP_KERNEL, set->numa_node); if (!q->queue_hw_ctx) @@ -2067,50 +2069,20 @@ static void blk_mq_queue_reinit(struct request_queue *q, blk_mq_sysfs_register(q); } -/* - * New online cpumask which is going to be set in this hotplug event. - * Declare this cpumasks as global as cpu-hotplug operation is invoked - * one-by-one and dynamically allocating this could result in a failure. - */ -static struct cpumask cpuhp_online_new; - -static void blk_mq_queue_reinit_work(void) +static int blk_mq_queue_reinit_dead(unsigned int cpu) { struct request_queue *q; + struct blk_mq_hw_ctx *hctx; + int i; mutex_lock(&all_q_mutex); - /* - * We need to freeze and reinit all existing queues. Freezing - * involves synchronous wait for an RCU grace period and doing it - * one by one may take a long time. Start freezing all queues in - * one swoop and then wait for the completions so that freezing can - * take place in parallel. - */ - list_for_each_entry(q, &all_q_list, all_q_node) - blk_mq_freeze_queue_start(q); list_for_each_entry(q, &all_q_list, all_q_node) { - blk_mq_freeze_queue_wait(q); - - /* - * timeout handler can't touch hw queue during the - * reinitialization - */ - del_timer_sync(&q->timeout); + queue_for_each_hw_ctx(q, hctx, i) { + cpumask_clear_cpu(cpu, hctx->cpumask); + } } - - list_for_each_entry(q, &all_q_list, all_q_node) - blk_mq_queue_reinit(q, &cpuhp_online_new); - - list_for_each_entry(q, &all_q_list, all_q_node) - blk_mq_unfreeze_queue(q); - mutex_unlock(&all_q_mutex); -} -static int blk_mq_queue_reinit_dead(unsigned int cpu) -{ - cpumask_copy(&cpuhp_online_new, cpu_online_mask); - blk_mq_queue_reinit_work(); return 0; } @@ -2132,9 +2104,17 @@ static int blk_mq_queue_reinit_dead(unsigned int cpu) */ static int blk_mq_queue_reinit_prepare(unsigned int cpu) { - cpumask_copy(&cpuhp_online_new, cpu_online_mask); - cpumask_set_cpu(cpu, &cpuhp_online_new); - blk_mq_queue_reinit_work(); + struct request_queue *q; + struct blk_mq_hw_ctx *hctx; + int i; + + mutex_lock(&all_q_mutex); + list_for_each_entry(q, &all_q_list, all_q_node) { + queue_for_each_hw_ctx(q, hctx, i) { + cpumask_set_cpu(cpu, hctx->cpumask); + } + } + mutex_unlock(&all_q_mutex); return 0; } diff --git a/block/blk-mq.h b/block/blk-mq.h index e5d25249028c746c2876c668aa040bcf352b70c6..c55bcf67b9560fba32e4e53318ba149dba4320ad 100644 --- a/block/blk-mq.h +++ b/block/blk-mq.h @@ -50,6 +50,7 @@ static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q, /* * sysfs helpers */ +extern void blk_mq_sysfs_init(struct request_queue *q); extern int blk_mq_sysfs_register(struct request_queue *q); extern void blk_mq_sysfs_unregister(struct request_queue *q); extern void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx); diff --git a/block/blk-timeout.c b/block/blk-timeout.c index a30441a200c0952eec31f6694dd05641a54227fa..220661a50f58557df475a550058d68ee48bf1497 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -135,8 +135,6 @@ void blk_timeout_work(struct work_struct *work) struct request *rq, *tmp; int next_set = 0; - if (blk_queue_enter(q, true)) - return; spin_lock_irqsave(q->queue_lock, flags); list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) @@ -146,7 +144,6 @@ void blk_timeout_work(struct work_struct *work) mod_timer(&q->timeout, round_jiffies_up(next)); spin_unlock_irqrestore(q->queue_lock, flags); - blk_queue_exit(q); } /** diff --git a/block/blk.h b/block/blk.h index 74444c49078fc7911289f9d8a65939399d8cb126..ae076666cc23c7c9d2d44da23b542f0981c2f043 100644 --- a/block/blk.h +++ b/block/blk.h @@ -207,7 +207,6 @@ int attempt_back_merge(struct request_queue *q, struct request *rq); int attempt_front_merge(struct request_queue *q, struct request *rq); int blk_attempt_req_merge(struct request_queue *q, struct request *rq, struct request *next); -void blk_recalc_rq_segments(struct request *rq); void blk_rq_set_mixed_merge(struct request *rq); bool blk_rq_merge_ok(struct request *rq, struct bio *bio); int blk_try_merge(struct request *rq, struct bio *bio); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3ab6807773eeb8e05d74143ca65391b3abef2bd0..6a901554ba50dbded049fdae10d6a065f535078c 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -36,9 +36,13 @@ static const u64 cfq_target_latency = (u64)NSEC_PER_SEC * 3/10; /* 300 ms */ static const int cfq_hist_divisor = 4; /* - * offset from end of service tree + * offset from end of queue service tree for idle class */ #define CFQ_IDLE_DELAY (NSEC_PER_SEC / 5) +/* offset from end of group service tree under time slice mode */ +#define CFQ_SLICE_MODE_GROUP_DELAY (NSEC_PER_SEC / 5) +/* offset from end of group service under IOPS mode */ +#define CFQ_IOPS_MODE_GROUP_DELAY (HZ / 5) /* * below this threshold, we consider thinktime immediate @@ -1370,6 +1374,14 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg) cfqg->vfraction = max_t(unsigned, vfr, 1); } +static inline u64 cfq_get_cfqg_vdisktime_delay(struct cfq_data *cfqd) +{ + if (!iops_mode(cfqd)) + return CFQ_SLICE_MODE_GROUP_DELAY; + else + return CFQ_IOPS_MODE_GROUP_DELAY; +} + static void cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg) { @@ -1389,7 +1401,8 @@ cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg) n = rb_last(&st->rb); if (n) { __cfqg = rb_entry_cfqg(n); - cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY; + cfqg->vdisktime = __cfqg->vdisktime + + cfq_get_cfqg_vdisktime_delay(cfqd); } else cfqg->vdisktime = st->min_vdisktime; cfq_group_service_tree_add(st, cfqg); @@ -2935,10 +2948,11 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) /* * SSD device without seek penalty, disable idling. But only do so - * for devices that support queuing, otherwise we still have a problem - * with sync vs async workloads. + * for devices that support queuing (and when group idle is 0), + * otherwise we still have a problem with sync vs async workloads. */ - if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag) + if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag && + !cfqd->cfq_group_idle) return; WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list)); @@ -3854,7 +3868,8 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, goto out; } - cfqq = kmem_cache_alloc_node(cfq_pool, GFP_NOWAIT | __GFP_ZERO, + cfqq = kmem_cache_alloc_node(cfq_pool, + GFP_NOWAIT | __GFP_ZERO | __GFP_NOWARN, cfqd->queue->node); if (!cfqq) { cfqq = &cfqd->oom_cfqq; diff --git a/block/partition-generic.c b/block/partition-generic.c index 71d9ed9df8daeae8b54234634a5eab45bf0df00d..a2437c0066402786762c5636ec928c2cca112d95 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -447,7 +447,6 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); - blk_integrity_revalidate(disk); check_disk_size_change(disk, bdev); bdev->bd_invalidated = 0; if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) diff --git a/block/partitions/efi.c b/block/partitions/efi.c index bcd86e5cd5460cc34750f3491d720f4b69e2a19c..39f70d968754e558ccb175dc3c56822d6da3fcab 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -293,7 +293,7 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, if (!gpt) return NULL; - count = le32_to_cpu(gpt->num_partition_entries) * + count = (size_t)le32_to_cpu(gpt->num_partition_entries) * le32_to_cpu(gpt->sizeof_partition_entry); if (!count) return NULL; @@ -352,7 +352,7 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, gpt_header **gpt, gpt_entry **ptes) { u32 crc, origcrc; - u64 lastlba; + u64 lastlba, pt_size; if (!ptes) return 0; @@ -434,13 +434,20 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, goto fail; } + /* Sanity check partition table size */ + pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) * + le32_to_cpu((*gpt)->sizeof_partition_entry); + if (pt_size > KMALLOC_MAX_SIZE) { + pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n", + (unsigned long long)pt_size, KMALLOC_MAX_SIZE); + goto fail; + } + if (!(*ptes = alloc_read_gpt_entries(state, *gpt))) goto fail; /* Check the GUID Partition Entry Array CRC */ - crc = efi_crc32((const unsigned char *) (*ptes), - le32_to_cpu((*gpt)->num_partition_entries) * - le32_to_cpu((*gpt)->sizeof_partition_entry)); + crc = efi_crc32((const unsigned char *) (*ptes), pt_size); if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { pr_debug("GUID Partition Entry Array CRC check failed.\n"); diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c index 93e7c1b32eddd5aa27fc8c96f5f581f712541a53..5610cd537da78812e2633d76ca90e5c3fb66e7cc 100644 --- a/block/partitions/msdos.c +++ b/block/partitions/msdos.c @@ -300,6 +300,8 @@ static void parse_bsd(struct parsed_partitions *state, continue; bsd_start = le32_to_cpu(p->p_offset); bsd_size = le32_to_cpu(p->p_size); + if (memcmp(flavour, "bsd\0", 4) == 0) + bsd_start += offset; if (offset == bsd_start && size == bsd_size) /* full parent partition, we have it already */ continue; diff --git a/crypto/algapi.c b/crypto/algapi.c index 1fad2a6b3bbbf0d1d4ee07f585bdc4d501467b5d..5c098ffa7d3d857deeafff9581df6e1bc5f2f4f5 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -167,6 +167,18 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, spawn->alg = NULL; spawns = &inst->alg.cra_users; + + /* + * We may encounter an unregistered instance here, since + * an instance's spawns are set up prior to the instance + * being registered. An unregistered instance will have + * NULL ->cra_users.next, since ->cra_users isn't + * properly initialized until registration. But an + * unregistered instance cannot have any users, so treat + * it the same as ->cra_users being empty. + */ + if (spawns->next == NULL) + break; } } while ((spawns = crypto_more_spawns(alg, &stack, &top, &secondary_spawns))); diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index fde8d885f7b6b34860d76958c0204a67c179bb78..6c11537ca404673fb576c615786e8aa009d06015 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -44,6 +44,11 @@ struct aead_async_req { char iv[]; }; +struct aead_tfm { + struct crypto_aead *aead; + bool has_key; +}; + struct aead_ctx { struct aead_sg_list tsgl; struct aead_async_rsgl first_rsgl; @@ -732,24 +737,146 @@ static struct proto_ops algif_aead_ops = { .poll = aead_poll, }; +static int aead_check_key(struct socket *sock) +{ + int err = 0; + struct sock *psk; + struct alg_sock *pask; + struct aead_tfm *tfm; + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + + lock_sock(sk); + if (ask->refcnt) + goto unlock_child; + + psk = ask->parent; + pask = alg_sk(ask->parent); + tfm = pask->private; + + err = -ENOKEY; + lock_sock_nested(psk, SINGLE_DEPTH_NESTING); + if (!tfm->has_key) + goto unlock; + + if (!pask->refcnt++) + sock_hold(psk); + + ask->refcnt = 1; + sock_put(psk); + + err = 0; + +unlock: + release_sock(psk); +unlock_child: + release_sock(sk); + + return err; +} + +static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t size) +{ + int err; + + err = aead_check_key(sock); + if (err) + return err; + + return aead_sendmsg(sock, msg, size); +} + +static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page, + int offset, size_t size, int flags) +{ + int err; + + err = aead_check_key(sock); + if (err) + return err; + + return aead_sendpage(sock, page, offset, size, flags); +} + +static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) +{ + int err; + + err = aead_check_key(sock); + if (err) + return err; + + return aead_recvmsg(sock, msg, ignored, flags); +} + +static struct proto_ops algif_aead_ops_nokey = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .getsockopt = sock_no_getsockopt, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .accept = sock_no_accept, + .setsockopt = sock_no_setsockopt, + + .release = af_alg_release, + .sendmsg = aead_sendmsg_nokey, + .sendpage = aead_sendpage_nokey, + .recvmsg = aead_recvmsg_nokey, + .poll = aead_poll, +}; + static void *aead_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_aead(name, type, mask); + struct aead_tfm *tfm; + struct crypto_aead *aead; + + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); + if (!tfm) + return ERR_PTR(-ENOMEM); + + aead = crypto_alloc_aead(name, type, mask); + if (IS_ERR(aead)) { + kfree(tfm); + return ERR_CAST(aead); + } + + tfm->aead = aead; + + return tfm; } static void aead_release(void *private) { - crypto_free_aead(private); + struct aead_tfm *tfm = private; + + crypto_free_aead(tfm->aead); + kfree(tfm); } static int aead_setauthsize(void *private, unsigned int authsize) { - return crypto_aead_setauthsize(private, authsize); + struct aead_tfm *tfm = private; + + return crypto_aead_setauthsize(tfm->aead, authsize); } static int aead_setkey(void *private, const u8 *key, unsigned int keylen) { - return crypto_aead_setkey(private, key, keylen); + struct aead_tfm *tfm = private; + int err; + + err = crypto_aead_setkey(tfm->aead, key, keylen); + tfm->has_key = !err; + + return err; } static void aead_sock_destruct(struct sock *sk) @@ -766,12 +893,14 @@ static void aead_sock_destruct(struct sock *sk) af_alg_release_parent(sk); } -static int aead_accept_parent(void *private, struct sock *sk) +static int aead_accept_parent_nokey(void *private, struct sock *sk) { struct aead_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private); - unsigned int ivlen = crypto_aead_ivsize(private); + struct aead_tfm *tfm = private; + struct crypto_aead *aead = tfm->aead; + unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead); + unsigned int ivlen = crypto_aead_ivsize(aead); ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) @@ -798,7 +927,7 @@ static int aead_accept_parent(void *private, struct sock *sk) ask->private = ctx; - aead_request_set_tfm(&ctx->aead_req, private); + aead_request_set_tfm(&ctx->aead_req, aead); aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_complete, &ctx->completion); @@ -807,13 +936,25 @@ static int aead_accept_parent(void *private, struct sock *sk) return 0; } +static int aead_accept_parent(void *private, struct sock *sk) +{ + struct aead_tfm *tfm = private; + + if (!tfm->has_key) + return -ENOKEY; + + return aead_accept_parent_nokey(private, sk); +} + static const struct af_alg_type algif_type_aead = { .bind = aead_bind, .release = aead_release, .setkey = aead_setkey, .setauthsize = aead_setauthsize, .accept = aead_accept_parent, + .accept_nokey = aead_accept_parent_nokey, .ops = &algif_aead_ops, + .ops_nokey = &algif_aead_ops_nokey, .name = "aead", .owner = THIS_MODULE }; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 28556fce42671e2f182d5239d3dc6468e5b1d970..aaf2f810d170f2e31039dd5e2b607220645b4122 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -86,8 +86,13 @@ static void skcipher_free_async_sgls(struct skcipher_async_req *sreq) } sgl = sreq->tsg; n = sg_nents(sgl); - for_each_sg(sgl, sg, n, i) - put_page(sg_page(sg)); + for_each_sg(sgl, sg, n, i) { + struct page *page = sg_page(sg); + + /* some SGs may not have a page mapped */ + if (page && page_ref_count(page)) + put_page(page); + } kfree(sreq->tsg); } @@ -138,8 +143,10 @@ static int skcipher_alloc_sgl(struct sock *sk) sg_init_table(sgl->sg, MAX_SGL_ENTS + 1); sgl->cur = 0; - if (sg) + if (sg) { sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg); + sg_unmark_end(sg + (MAX_SGL_ENTS - 1)); + } list_add_tail(&sgl->list, &ctx->tsgl); } diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index af4cd864911752478ba5f3c2732273f9624d434f..d140d8bb2c96140c408b1e3450f288e562372743 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -88,6 +88,9 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg) bool want = false; sinfo = msg->signed_infos; + if (!sinfo) + goto inconsistent; + if (sinfo->authattrs) { want = true; msg->have_authattrs = true; diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 2ffd69769466082eaf55cdfe71fb67704e0364af..5a37962d21994c2f4ee55f31a40970cda1c4d439 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -150,7 +150,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7, pr_devel("Sig %u: Found cert serial match X.509[%u]\n", sinfo->index, certix); - if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) { + if (strcmp(x509->pub->pkey_algo, sinfo->sig->pkey_algo) != 0) { pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", sinfo->index); continue; diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index fd76b5fc3b3abe1919f193342108d87e8f1c0a93..4955eb66e361f45594a70c738b62fd6060ccdcc5 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -140,7 +140,7 @@ int public_key_verify_signature(const struct public_key *pkey, * signature and returns that to us. */ ret = crypto_akcipher_verify(req); - if (ret == -EINPROGRESS) { + if ((ret == -EINPROGRESS) || (ret == -EBUSY)) { wait_for_completion(&compl.completion); ret = compl.err; } diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index c80765b211cf0fae7a91c35494dc9ed45247eafe..029f7051f2beae25286f4601948303408ed75849 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -408,6 +408,8 @@ int x509_extract_key_data(void *context, size_t hdrlen, ctx->cert->pub->pkey_algo = "rsa"; /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; ctx->key = value + 1; ctx->key_size = vlen - 1; return 0; diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index fb732296cd36437950e9228baaecce4373a329eb..e16009a8da9ca580c230a74536eeda8be7b128ca 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -125,7 +125,7 @@ int x509_check_for_self_signed(struct x509_certificate *cert) } ret = -EKEYREJECTED; - if (cert->pub->pkey_algo != cert->sig->pkey_algo) + if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0) goto out; ret = public_key_verify_signature(cert->pub, cert->sig); diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 121010ac99629c679c419ac1478b448fae253f1e..18c94e1c31d1082658c372d513ca4e9244298497 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -248,6 +248,9 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, u8 *ihash = ohash + crypto_ahash_digestsize(auth); u32 tmp[2]; + if (!authsize) + goto decrypt; + /* Move high-order bits of sequence number back. */ scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); @@ -256,6 +259,8 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, if (crypto_memneq(ihash, ohash, authsize)) return -EBADMSG; +decrypt: + sg_init_table(areq_ctx->dst, 2); dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); diff --git a/crypto/ccm.c b/crypto/ccm.c index 006d8575ef5c71b5ca5f43f35c93a636ce74c618..b3ace633fae92a09c1e3f86876eb137b21b4b729 100644 --- a/crypto/ccm.c +++ b/crypto/ccm.c @@ -413,7 +413,7 @@ static int crypto_ccm_decrypt(struct aead_request *req) unsigned int cryptlen = req->cryptlen; u8 *authtag = pctx->auth_tag; u8 *odata = pctx->odata; - u8 *iv = req->iv; + u8 *iv = pctx->idata; int err; cryptlen -= authsize; @@ -429,6 +429,8 @@ static int crypto_ccm_decrypt(struct aead_request *req) if (req->src != req->dst) dst = pctx->dst; + memcpy(iv, req->iv, 16); + skcipher_request_set_tfm(skreq, ctx->ctr); skcipher_request_set_callback(skreq, pctx->flags, crypto_ccm_decrypt_done, req); diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c index e899ef51dc8eda2dec93f98a1260977f04e9d4b2..cb1c3a3287b09a69896f02ddd007f9fbda5a81e5 100644 --- a/crypto/chacha20poly1305.c +++ b/crypto/chacha20poly1305.c @@ -610,6 +610,11 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, algt->mask)); if (IS_ERR(poly)) return PTR_ERR(poly); + poly_hash = __crypto_hash_alg_common(poly); + + err = -EINVAL; + if (poly_hash->digestsize != POLY1305_DIGEST_SIZE) + goto out_put_poly; err = -ENOMEM; inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); @@ -618,7 +623,6 @@ static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, ctx = aead_instance_ctx(inst); ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize; - poly_hash = __crypto_hash_alg_common(poly); err = crypto_init_ahash_spawn(&ctx->poly, poly_hash, aead_crypto_instance(inst)); if (err) diff --git a/crypto/dh.c b/crypto/dh.c index 9d19360e71897d3971f117338c27eb151d8f3e25..99e20fc63cc9ee36df9a7d5474f77b40b37fba11 100644 --- a/crypto/dh.c +++ b/crypto/dh.c @@ -21,19 +21,12 @@ struct dh_ctx { MPI xa; }; -static inline void dh_clear_params(struct dh_ctx *ctx) +static void dh_clear_ctx(struct dh_ctx *ctx) { mpi_free(ctx->p); mpi_free(ctx->g); - ctx->p = NULL; - ctx->g = NULL; -} - -static void dh_free_ctx(struct dh_ctx *ctx) -{ - dh_clear_params(ctx); mpi_free(ctx->xa); - ctx->xa = NULL; + memset(ctx, 0, sizeof(*ctx)); } /* @@ -71,10 +64,8 @@ static int dh_set_params(struct dh_ctx *ctx, struct dh *params) return -EINVAL; ctx->g = mpi_read_raw_data(params->g, params->g_size); - if (!ctx->g) { - mpi_free(ctx->p); + if (!ctx->g) return -EINVAL; - } return 0; } @@ -84,19 +75,24 @@ static int dh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len) struct dh_ctx *ctx = dh_get_ctx(tfm); struct dh params; + /* Free the old MPI key if any */ + dh_clear_ctx(ctx); + if (crypto_dh_decode_key(buf, len, ¶ms) < 0) - return -EINVAL; + goto err_clear_ctx; if (dh_set_params(ctx, ¶ms) < 0) - return -EINVAL; + goto err_clear_ctx; ctx->xa = mpi_read_raw_data(params.key, params.key_size); - if (!ctx->xa) { - dh_clear_params(ctx); - return -EINVAL; - } + if (!ctx->xa) + goto err_clear_ctx; return 0; + +err_clear_ctx: + dh_clear_ctx(ctx); + return -EINVAL; } static int dh_compute_value(struct kpp_request *req) @@ -154,7 +150,7 @@ static void dh_exit_tfm(struct crypto_kpp *tfm) { struct dh_ctx *ctx = dh_get_ctx(tfm); - dh_free_ctx(ctx); + dh_clear_ctx(ctx); } static struct kpp_alg dh = { diff --git a/crypto/dh_helper.c b/crypto/dh_helper.c index 02db76b20d003f02e86ef88552663c97f3a449a1..14539904416e93cebb370db4418a3e038382b958 100644 --- a/crypto/dh_helper.c +++ b/crypto/dh_helper.c @@ -83,6 +83,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params) if (secret.len != crypto_dh_key_len(params)) return -EINVAL; + /* + * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since + * some drivers assume otherwise. + */ + if (params->key_size > params->p_size || + params->g_size > params->p_size) + return -EINVAL; + /* Don't allocate memory. Set pointers to data within * the given buffer */ @@ -90,6 +98,14 @@ int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params) params->p = (void *)(ptr + params->key_size); params->g = (void *)(ptr + params->key_size + params->p_size); + /* + * Don't permit 'p' to be 0. It's not a prime number, and it's subject + * to corner cases such as 'mod 0' being undefined or + * crypto_kpp_maxsize() returning 0. + */ + if (memchr_inv(params->p, 0, params->p_size) == NULL) + return -EINVAL; + return 0; } EXPORT_SYMBOL_GPL(crypto_dh_decode_key); diff --git a/crypto/drbg.c b/crypto/drbg.c index 053035b5c8f85686446df108ccbf3675a19cd056..942ddff684083d5dc86ad43b535af5af8bc5aeca 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1133,10 +1133,10 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) { if (!drbg) return; - kzfree(drbg->V); - drbg->Vbuf = NULL; - kzfree(drbg->C); - drbg->Cbuf = NULL; + kzfree(drbg->Vbuf); + drbg->V = NULL; + kzfree(drbg->Cbuf); + drbg->C = NULL; kzfree(drbg->scratchpadbuf); drbg->scratchpadbuf = NULL; drbg->reseed_ctr = 0; @@ -1691,6 +1691,7 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg) return PTR_ERR(sk_tfm); } drbg->ctr_handle = sk_tfm; + init_completion(&drbg->ctr_completion); req = skcipher_request_alloc(sk_tfm, GFP_KERNEL); if (!req) { @@ -1768,9 +1769,8 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, break; case -EINPROGRESS: case -EBUSY: - ret = wait_for_completion_interruptible( - &drbg->ctr_completion); - if (!ret && !drbg->ctr_async_err) { + wait_for_completion(&drbg->ctr_completion); + if (!drbg->ctr_async_err) { reinit_completion(&drbg->ctr_completion); break; } diff --git a/crypto/gcm.c b/crypto/gcm.c index f624ac98c94e4d9b1910178feb279a610c603e28..dd33fbd2d868b5840a5219f61a6bb4114f4c829c 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -152,10 +152,8 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, err = crypto_skcipher_encrypt(&data->req); if (err == -EINPROGRESS || err == -EBUSY) { - err = wait_for_completion_interruptible( - &data->result.completion); - if (!err) - err = data->result.err; + wait_for_completion(&data->result.completion); + err = data->result.err; } if (err) diff --git a/crypto/hmac.c b/crypto/hmac.c index 72e38c098bb3184d3886ac4054f123dca3bb49ac..ba07fb6221aee61be48bed8c4a1b994f3d61a0cb 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -194,11 +194,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) salg = shash_attr_alg(tb[1], 0, 0); if (IS_ERR(salg)) return PTR_ERR(salg); + alg = &salg->base; + /* The underlying hash algorithm must be unkeyed */ err = -EINVAL; + if (crypto_shash_alg_has_setkey(salg)) + goto out_put_alg; + ds = salg->digestsize; ss = salg->statesize; - alg = &salg->base; if (ds > alg->cra_blocksize || ss < alg->cra_blocksize) goto out_put_alg; diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c index c207458d62993350d9a0cfca5e1deca573b09c8c..a14100e747548a90d56abc3dc77ee85380dc551c 100644 --- a/crypto/mcryptd.c +++ b/crypto/mcryptd.c @@ -80,6 +80,7 @@ static int mcryptd_init_queue(struct mcryptd_queue *queue, pr_debug("cpu_queue #%d %p\n", cpu, queue->cpu_queue); crypto_init_queue(&cpu_queue->queue, max_cpu_qlen); INIT_WORK(&cpu_queue->work, mcryptd_queue_worker); + spin_lock_init(&cpu_queue->q_lock); } return 0; } @@ -103,15 +104,16 @@ static int mcryptd_enqueue_request(struct mcryptd_queue *queue, int cpu, err; struct mcryptd_cpu_queue *cpu_queue; - cpu = get_cpu(); - cpu_queue = this_cpu_ptr(queue->cpu_queue); - rctx->tag.cpu = cpu; + cpu_queue = raw_cpu_ptr(queue->cpu_queue); + spin_lock(&cpu_queue->q_lock); + cpu = smp_processor_id(); + rctx->tag.cpu = smp_processor_id(); err = crypto_enqueue_request(&cpu_queue->queue, request); pr_debug("enqueue request: cpu %d cpu_queue %p request %p\n", cpu, cpu_queue, request); + spin_unlock(&cpu_queue->q_lock); queue_work_on(cpu, kcrypto_wq, &cpu_queue->work); - put_cpu(); return err; } @@ -160,16 +162,11 @@ static void mcryptd_queue_worker(struct work_struct *work) cpu_queue = container_of(work, struct mcryptd_cpu_queue, work); i = 0; while (i < MCRYPTD_BATCH || single_task_running()) { - /* - * preempt_disable/enable is used to prevent - * being preempted by mcryptd_enqueue_request() - */ - local_bh_disable(); - preempt_disable(); + + spin_lock_bh(&cpu_queue->q_lock); backlog = crypto_get_backlog(&cpu_queue->queue); req = crypto_dequeue_request(&cpu_queue->queue); - preempt_enable(); - local_bh_enable(); + spin_unlock_bh(&cpu_queue->q_lock); if (!req) { mcryptd_opportunistic_flush(); @@ -184,7 +181,7 @@ static void mcryptd_queue_worker(struct work_struct *work) ++i; } if (cpu_queue->queue.qlen) - queue_work(kcrypto_wq, &cpu_queue->work); + queue_work_on(smp_processor_id(), kcrypto_wq, &cpu_queue->work); } void mcryptd_flusher(struct work_struct *__work) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index ee9cfb99fe256af06ae7ad5d946c3b76d90de1e9..f8ec3d4ba4a80f8eefed739d9e8a852865a7ac02 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -254,6 +254,14 @@ static void pcrypt_aead_exit_tfm(struct crypto_aead *tfm) crypto_free_aead(ctx->child); } +static void pcrypt_free(struct aead_instance *inst) +{ + struct pcrypt_instance_ctx *ctx = aead_instance_ctx(inst); + + crypto_drop_aead(&ctx->spawn); + kfree(inst); +} + static int pcrypt_init_instance(struct crypto_instance *inst, struct crypto_alg *alg) { @@ -319,6 +327,8 @@ static int pcrypt_create_aead(struct crypto_template *tmpl, struct rtattr **tb, inst->alg.encrypt = pcrypt_aead_encrypt; inst->alg.decrypt = pcrypt_aead_decrypt; + inst->free = pcrypt_free; + err = aead_register_instance(tmpl, inst); if (err) goto out_drop_aead; @@ -349,14 +359,6 @@ static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb) return -EINVAL; } -static void pcrypt_free(struct crypto_instance *inst) -{ - struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst); - - crypto_drop_aead(&ctx->spawn); - kfree(inst); -} - static int pcrypt_cpumask_change_notify(struct notifier_block *self, unsigned long val, void *data) { @@ -469,7 +471,6 @@ static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) static struct crypto_template pcrypt_tmpl = { .name = "pcrypt", .create = pcrypt_create, - .free = pcrypt_free, .module = THIS_MODULE, }; diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index 8baab4307f7b9a9064fa1234825fca29a34380c6..7830d304dff6f75d9464857fbab0592872657d37 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -496,7 +496,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) goto done; pos++; - if (memcmp(out_buf + pos, digest_info->data, digest_info->size)) + if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size)) goto done; pos += digest_info->size; diff --git a/crypto/rsa_helper.c b/crypto/rsa_helper.c index 0b66dc8246068aa084dd0b44210b04dee5f2bccb..cad395d70d78e18527866bf1a3f6452c338e4c7c 100644 --- a/crypto/rsa_helper.c +++ b/crypto/rsa_helper.c @@ -30,7 +30,7 @@ int rsa_get_n(void *context, size_t hdrlen, unsigned char tag, return -EINVAL; if (fips_enabled) { - while (!*ptr && n_sz) { + while (n_sz && !*ptr) { ptr++; n_sz--; } diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index f550b5d9463074b16670129341de59e069f8509c..d7da0eea5622af96f63300ad45c35450951551e1 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -188,13 +188,6 @@ static int encrypt(struct blkcipher_desc *desc, salsa20_ivsetup(ctx, walk.iv); - if (likely(walk.nbytes == nbytes)) - { - salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, - walk.src.virt.addr, nbytes); - return blkcipher_walk_done(desc, &walk, 0); - } - while (walk.nbytes >= 64) { salsa20_encrypt_bytes(ctx, walk.dst.virt.addr, walk.src.virt.addr, diff --git a/crypto/shash.c b/crypto/shash.c index a051541a4a1718c996ba7a7b678b5b9e5e857488..9bd5044d467b28b6f430d08ef6e8c45559b51779 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -24,11 +24,12 @@ static const struct crypto_type crypto_shash_type; -static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) +int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) { return -ENOSYS; } +EXPORT_SYMBOL_GPL(shash_no_setkey); static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) @@ -274,12 +275,14 @@ static int shash_async_finup(struct ahash_request *req) int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) { - struct scatterlist *sg = req->src; - unsigned int offset = sg->offset; unsigned int nbytes = req->nbytes; + struct scatterlist *sg; + unsigned int offset; int err; - if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { + if (nbytes && + (sg = req->src, offset = sg->offset, + nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) { void *data; data = kmap_atomic(sg_page(sg)); diff --git a/crypto/skcipher.c b/crypto/skcipher.c index f7d0018dcaee68972abd330ee767d1af62dc1120..93110d70c1d3061bf1640989addca4b8a5a2cb48 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -221,6 +221,44 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) return 0; } +static int skcipher_setkey_unaligned(struct crypto_skcipher *tfm, + const u8 *key, unsigned int keylen) +{ + unsigned long alignmask = crypto_skcipher_alignmask(tfm); + struct skcipher_alg *cipher = crypto_skcipher_alg(tfm); + u8 *buffer, *alignbuffer; + unsigned long absize; + int ret; + + absize = keylen + alignmask; + buffer = kmalloc(absize, GFP_ATOMIC); + if (!buffer) + return -ENOMEM; + + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keylen); + ret = cipher->setkey(tfm, alignbuffer, keylen); + kzfree(buffer); + return ret; +} + +static int skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct skcipher_alg *cipher = crypto_skcipher_alg(tfm); + unsigned long alignmask = crypto_skcipher_alignmask(tfm); + + if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { + crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + if ((unsigned long)key & alignmask) + return skcipher_setkey_unaligned(tfm, key, keylen); + + return cipher->setkey(tfm, key, keylen); +} + static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) { struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); @@ -241,7 +279,7 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) tfm->__crt_alg->cra_type == &crypto_givcipher_type) return crypto_init_skcipher_ops_ablkcipher(tfm); - skcipher->setkey = alg->setkey; + skcipher->setkey = skcipher_setkey; skcipher->encrypt = alg->encrypt; skcipher->decrypt = alg->decrypt; skcipher->ivsize = alg->ivsize; diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index ae22f05d5936c724f830cd00afee303a85836dd5..e3af318af2db71088970b57c75dfdefbb5ff607d 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -342,7 +342,7 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs, } sg_init_aead(sg, xbuf, - *b_size + (enc ? authsize : 0)); + *b_size + (enc ? 0 : authsize)); sg_init_aead(sgout, xoutbuf, *b_size + (enc ? authsize : 0)); @@ -350,7 +350,9 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs, sg_set_buf(&sg[0], assoc, aad_size); sg_set_buf(&sgout[0], assoc, aad_size); - aead_request_set_crypt(req, sg, sgout, *b_size, iv); + aead_request_set_crypt(req, sg, sgout, + *b_size + (enc ? 0 : authsize), + iv); aead_request_set_ad(req, aad_size); if (secs) diff --git a/drivers/Kconfig b/drivers/Kconfig index 6266a379ae2bba79ab7ed39e2c6cf91946e72689..e37c9aa5bae316204378a7add1c08a8d14130497 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -54,8 +54,6 @@ source "drivers/char/Kconfig" source "drivers/i2c/Kconfig" -source "drivers/soundwire/Kconfig" - source "drivers/spi/Kconfig" source "drivers/slimbus/Kconfig" @@ -208,4 +206,6 @@ source "drivers/hwtracing/intel_th/Kconfig" source "drivers/fpga/Kconfig" +source "drivers/sensors/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 1419893db49be6788ca961cb246d3f8be8a3104f..04e2d4e83f4e286572d4663be221ced3220a4915 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ obj-$(CONFIG_NUBUS) += nubus/ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ +obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SCSI) += scsi/ obj-y += nvme/ obj-$(CONFIG_ATA) += ata/ @@ -80,7 +81,6 @@ obj-$(CONFIG_TARGET_CORE) += target/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_SPMI) += spmi/ -obj-$(CONFIG_SOUNDWIRE) += soundwire/ obj-$(CONFIG_SLIMBUS) += slimbus/ obj-$(CONFIG_HSI) += hsi/ obj-y += net/ @@ -103,6 +103,7 @@ obj-$(CONFIG_USB_PHY) += usb/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_PCI) += usb/ obj-$(CONFIG_USB_GADGET) += usb/ +obj-$(CONFIG_OF) += usb/ obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ @@ -130,7 +131,6 @@ obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ -obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ ifndef CONFIG_ARCH_USES_GETTIMEOFFSET obj-y += clocksource/ @@ -176,3 +176,4 @@ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_ESOC) += esoc/ obj-$(CONFIG_FPGA) += fpga/ +obj-$(CONFIG_SENSORS_SSC) += sensors/ diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 3de3b6b8f0f1b756adc455229aedba9731113e5d..f43a586236eaa3490fc30e2aab51c50f9ac113a3 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -182,11 +182,6 @@ int __weak arch_register_cpu(int cpu) void __weak arch_unregister_cpu(int cpu) {} -int __weak acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) -{ - return -ENODEV; -} - static int acpi_processor_hotadd_init(struct acpi_processor *pr) { unsigned long long sta; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index ec4f507b524fa81343c44d0da039a19e468da5c4..4558cc73abf348a37680e8e62f4200dcc0e9f69a 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1020,7 +1020,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, /* The record may be cleared by others, try read next record */ if (len == -ENOENT) goto skip; - else if (len < sizeof(*rcd)) { + else if (len < 0 || len < sizeof(*rcd)) { rc = -EIO; goto out; } diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index e53bef6cf53c627d7c9a6a566d75fbe1805d1138..0375c602406217708c7a80a5f1d8c1ffc33a558b 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1072,6 +1072,7 @@ static int ghes_remove(struct platform_device *ghes_dev) if (list_empty(&ghes_sci)) unregister_acpi_hed_notifier(&ghes_notifier_sci); mutex_unlock(&ghes_list_mutex); + synchronize_rcu(); break; case ACPI_HEST_NOTIFY_NMI: ghes_nmi_remove(ghes); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 56190d00fd87042461f430c5aa1cdd82fb60dc8d..0a3ca20f99af30221293df5ccf1e4cbd8292bd6e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1197,7 +1197,6 @@ static int __init acpi_init(void) acpi_wakeup_device_init(); acpi_debugger_init(); acpi_setup_sb_notify_handler(); - acpi_set_processor_mapping(); return 0; } diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6d5a8c1d313269eaa2a18fcb1fdc611e90ccf1b9..e19f530f1083a13732328516925e3bbeb6493e14 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -113,7 +113,7 @@ struct acpi_button { static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); static struct acpi_device *lid_device; -static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; +static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; static unsigned long lid_report_interval __read_mostly = 500; module_param(lid_report_interval, ulong, 0644); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 22ca89242518432e4bcbffe75725edfad9a47db8..c3bcb7f5986e704c4b0bdc67956ae5b999702b17 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -147,7 +147,7 @@ static unsigned int ec_storm_threshold __read_mostly = 8; module_param(ec_storm_threshold, uint, 0644); MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); -static bool ec_freeze_events __read_mostly = true; +static bool ec_freeze_events __read_mostly = false; module_param(ec_freeze_events, bool, 0644); MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume"); @@ -482,8 +482,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec) { if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) ec_log_drv("event unblocked"); - if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - advance_transaction(ec); + /* + * Unconditionally invoke this once after enabling the event + * handling mechanism to detect the pending events. + */ + advance_transaction(ec); } static inline void __acpi_ec_disable_event(struct acpi_ec *ec) @@ -1458,11 +1461,10 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) acpi_ec_enable_gpe(ec, true); - - /* EC is fully operational, allow queries */ - acpi_ec_enable_event(ec); } } + /* EC is fully operational, allow queries */ + acpi_ec_enable_event(ec); return 0; } @@ -1728,7 +1730,7 @@ int __init acpi_ec_dsdt_probe(void) * functioning ECDT EC first in order to handle the events. * https://bugzilla.kernel.org/show_bug.cgi?id=115021 */ -int __init acpi_ec_ecdt_start(void) +static int __init acpi_ec_ecdt_start(void) { acpi_handle handle; @@ -1865,24 +1867,6 @@ int __init acpi_ec_ecdt_probe(void) } #ifdef CONFIG_PM_SLEEP -static int acpi_ec_suspend_noirq(struct device *dev) -{ - struct acpi_ec *ec = - acpi_driver_data(to_acpi_device(dev)); - - acpi_ec_enter_noirq(ec); - return 0; -} - -static int acpi_ec_resume_noirq(struct device *dev) -{ - struct acpi_ec *ec = - acpi_driver_data(to_acpi_device(dev)); - - acpi_ec_leave_noirq(ec); - return 0; -} - static int acpi_ec_suspend(struct device *dev) { struct acpi_ec *ec = @@ -1904,7 +1888,6 @@ static int acpi_ec_resume(struct device *dev) #endif static const struct dev_pm_ops acpi_ec_pm = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq) SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume) }; @@ -1978,20 +1961,17 @@ static inline void acpi_ec_query_exit(void) int __init acpi_ec_init(void) { int result; + int ecdt_fail, dsdt_fail; /* register workqueue for _Qxx evaluations */ result = acpi_ec_query_init(); if (result) - goto err_exit; - /* Now register the driver for the EC */ - result = acpi_bus_register_driver(&acpi_ec_driver); - if (result) - goto err_exit; + return result; -err_exit: - if (result) - acpi_ec_query_exit(); - return result; + /* Drivers must be started after acpi_ec_query_init() */ + ecdt_fail = acpi_ec_ecdt_start(); + dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); + return ecdt_fail && dsdt_fail ? -ENODEV : 0; } /* EC driver currently not unloadable */ diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 5ea5dc219f563702e5bad7141832af2861e9144a..73c9c7fa9001434ec2bd8b1815260404a3308176 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -98,7 +98,15 @@ static int find_child_checks(struct acpi_device *adev, bool check_children) if (check_children && list_empty(&adev->children)) return -ENODEV; - return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; + /* + * If the device has a _HID (or _CID) returning a valid ACPI/PNP + * device ID, it is better to make it look less attractive here, so that + * the other device with the same _ADR value (that may not have a valid + * device ID) can be matched going forward. [This means a second spec + * violation in a row, so whatever we do here is best effort anyway.] + */ + return sta_present && list_empty(&adev->pnp.ids) ? + FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } struct acpi_device *acpi_find_child_device(struct acpi_device *parent, diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 219b90bc092297c753639f84972939710de25298..08b3ca0ead69f3dc9f8139a1b2dff658fe74510c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -185,7 +185,6 @@ typedef int (*acpi_ec_query_func) (void *data); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_ec_dsdt_probe(void); -int acpi_ec_ecdt_start(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c index 6d7ce6e12aaa6662b360c391f8c3b5e84a84ddc7..5e18ccf5ab57c12132603e87fd056566c58a3ba7 100644 --- a/drivers/acpi/ioapic.c +++ b/drivers/acpi/ioapic.c @@ -45,6 +45,12 @@ static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) struct resource *res = data; struct resource_win win; + /* + * We might assign this to 'res' later, make sure all pointers are + * cleared before the resource is added to the global list + */ + memset(&win, 0, sizeof(win)); + res->flags = 0; if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM)) return AE_OK; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 9ef3941eeff0f067c5686a4e90705c76b7ab2fdb..fe03d00de22b3dd8462ec6aa25b2dee0523747f4 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1390,6 +1390,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, dev_name(&adev_dimm->dev)); return -ENXIO; } + /* + * Record nfit_mem for the notification path to track back to + * the nfit sysfs attributes for this dimm device object. + */ + dev_set_drvdata(&adev_dimm->dev, nfit_mem); /* * Until standardization materializes we need to consider 4 @@ -1446,9 +1451,11 @@ static void shutdown_dimm_notify(void *data) sysfs_put(nfit_mem->flags_attr); nfit_mem->flags_attr = NULL; } - if (adev_dimm) + if (adev_dimm) { acpi_remove_notify_handler(adev_dimm->handle, ACPI_DEVICE_NOTIFY, acpi_nvdimm_notify); + dev_set_drvdata(&adev_dimm->dev, NULL); + } } mutex_unlock(&acpi_desc->init_mutex); } @@ -2945,6 +2952,8 @@ static struct acpi_driver acpi_nfit_driver = { static __init int nfit_init(void) { + int ret; + BUILD_BUG_ON(sizeof(struct acpi_table_nfit) != 40); BUILD_BUG_ON(sizeof(struct acpi_nfit_system_address) != 56); BUILD_BUG_ON(sizeof(struct acpi_nfit_memory_map) != 48); @@ -2972,8 +2981,14 @@ static __init int nfit_init(void) return -ENOMEM; nfit_mce_register(); + ret = acpi_bus_register_driver(&acpi_nfit_driver); + if (ret) { + nfit_mce_unregister(); + destroy_workqueue(nfit_wq); + } + + return ret; - return acpi_bus_register_driver(&acpi_nfit_driver); } static __exit void nfit_exit(void) diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c index e5ce81c38eed4bbeea0bcbc380c77ba66d0b097c..e25787afb212cd5681c6793d8abc2e8f5f2d65d1 100644 --- a/drivers/acpi/nfit/mce.c +++ b/drivers/acpi/nfit/mce.c @@ -26,7 +26,7 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val, struct nfit_spa *nfit_spa; /* We only care about memory errors */ - if (!(mce->status & MCACOD)) + if (!mce_is_memory_error(mce)) return NOTIFY_DONE; /* diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 5c78ee1860b0ad390671e8f1b1c624339f7414ed..fd59ae871db3b4e2034fbec95373a852ddc9047c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -280,79 +280,6 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) } EXPORT_SYMBOL_GPL(acpi_get_cpuid); -#ifdef CONFIG_ACPI_HOTPLUG_CPU -static bool __init -map_processor(acpi_handle handle, phys_cpuid_t *phys_id, int *cpuid) -{ - int type, id; - u32 acpi_id; - acpi_status status; - acpi_object_type acpi_type; - unsigned long long tmp; - union acpi_object object = { 0 }; - struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; - - status = acpi_get_type(handle, &acpi_type); - if (ACPI_FAILURE(status)) - return false; - - switch (acpi_type) { - case ACPI_TYPE_PROCESSOR: - status = acpi_evaluate_object(handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) - return false; - acpi_id = object.processor.proc_id; - - /* validate the acpi_id */ - if(acpi_processor_validate_proc_id(acpi_id)) - return false; - break; - case ACPI_TYPE_DEVICE: - status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); - if (ACPI_FAILURE(status)) - return false; - acpi_id = tmp; - break; - default: - return false; - } - - type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; - - *phys_id = __acpi_get_phys_id(handle, type, acpi_id, false); - id = acpi_map_cpuid(*phys_id, acpi_id); - - if (id < 0) - return false; - *cpuid = id; - return true; -} - -static acpi_status __init -set_processor_node_mapping(acpi_handle handle, u32 lvl, void *context, - void **rv) -{ - phys_cpuid_t phys_id; - int cpu_id; - - if (!map_processor(handle, &phys_id, &cpu_id)) - return AE_ERROR; - - acpi_map_cpu2node(handle, cpu_id, phys_id); - return AE_OK; -} - -void __init acpi_set_processor_mapping(void) -{ - /* Set persistent cpu <-> node mapping for all processors. */ - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, set_processor_node_mapping, - NULL, NULL, NULL); -} -#else -void __init acpi_set_processor_mapping(void) {} -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ - #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, u64 *phys_addr, int *ioapic_id) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index dd3786acba89258622d1fe03238a0903c2fa9199..cf725d581cae48100d4c1c84762e5cb47f8d3898 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2051,7 +2051,6 @@ int __init acpi_scan_init(void) acpi_gpe_apply_masked_gpes(); acpi_update_all_gpes(); - acpi_ec_ecdt_start(); acpi_scan_initialized = true; diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 4d4cdc1a6e257c2df4aab9ca0ec9126cb6969415..01de42c8b74bd7032197512ea79c658606f660e4 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -44,6 +44,16 @@ config ANDROID_BINDER_IPC_32BIT Note that enabling this will break newer Android user-space. +config ANDROID_BINDER_IPC_SELFTEST + bool "Android Binder IPC Driver Selftest" + depends on ANDROID_BINDER_IPC + ---help--- + This feature allows binder selftest to run. + + Binder selftest checks the allocation and free of binder buffers + exhaustively with combinations of various buffer sizes and + alignments. + endif # if ANDROID endmenu diff --git a/drivers/android/Makefile b/drivers/android/Makefile index 3b7e4b072c58c77dcd1b283711dfa96e34abdaa7..a01254c43ee3f714020aff487314f32ec0b2bbde 100644 --- a/drivers/android/Makefile +++ b/drivers/android/Makefile @@ -1,3 +1,4 @@ ccflags-y += -I$(src) # needed for trace events -obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o +obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o +obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 6485c7744656aa580fced236f4ddf136b12d3fbf..1ef2f68bfcb2fb1c7cea1538e7a2c163e193142b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -15,6 +15,40 @@ * */ +/* + * Locking overview + * + * There are 3 main spinlocks which must be acquired in the + * order shown: + * + * 1) proc->outer_lock : protects binder_ref + * binder_proc_lock() and binder_proc_unlock() are + * used to acq/rel. + * 2) node->lock : protects most fields of binder_node. + * binder_node_lock() and binder_node_unlock() are + * used to acq/rel + * 3) proc->inner_lock : protects the thread and node lists + * (proc->threads, proc->waiting_threads, proc->nodes) + * and all todo lists associated with the binder_proc + * (proc->todo, thread->todo, proc->delivered_death and + * node->async_todo), as well as thread->transaction_stack + * binder_inner_proc_lock() and binder_inner_proc_unlock() + * are used to acq/rel + * + * Any lock under procA must never be nested under any lock at the same + * level or below on procB. + * + * Functions that require a lock held on entry indicate which lock + * in the suffix of the function name: + * + * foo_olocked() : requires node->outer_lock + * foo_nlocked() : requires node->lock + * foo_ilocked() : requires proc->inner_lock + * foo_oilocked(): requires proc->outer_lock and proc->inner_lock + * foo_nilocked(): requires node->lock and proc->inner_lock + * ... + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -24,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -34,30 +67,31 @@ #include #include #include -#include -#include #include #include +#include #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT #define BINDER_IPC_32BIT 1 #endif #include +#include "binder_alloc.h" #include "binder_trace.h" -static DEFINE_MUTEX(binder_main_lock); +static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); -static DEFINE_MUTEX(binder_mmap_lock); static HLIST_HEAD(binder_devices); static HLIST_HEAD(binder_procs); -static HLIST_HEAD(binder_deferred_list); +static DEFINE_MUTEX(binder_procs_lock); + static HLIST_HEAD(binder_dead_nodes); +static DEFINE_SPINLOCK(binder_dead_nodes_lock); static struct dentry *binder_debugfs_dir_entry_root; static struct dentry *binder_debugfs_dir_entry_proc; -static int binder_last_id; +static atomic_t binder_last_id; #define BINDER_DEBUG_ENTRY(name) \ static int binder_##name##_open(struct inode *inode, struct file *file) \ @@ -103,17 +137,13 @@ enum { BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, BINDER_DEBUG_FREE_BUFFER = 1U << 11, BINDER_DEBUG_INTERNAL_REFS = 1U << 12, - BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, - BINDER_DEBUG_PRIORITY_CAP = 1U << 14, - BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, + BINDER_DEBUG_PRIORITY_CAP = 1U << 13, + BINDER_DEBUG_SPINLOCKS = 1U << 14, }; static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); -static bool binder_debug_no_lock; -module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); - static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, S_IRUGO); @@ -170,26 +200,27 @@ enum binder_stat_types { }; struct binder_stats { - int br[_IOC_NR(BR_FAILED_REPLY) + 1]; - int bc[_IOC_NR(BC_REPLY_SG) + 1]; - int obj_created[BINDER_STAT_COUNT]; - int obj_deleted[BINDER_STAT_COUNT]; + atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; + atomic_t obj_created[BINDER_STAT_COUNT]; + atomic_t obj_deleted[BINDER_STAT_COUNT]; }; static struct binder_stats binder_stats; static inline void binder_stats_deleted(enum binder_stat_types type) { - binder_stats.obj_deleted[type]++; + atomic_inc(&binder_stats.obj_deleted[type]); } static inline void binder_stats_created(enum binder_stat_types type) { - binder_stats.obj_created[type]++; + atomic_inc(&binder_stats.obj_created[type]); } struct binder_transaction_log_entry { int debug_id; + int debug_id_done; int call_type; int from_proc; int from_thread; @@ -199,11 +230,14 @@ struct binder_transaction_log_entry { int to_node; int data_size; int offsets_size; + int return_error_line; + uint32_t return_error; + uint32_t return_error_param; const char *context_name; }; struct binder_transaction_log { - int next; - int full; + atomic_t cur; + bool full; struct binder_transaction_log_entry entry[32]; }; static struct binder_transaction_log binder_transaction_log; @@ -213,19 +247,26 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) { struct binder_transaction_log_entry *e; + unsigned int cur = atomic_inc_return(&log->cur); - e = &log->entry[log->next]; - memset(e, 0, sizeof(*e)); - log->next++; - if (log->next == ARRAY_SIZE(log->entry)) { - log->next = 0; + if (cur >= ARRAY_SIZE(log->entry)) log->full = 1; - } + e = &log->entry[cur % ARRAY_SIZE(log->entry)]; + WRITE_ONCE(e->debug_id_done, 0); + /* + * write-barrier to synchronize access to e->debug_id_done. + * We make sure the initialized 0 value is seen before + * memset() other fields are zeroed by memset. + */ + smp_wmb(); + memset(e, 0, sizeof(*e)); return e; } struct binder_context { struct binder_node *binder_context_mgr_node; + struct mutex context_mgr_node_lock; + kuid_t binder_context_mgr_uid; const char *name; }; @@ -236,11 +277,20 @@ struct binder_device { struct binder_context context; }; +/** + * struct binder_work - work enqueued on a worklist + * @entry: node enqueued on list + * @type: type of work to be performed + * + * There are separate work lists for proc, thread, and node (async). + */ struct binder_work { struct list_head entry; + enum { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_RETURN_ERROR, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, @@ -248,8 +298,76 @@ struct binder_work { } type; }; +struct binder_error { + struct binder_work work; + uint32_t cmd; +}; + +/** + * struct binder_node - binder node bookkeeping + * @debug_id: unique ID for debugging + * (invariant after initialized) + * @lock: lock for node fields + * @work: worklist element for node work + * (protected by @proc->inner_lock) + * @rb_node: element for proc->nodes tree + * (protected by @proc->inner_lock) + * @dead_node: element for binder_dead_nodes list + * (protected by binder_dead_nodes_lock) + * @proc: binder_proc that owns this node + * (invariant after initialized) + * @refs: list of references on this node + * (protected by @lock) + * @internal_strong_refs: used to take strong references when + * initiating a transaction + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_weak_refs: weak user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @local_strong_refs: strong user refs from local process + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @tmp_refs: temporary kernel refs + * (protected by @proc->inner_lock while @proc + * is valid, and by binder_dead_nodes_lock + * if @proc is NULL. During inc/dec and node release + * it is also protected by @lock to provide safety + * as the node dies and @proc becomes NULL) + * @ptr: userspace pointer for node + * (invariant, no lock needed) + * @cookie: userspace cookie for node + * (invariant, no lock needed) + * @has_strong_ref: userspace notified of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_strong_ref: userspace has acked notification of strong ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_weak_ref: userspace notified of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @pending_weak_ref: userspace has acked notification of weak ref + * (protected by @proc->inner_lock if @proc + * and by @lock) + * @has_async_transaction: async transaction to node in progress + * (protected by @lock) + * @sched_policy: minimum scheduling policy for node + * (invariant after initialized) + * @accept_fds: file descriptor operations supported for node + * (invariant after initialized) + * @min_priority: minimum scheduling priority + * (invariant after initialized) + * @inherit_rt: inherit RT scheduling policy from caller + * (invariant after initialized) + * @async_todo: list of async work items + * (protected by @proc->inner_lock) + * + * Bookkeeping structure for binder nodes. + */ struct binder_node { int debug_id; + spinlock_t lock; struct binder_work work; union { struct rb_node rb_node; @@ -260,88 +378,181 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; + int tmp_refs; binder_uintptr_t ptr; binder_uintptr_t cookie; - unsigned has_strong_ref:1; - unsigned pending_strong_ref:1; - unsigned has_weak_ref:1; - unsigned pending_weak_ref:1; - unsigned has_async_transaction:1; - unsigned accept_fds:1; - unsigned min_priority:8; + struct { + /* + * bitfield elements protected by + * proc inner_lock + */ + u8 has_strong_ref:1; + u8 pending_strong_ref:1; + u8 has_weak_ref:1; + u8 pending_weak_ref:1; + }; + struct { + /* + * invariant after initialization + */ + u8 sched_policy:2; + u8 inherit_rt:1; + u8 accept_fds:1; + u8 min_priority; + }; + bool has_async_transaction; struct list_head async_todo; }; struct binder_ref_death { + /** + * @work: worklist element for death notifications + * (protected by inner_lock of the proc that + * this ref belongs to) + */ struct binder_work work; binder_uintptr_t cookie; }; +/** + * struct binder_ref_data - binder_ref counts and id + * @debug_id: unique ID for the ref + * @desc: unique userspace handle for ref + * @strong: strong ref count (debugging only if not locked) + * @weak: weak ref count (debugging only if not locked) + * + * Structure to hold ref count and ref id information. Since + * the actual ref can only be accessed with a lock, this structure + * is used to return information about the ref to callers of + * ref inc/dec functions. + */ +struct binder_ref_data { + int debug_id; + uint32_t desc; + int strong; + int weak; +}; + +/** + * struct binder_ref - struct to track references on nodes + * @data: binder_ref_data containing id, handle, and current refcounts + * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree + * @rb_node_node: node for lookup by @node in proc's rb_tree + * @node_entry: list entry for node->refs list in target node + * (protected by @node->lock) + * @proc: binder_proc containing ref + * @node: binder_node of target node. When cleaning up a + * ref for deletion in binder_cleanup_ref, a non-NULL + * @node indicates the node must be freed + * @death: pointer to death notification (ref_death) if requested + * (protected by @node->lock) + * + * Structure to track references from procA to target node (on procB). This + * structure is unsafe to access without holding @proc->outer_lock. + */ struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ - int debug_id; + struct binder_ref_data data; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; struct binder_node *node; - uint32_t desc; - int strong; - int weak; struct binder_ref_death *death; }; -struct binder_buffer { - struct list_head entry; /* free and allocated entries by address */ - struct rb_node rb_node; /* free entry by size or allocated entry */ - /* by address */ - unsigned free:1; - unsigned allow_user_free:1; - unsigned async_transaction:1; - unsigned debug_id:29; - - struct binder_transaction *transaction; - - struct binder_node *target_node; - size_t data_size; - size_t offsets_size; - size_t extra_buffers_size; - uint8_t data[0]; +enum binder_deferred_state { + BINDER_DEFERRED_FLUSH = 0x01, + BINDER_DEFERRED_RELEASE = 0x02, }; -enum binder_deferred_state { - BINDER_DEFERRED_PUT_FILES = 0x01, - BINDER_DEFERRED_FLUSH = 0x02, - BINDER_DEFERRED_RELEASE = 0x04, +/** + * struct binder_priority - scheduler policy and priority + * @sched_policy scheduler policy + * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT + * + * The binder driver supports inheriting the following scheduler policies: + * SCHED_NORMAL + * SCHED_BATCH + * SCHED_FIFO + * SCHED_RR + */ +struct binder_priority { + unsigned int sched_policy; + int prio; }; +/** + * struct binder_proc - binder process bookkeeping + * @proc_node: element for binder_procs list + * @threads: rbtree of binder_threads in this proc + * (protected by @inner_lock) + * @nodes: rbtree of binder nodes associated with + * this proc ordered by node->ptr + * (protected by @inner_lock) + * @refs_by_desc: rbtree of refs ordered by ref->desc + * (protected by @outer_lock) + * @refs_by_node: rbtree of refs ordered by ref->node + * (protected by @outer_lock) + * @waiting_threads: threads currently waiting for proc work + * (protected by @inner_lock) + * @pid PID of group_leader of process + * (invariant after initialized) + * @tsk task_struct for group_leader of process + * (invariant after initialized) + * @deferred_work_node: element for binder_deferred_list + * (protected by binder_deferred_lock) + * @deferred_work: bitmap of deferred work to perform + * (protected by binder_deferred_lock) + * @is_dead: process is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @inner_lock) + * @todo: list of work for this process + * (protected by @inner_lock) + * @wait: wait queue head to wait for proc work + * (invariant after initialized) + * @stats: per-process binder statistics + * (atomics, no lock needed) + * @delivered_death: list of delivered death notification + * (protected by @inner_lock) + * @max_threads: cap on number of binder threads + * (protected by @inner_lock) + * @requested_threads: number of binder threads requested but not + * yet started. In current implementation, can + * only be 0 or 1. + * (protected by @inner_lock) + * @requested_threads_started: number binder threads started + * (protected by @inner_lock) + * @tmp_ref: temporary reference to indicate proc is in use + * (protected by @inner_lock) + * @default_priority: default scheduler priority + * (invariant after initialized) + * @debugfs_entry: debugfs node + * @alloc: binder allocator bookkeeping + * @context: binder_context for this proc + * (invariant after initialized) + * @inner_lock: can nest under outer_lock and/or node lock + * @outer_lock: no nesting under innor or node lock + * Lock order: 1) outer, 2) node, 3) inner + * + * Bookkeeping structure for binder processes + */ struct binder_proc { struct hlist_node proc_node; struct rb_root threads; struct rb_root nodes; struct rb_root refs_by_desc; struct rb_root refs_by_node; + struct list_head waiting_threads; int pid; - struct vm_area_struct *vma; - struct mm_struct *vma_vm_mm; struct task_struct *tsk; - struct files_struct *files; struct hlist_node deferred_work_node; int deferred_work; - void *buffer; - ptrdiff_t user_buffer_offset; + bool is_dead; - struct list_head buffers; - struct rb_root free_buffers; - struct rb_root allocated_buffers; - size_t free_async_space; - - struct page **pages; - size_t buffer_size; - uint32_t buffer_free; struct list_head todo; wait_queue_head_t wait; struct binder_stats stats; @@ -349,10 +560,13 @@ struct binder_proc { int max_threads; int requested_threads; int requested_threads_started; - int ready_threads; - long default_priority; + int tmp_ref; + struct binder_priority default_priority; struct dentry *debugfs_entry; + struct binder_alloc alloc; struct binder_context *context; + spinlock_t inner_lock; + spinlock_t outer_lock; }; enum { @@ -361,22 +575,63 @@ enum { BINDER_LOOPER_STATE_EXITED = 0x04, BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, - BINDER_LOOPER_STATE_NEED_RETURN = 0x20 + BINDER_LOOPER_STATE_POLL = 0x20, }; +/** + * struct binder_thread - binder thread bookkeeping + * @proc: binder process for this thread + * (invariant after initialization) + * @rb_node: element for proc->threads rbtree + * (protected by @proc->inner_lock) + * @waiting_thread_node: element for @proc->waiting_threads list + * (protected by @proc->inner_lock) + * @pid: PID for this thread + * (invariant after initialization) + * @looper: bitmap of looping state + * (only accessed by this thread) + * @looper_needs_return: looping thread needs to exit driver + * (no lock needed) + * @transaction_stack: stack of in-progress transactions for this thread + * (protected by @proc->inner_lock) + * @todo: list of work to do for this thread + * (protected by @proc->inner_lock) + * @process_todo: whether work in @todo should be processed + * (protected by @proc->inner_lock) + * @return_error: transaction errors reported by this thread + * (only accessed by this thread) + * @reply_error: transaction errors reported by target thread + * (protected by @proc->inner_lock) + * @wait: wait queue for thread work + * @stats: per-thread statistics + * (atomics, no lock needed) + * @tmp_ref: temporary reference to indicate thread is in use + * (atomic since @proc->inner_lock cannot + * always be acquired) + * @is_dead: thread is dead and awaiting free + * when outstanding transactions are cleaned up + * (protected by @proc->inner_lock) + * @task: struct task_struct for this thread + * + * Bookkeeping structure for binder threads. + */ struct binder_thread { struct binder_proc *proc; struct rb_node rb_node; + struct list_head waiting_thread_node; int pid; - int looper; + int looper; /* only modified by this thread */ + bool looper_need_return; /* can be written by other thread */ struct binder_transaction *transaction_stack; struct list_head todo; - uint32_t return_error; /* Write failed, return error code in read buf */ - uint32_t return_error2; /* Write failed, return error code in read */ - /* buffer. Used when sending a reply to a dead process that */ - /* we are also waiting on */ + bool process_todo; + struct binder_error return_error; + struct binder_error reply_error; wait_queue_head_t wait; struct binder_stats stats; + atomic_t tmp_ref; + bool is_dead; + struct task_struct *task; }; struct binder_transaction { @@ -393,34 +648,329 @@ struct binder_transaction { struct binder_buffer *buffer; unsigned int code; unsigned int flags; - long priority; - long saved_priority; + struct binder_priority priority; + struct binder_priority saved_priority; + bool set_priority_called; kuid_t sender_euid; + /** + * @lock: protects @from, @to_proc, and @to_thread + * + * @from, @to_proc, and @to_thread can be set to NULL + * during thread teardown + */ + spinlock_t lock; }; +/** + * binder_proc_lock() - Acquire outer lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Acquires proc->outer_lock. Used to protect binder_ref + * structures associated with the given proc. + */ +#define binder_proc_lock(proc) _binder_proc_lock(proc, __LINE__) +static void +_binder_proc_lock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&proc->outer_lock); +} + +/** + * binder_proc_unlock() - Release spinlock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Release lock acquired via binder_proc_lock() + */ +#define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__) +static void +_binder_proc_unlock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&proc->outer_lock); +} + +/** + * binder_inner_proc_lock() - Acquire inner lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Acquires proc->inner_lock. Used to protect todo lists + */ +#define binder_inner_proc_lock(proc) _binder_inner_proc_lock(proc, __LINE__) +static void +_binder_inner_proc_lock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&proc->inner_lock); +} + +/** + * binder_inner_proc_unlock() - Release inner lock for given binder_proc + * @proc: struct binder_proc to acquire + * + * Release lock acquired via binder_inner_proc_lock() + */ +#define binder_inner_proc_unlock(proc) _binder_inner_proc_unlock(proc, __LINE__) +static void +_binder_inner_proc_unlock(struct binder_proc *proc, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&proc->inner_lock); +} + +/** + * binder_node_lock() - Acquire spinlock for given binder_node + * @node: struct binder_node to acquire + * + * Acquires node->lock. Used to protect binder_node fields + */ +#define binder_node_lock(node) _binder_node_lock(node, __LINE__) +static void +_binder_node_lock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&node->lock); +} + +/** + * binder_node_unlock() - Release spinlock for given binder_proc + * @node: struct binder_node to acquire + * + * Release lock acquired via binder_node_lock() + */ +#define binder_node_unlock(node) _binder_node_unlock(node, __LINE__) +static void +_binder_node_unlock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_unlock(&node->lock); +} + +/** + * binder_node_inner_lock() - Acquire node and inner locks + * @node: struct binder_node to acquire + * + * Acquires node->lock. If node->proc also acquires + * proc->inner_lock. Used to protect binder_node fields + */ +#define binder_node_inner_lock(node) _binder_node_inner_lock(node, __LINE__) +static void +_binder_node_inner_lock(struct binder_node *node, int line) +{ + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + spin_lock(&node->lock); + if (node->proc) + binder_inner_proc_lock(node->proc); +} + +/** + * binder_node_unlock() - Release node and inner locks + * @node: struct binder_node to acquire + * + * Release lock acquired via binder_node_lock() + */ +#define binder_node_inner_unlock(node) _binder_node_inner_unlock(node, __LINE__) +static void +_binder_node_inner_unlock(struct binder_node *node, int line) +{ + struct binder_proc *proc = node->proc; + + binder_debug(BINDER_DEBUG_SPINLOCKS, + "%s: line=%d\n", __func__, line); + if (proc) + binder_inner_proc_unlock(proc); + spin_unlock(&node->lock); +} + +static bool binder_worklist_empty_ilocked(struct list_head *list) +{ + return list_empty(list); +} + +/** + * binder_worklist_empty() - Check if no items on the work list + * @proc: binder_proc associated with list + * @list: list to check + * + * Return: true if there are no items on list, else false + */ +static bool binder_worklist_empty(struct binder_proc *proc, + struct list_head *list) +{ + bool ret; + + binder_inner_proc_lock(proc); + ret = binder_worklist_empty_ilocked(list); + binder_inner_proc_unlock(proc); + return ret; +} + +/** + * binder_enqueue_work_ilocked() - Add an item to the work list + * @work: struct binder_work to add to list + * @target_list: list to add work to + * + * Adds the work to the specified list. Asserts that work + * is not already on a list. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_work_ilocked(struct binder_work *work, + struct list_head *target_list) +{ + BUG_ON(target_list == NULL); + BUG_ON(work->entry.next && !list_empty(&work->entry)); + list_add_tail(&work->entry, target_list); +} + +/** + * binder_enqueue_deferred_thread_work_ilocked() - Add deferred thread work + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread. Doesn't set the process_todo + * flag, which means that (if it wasn't already set) the thread will go to + * sleep without handling this work when it calls read. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) +{ + binder_enqueue_work_ilocked(work, &thread->todo); +} + +/** + * binder_enqueue_thread_work_ilocked() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) +{ + binder_enqueue_work_ilocked(work, &thread->todo); + thread->process_todo = true; +} + +/** + * binder_enqueue_thread_work() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + */ +static void +binder_enqueue_thread_work(struct binder_thread *thread, + struct binder_work *work) +{ + binder_inner_proc_lock(thread->proc); + binder_enqueue_thread_work_ilocked(thread, work); + binder_inner_proc_unlock(thread->proc); +} + +static void +binder_dequeue_work_ilocked(struct binder_work *work) +{ + list_del_init(&work->entry); +} + +/** + * binder_dequeue_work() - Removes an item from the work list + * @proc: binder_proc associated with list + * @work: struct binder_work to remove from list + * + * Removes the specified work item from whatever list it is on. + * Can safely be called if work is not on any list. + */ +static void +binder_dequeue_work(struct binder_proc *proc, struct binder_work *work) +{ + binder_inner_proc_lock(proc); + binder_dequeue_work_ilocked(work); + binder_inner_proc_unlock(proc); +} + +static struct binder_work *binder_dequeue_work_head_ilocked( + struct list_head *list) +{ + struct binder_work *w; + + w = list_first_entry_or_null(list, struct binder_work, entry); + if (w) + list_del_init(&w->entry); + return w; +} + +/** + * binder_dequeue_work_head() - Dequeues the item at head of list + * @proc: binder_proc associated with list + * @list: list to dequeue head + * + * Removes the head of the list if there are items on the list + * + * Return: pointer dequeued binder_work, NULL if list was empty + */ +static struct binder_work *binder_dequeue_work_head( + struct binder_proc *proc, + struct list_head *list) +{ + struct binder_work *w; + + binder_inner_proc_lock(proc); + w = binder_dequeue_work_head_ilocked(list); + binder_inner_proc_unlock(proc); + return w; +} + static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); +static void binder_free_thread(struct binder_thread *thread); +static void binder_free_proc(struct binder_proc *proc); +static void binder_inc_node_tmpref_ilocked(struct binder_node *node); + +struct files_struct *binder_get_files_struct(struct binder_proc *proc) +{ + return get_files_struct(proc->tsk); +} static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = proc->files; + struct files_struct *files; unsigned long rlim_cur; unsigned long irqs; int ret; + files = binder_get_files_struct(proc); if (files == NULL) return -ESRCH; - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; + } rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - preempt_enable_no_resched(); ret = __alloc_fd(files, 0, rlim_cur, flags); - preempt_disable(); - +err: + put_files_struct(files); return ret; } @@ -430,10 +980,11 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { - if (proc->files) { - preempt_enable_no_resched(); - __fd_install(proc->files, fd, file); - preempt_disable(); + struct files_struct *files = binder_get_files_struct(proc); + + if (files) { + __fd_install(files, fd, file); + put_files_struct(files); } } @@ -442,541 +993,300 @@ static void task_fd_install( */ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { + struct files_struct *files = binder_get_files_struct(proc); int retval; - if (proc->files == NULL) + if (files == NULL) return -ESRCH; - retval = __close_fd(proc->files, fd); + retval = __close_fd(files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || retval == -ERESTARTNOINTR || retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; + put_files_struct(files); return retval; } -static inline void binder_lock(const char *tag) -{ - trace_binder_lock(tag); - mutex_lock(&binder_main_lock); - preempt_disable(); - trace_binder_locked(tag); -} - -static inline void binder_unlock(const char *tag) +static bool binder_has_work_ilocked(struct binder_thread *thread, + bool do_proc_work) { - trace_binder_unlock(tag); - mutex_unlock(&binder_main_lock); - preempt_enable(); + return thread->process_todo || + thread->looper_need_return || + (do_proc_work && + !binder_worklist_empty_ilocked(&thread->proc->todo)); } -static inline void *kzalloc_preempt_disabled(size_t size) +static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) { - void *ptr; + bool has_work; - ptr = kzalloc(size, GFP_NOWAIT); - if (ptr) - return ptr; + binder_inner_proc_lock(thread->proc); + has_work = binder_has_work_ilocked(thread, do_proc_work); + binder_inner_proc_unlock(thread->proc); - preempt_enable_no_resched(); - ptr = kzalloc(size, GFP_KERNEL); - preempt_disable(); + return has_work; +} - return ptr; +static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) +{ + return !thread->transaction_stack && + binder_worklist_empty_ilocked(&thread->todo) && + (thread->looper & (BINDER_LOOPER_STATE_ENTERED | + BINDER_LOOPER_STATE_REGISTERED)); } -static inline long copy_to_user_preempt_disabled(void __user *to, const void *from, long n) +static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, + bool sync) { - long ret; + struct rb_node *n; + struct binder_thread *thread; - preempt_enable_no_resched(); - ret = copy_to_user(to, from, n); - preempt_disable(); - return ret; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + thread = rb_entry(n, struct binder_thread, rb_node); + if (thread->looper & BINDER_LOOPER_STATE_POLL && + binder_available_for_proc_work_ilocked(thread)) { + if (sync) + wake_up_interruptible_sync(&thread->wait); + else + wake_up_interruptible(&thread->wait); + } + } } -static inline long copy_from_user_preempt_disabled(void *to, const void __user *from, long n) +/** + * binder_select_thread_ilocked() - selects a thread for doing proc work. + * @proc: process to select a thread from + * + * Note that calling this function moves the thread off the waiting_threads + * list, so it can only be woken up by the caller of this function, or a + * signal. Therefore, callers *should* always wake up the thread this function + * returns. + * + * Return: If there's a thread currently waiting for process work, + * returns that thread. Otherwise returns NULL. + */ +static struct binder_thread * +binder_select_thread_ilocked(struct binder_proc *proc) { - long ret; + struct binder_thread *thread; - preempt_enable_no_resched(); - ret = copy_from_user(to, from, n); - preempt_disable(); - return ret; -} + assert_spin_locked(&proc->inner_lock); + thread = list_first_entry_or_null(&proc->waiting_threads, + struct binder_thread, + waiting_thread_node); -#define get_user_preempt_disabled(x, ptr) \ -({ \ - int __ret; \ - preempt_enable_no_resched(); \ - __ret = get_user(x, ptr); \ - preempt_disable(); \ - __ret; \ -}) + if (thread) + list_del_init(&thread->waiting_thread_node); -#define put_user_preempt_disabled(x, ptr) \ -({ \ - int __ret; \ - preempt_enable_no_resched(); \ - __ret = put_user(x, ptr); \ - preempt_disable(); \ - __ret; \ -}) + return thread; +} -static void binder_set_nice(long nice) +/** + * binder_wakeup_thread_ilocked() - wakes up a thread for doing proc work. + * @proc: process to wake up a thread in + * @thread: specific thread to wake-up (may be NULL) + * @sync: whether to do a synchronous wake-up + * + * This function wakes up a thread in the @proc process. + * The caller may provide a specific thread to wake-up in + * the @thread parameter. If @thread is NULL, this function + * will wake up threads that have called poll(). + * + * Note that for this function to work as expected, callers + * should first call binder_select_thread() to find a thread + * to handle the work (if they don't have a thread already), + * and pass the result into the @thread parameter. + */ +static void binder_wakeup_thread_ilocked(struct binder_proc *proc, + struct binder_thread *thread, + bool sync) { - long min_nice; + assert_spin_locked(&proc->inner_lock); - if (can_nice(current, nice)) { - set_user_nice(current, nice); + if (thread) { + if (sync) + wake_up_interruptible_sync(&thread->wait); + else + wake_up_interruptible(&thread->wait); return; } - min_nice = rlimit_to_nice(current->signal->rlim[RLIMIT_NICE].rlim_cur); - binder_debug(BINDER_DEBUG_PRIORITY_CAP, - "%d: nice value %ld not allowed use %ld instead\n", - current->pid, nice, min_nice); - set_user_nice(current, min_nice); - if (min_nice <= MAX_NICE) - return; - binder_user_error("%d RLIMIT_NICE not set\n", current->pid); -} -static size_t binder_buffer_size(struct binder_proc *proc, - struct binder_buffer *buffer) -{ - if (list_is_last(&buffer->entry, &proc->buffers)) - return proc->buffer + proc->buffer_size - (void *)buffer->data; - return (size_t)list_entry(buffer->entry.next, - struct binder_buffer, entry) - (size_t)buffer->data; + /* Didn't find a thread waiting for proc work; this can happen + * in two scenarios: + * 1. All threads are busy handling transactions + * In that case, one of those threads should call back into + * the kernel driver soon and pick up this work. + * 2. Threads are using the (e)poll interface, in which case + * they may be blocked on the waitqueue without having been + * added to waiting_threads. For this case, we just iterate + * over all threads not handling transaction work, and + * wake them all up. We wake all because we don't know whether + * a thread that called into (e)poll is handling non-binder + * work currently. + */ + binder_wakeup_poll_threads_ilocked(proc, sync); } -static void binder_insert_free_buffer(struct binder_proc *proc, - struct binder_buffer *new_buffer) +static void binder_wakeup_proc_ilocked(struct binder_proc *proc) { - struct rb_node **p = &proc->free_buffers.rb_node; - struct rb_node *parent = NULL; - struct binder_buffer *buffer; - size_t buffer_size; - size_t new_buffer_size; + struct binder_thread *thread = binder_select_thread_ilocked(proc); - BUG_ON(!new_buffer->free); + binder_wakeup_thread_ilocked(proc, thread, /* sync = */false); +} - new_buffer_size = binder_buffer_size(proc, new_buffer); +static bool is_rt_policy(int policy) +{ + return policy == SCHED_FIFO || policy == SCHED_RR; +} - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: add free buffer, size %zd, at %p\n", - proc->pid, new_buffer_size, new_buffer); +static bool is_fair_policy(int policy) +{ + return policy == SCHED_NORMAL || policy == SCHED_BATCH; +} - while (*p) { - parent = *p; - buffer = rb_entry(parent, struct binder_buffer, rb_node); - BUG_ON(!buffer->free); +static bool binder_supported_policy(int policy) +{ + return is_fair_policy(policy) || is_rt_policy(policy); +} - buffer_size = binder_buffer_size(proc, buffer); +static int to_userspace_prio(int policy, int kernel_priority) +{ + if (is_fair_policy(policy)) + return PRIO_TO_NICE(kernel_priority); + else + return MAX_USER_RT_PRIO - 1 - kernel_priority; +} - if (new_buffer_size < buffer_size) - p = &parent->rb_left; - else - p = &parent->rb_right; - } - rb_link_node(&new_buffer->rb_node, parent, p); - rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); +static int to_kernel_prio(int policy, int user_priority) +{ + if (is_fair_policy(policy)) + return NICE_TO_PRIO(user_priority); + else + return MAX_USER_RT_PRIO - 1 - user_priority; } -static void binder_insert_allocated_buffer(struct binder_proc *proc, - struct binder_buffer *new_buffer) +static void binder_do_set_priority(struct task_struct *task, + struct binder_priority desired, + bool verify) { - struct rb_node **p = &proc->allocated_buffers.rb_node; - struct rb_node *parent = NULL; - struct binder_buffer *buffer; + int priority; /* user-space prio value */ + bool has_cap_nice; + unsigned int policy = desired.sched_policy; - BUG_ON(new_buffer->free); - - while (*p) { - parent = *p; - buffer = rb_entry(parent, struct binder_buffer, rb_node); - BUG_ON(buffer->free); - - if (new_buffer < buffer) - p = &parent->rb_left; - else if (new_buffer > buffer) - p = &parent->rb_right; - else - BUG(); - } - rb_link_node(&new_buffer->rb_node, parent, p); - rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); -} - -static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - uintptr_t user_ptr) -{ - struct rb_node *n = proc->allocated_buffers.rb_node; - struct binder_buffer *buffer; - struct binder_buffer *kern_ptr; - - kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset - - offsetof(struct binder_buffer, data)); - - while (n) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - BUG_ON(buffer->free); - - if (kern_ptr < buffer) - n = n->rb_left; - else if (kern_ptr > buffer) - n = n->rb_right; - else - return buffer; - } - return NULL; -} - -static int binder_update_page_range(struct binder_proc *proc, int allocate, - void *start, void *end, - struct vm_area_struct *vma) -{ - void *page_addr; - unsigned long user_page_addr; - struct page **page; - struct mm_struct *mm; - - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: %s pages %p-%p\n", proc->pid, - allocate ? "allocate" : "free", start, end); - - if (end <= start) - return 0; + if (task->policy == policy && task->normal_prio == desired.prio) + return; - trace_binder_update_page_range(proc, allocate, start, end); + has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE); - if (vma) - mm = NULL; - else - mm = get_task_mm(proc->tsk); + priority = to_userspace_prio(policy, desired.prio); - preempt_enable_no_resched(); + if (verify && is_rt_policy(policy) && !has_cap_nice) { + long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO); - if (mm) { - down_write(&mm->mmap_sem); - vma = proc->vma; - if (vma && mm != proc->vma_vm_mm) { - pr_err("%d: vma mm and task mm mismatch\n", - proc->pid); - vma = NULL; + if (max_rtprio == 0) { + policy = SCHED_NORMAL; + priority = MIN_NICE; + } else if (priority > max_rtprio) { + priority = max_rtprio; } } - if (allocate == 0) - goto free_range; - - if (vma == NULL) { - pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", - proc->pid); - goto err_no_vma; - } + if (verify && is_fair_policy(policy) && !has_cap_nice) { + long min_nice = rlimit_to_nice(task_rlimit(task, RLIMIT_NICE)); - for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { - int ret; - - page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; - - BUG_ON(*page); - *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); - if (*page == NULL) { - pr_err("%d: binder_alloc_buf failed for page at %p\n", - proc->pid, page_addr); - goto err_alloc_page_failed; - } - ret = map_kernel_range_noflush((unsigned long)page_addr, - PAGE_SIZE, PAGE_KERNEL, page); - flush_cache_vmap((unsigned long)page_addr, - (unsigned long)page_addr + PAGE_SIZE); - if (ret != 1) { - pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n", - proc->pid, page_addr); - goto err_map_kernel_failed; - } - user_page_addr = - (uintptr_t)page_addr + proc->user_buffer_offset; - ret = vm_insert_page(vma, user_page_addr, page[0]); - if (ret) { - pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", - proc->pid, user_page_addr); - goto err_vm_insert_page_failed; + if (min_nice > MAX_NICE) { + binder_user_error("%d RLIMIT_NICE not set\n", + task->pid); + return; + } else if (priority < min_nice) { + priority = min_nice; } - /* vm_insert_page does not seem to increment the refcount */ - } - if (mm) { - up_write(&mm->mmap_sem); - mmput(mm); - } - - preempt_disable(); - - return 0; - -free_range: - for (page_addr = end - PAGE_SIZE; page_addr >= start; - page_addr -= PAGE_SIZE) { - page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; - if (vma) - zap_page_range(vma, (uintptr_t)page_addr + - proc->user_buffer_offset, PAGE_SIZE, NULL); -err_vm_insert_page_failed: - unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); -err_map_kernel_failed: - __free_page(*page); - *page = NULL; -err_alloc_page_failed: - ; - } -err_no_vma: - if (mm) { - up_write(&mm->mmap_sem); - mmput(mm); - } - - preempt_disable(); - - return -ENOMEM; -} - -static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) -{ - struct rb_node *n = proc->free_buffers.rb_node; - struct binder_buffer *buffer; - size_t buffer_size; - struct rb_node *best_fit = NULL; - void *has_page_addr; - void *end_page_addr; - size_t size, data_offsets_size; - - if (proc->vma == NULL) { - pr_err("%d: binder_alloc_buf, no vma\n", - proc->pid); - return NULL; } - data_offsets_size = ALIGN(data_size, sizeof(void *)) + - ALIGN(offsets_size, sizeof(void *)); + if (policy != desired.sched_policy || + to_kernel_prio(policy, priority) != desired.prio) + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: priority %d not allowed, using %d instead\n", + task->pid, desired.prio, + to_kernel_prio(policy, priority)); - if (data_offsets_size < data_size || data_offsets_size < offsets_size) { - binder_user_error("%d: got transaction with invalid size %zd-%zd\n", - proc->pid, data_size, offsets_size); - return NULL; - } - size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); - if (size < data_offsets_size || size < extra_buffers_size) { - binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n", - proc->pid, extra_buffers_size); - return NULL; - } - if (is_async && - proc->free_async_space < size + sizeof(struct binder_buffer)) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd failed, no async space left\n", - proc->pid, size); - return NULL; - } + trace_binder_set_priority(task->tgid, task->pid, task->normal_prio, + to_kernel_prio(policy, priority), + desired.prio); - while (n) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - BUG_ON(!buffer->free); - buffer_size = binder_buffer_size(proc, buffer); + /* Set the actual priority */ + if (task->policy != policy || is_rt_policy(policy)) { + struct sched_param params; - if (size < buffer_size) { - best_fit = n; - n = n->rb_left; - } else if (size > buffer_size) - n = n->rb_right; - else { - best_fit = n; - break; - } - } - if (best_fit == NULL) { - pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", - proc->pid, size); - return NULL; - } - if (n == NULL) { - buffer = rb_entry(best_fit, struct binder_buffer, rb_node); - buffer_size = binder_buffer_size(proc, buffer); - } - - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got buffer %p size %zd\n", - proc->pid, size, buffer, buffer_size); - - has_page_addr = - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); - if (n == NULL) { - if (size + sizeof(struct binder_buffer) + 4 >= buffer_size) - buffer_size = size; /* no room for other buffers */ - else - buffer_size = size + sizeof(struct binder_buffer); - } - end_page_addr = - (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size); - if (end_page_addr > has_page_addr) - end_page_addr = has_page_addr; - if (binder_update_page_range(proc, 1, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) - return NULL; + params.sched_priority = is_rt_policy(policy) ? priority : 0; - rb_erase(best_fit, &proc->free_buffers); - buffer->free = 0; - binder_insert_allocated_buffer(proc, buffer); - if (buffer_size != size) { - struct binder_buffer *new_buffer = (void *)buffer->data + size; - - list_add(&new_buffer->entry, &buffer->entry); - new_buffer->free = 1; - binder_insert_free_buffer(proc, new_buffer); - } - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got %p\n", - proc->pid, size, buffer); - buffer->data_size = data_size; - buffer->offsets_size = offsets_size; - buffer->extra_buffers_size = extra_buffers_size; - buffer->async_transaction = is_async; - if (is_async) { - proc->free_async_space -= size + sizeof(struct binder_buffer); - binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, - "%d: binder_alloc_buf size %zd async free %zd\n", - proc->pid, size, proc->free_async_space); + sched_setscheduler_nocheck(task, + policy | SCHED_RESET_ON_FORK, + ¶ms); } - - return buffer; + if (is_fair_policy(policy)) + set_user_nice(task, priority); } -static void *buffer_start_page(struct binder_buffer *buffer) +static void binder_set_priority(struct task_struct *task, + struct binder_priority desired) { - return (void *)((uintptr_t)buffer & PAGE_MASK); + binder_do_set_priority(task, desired, /* verify = */ true); } -static void *buffer_end_page(struct binder_buffer *buffer) +static void binder_restore_priority(struct task_struct *task, + struct binder_priority desired) { - return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); + binder_do_set_priority(task, desired, /* verify = */ false); } -static void binder_delete_free_buffer(struct binder_proc *proc, - struct binder_buffer *buffer) +static void binder_transaction_priority(struct task_struct *task, + struct binder_transaction *t, + struct binder_priority node_prio, + bool inherit_rt) { - struct binder_buffer *prev, *next = NULL; - int free_page_end = 1; - int free_page_start = 1; - - BUG_ON(proc->buffers.next == &buffer->entry); - prev = list_entry(buffer->entry.prev, struct binder_buffer, entry); - BUG_ON(!prev->free); - if (buffer_end_page(prev) == buffer_start_page(buffer)) { - free_page_start = 0; - if (buffer_end_page(prev) == buffer_end_page(buffer)) - free_page_end = 0; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %p share page with %p\n", - proc->pid, buffer, prev); - } - - if (!list_is_last(&buffer->entry, &proc->buffers)) { - next = list_entry(buffer->entry.next, - struct binder_buffer, entry); - if (buffer_start_page(next) == buffer_end_page(buffer)) { - free_page_end = 0; - if (buffer_start_page(next) == - buffer_start_page(buffer)) - free_page_start = 0; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %p share page with %p\n", - proc->pid, buffer, prev); - } - } - list_del(&buffer->entry); - if (free_page_start || free_page_end) { - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %p do not share page%s%s with %p or %p\n", - proc->pid, buffer, free_page_start ? "" : " end", - free_page_end ? "" : " start", prev, next); - binder_update_page_range(proc, 0, free_page_start ? - buffer_start_page(buffer) : buffer_end_page(buffer), - (free_page_end ? buffer_end_page(buffer) : - buffer_start_page(buffer)) + PAGE_SIZE, NULL); - } -} - -static void binder_free_buf(struct binder_proc *proc, - struct binder_buffer *buffer) -{ - size_t size, buffer_size; - - buffer_size = binder_buffer_size(proc, buffer); - - size = ALIGN(buffer->data_size, sizeof(void *)) + - ALIGN(buffer->offsets_size, sizeof(void *)) + - ALIGN(buffer->extra_buffers_size, sizeof(void *)); + struct binder_priority desired_prio = t->priority; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_free_buf %p size %zd buffer_size %zd\n", - proc->pid, buffer, size, buffer_size); - - BUG_ON(buffer->free); - BUG_ON(size > buffer_size); - BUG_ON(buffer->transaction != NULL); - BUG_ON((void *)buffer < proc->buffer); - BUG_ON((void *)buffer > proc->buffer + proc->buffer_size); + if (t->set_priority_called) + return; - if (buffer->async_transaction) { - proc->free_async_space += size + sizeof(struct binder_buffer); + t->set_priority_called = true; + t->saved_priority.sched_policy = task->policy; + t->saved_priority.prio = task->normal_prio; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, - "%d: binder_free_buf size %zd async free %zd\n", - proc->pid, size, proc->free_async_space); + if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) { + desired_prio.prio = NICE_TO_PRIO(0); + desired_prio.sched_policy = SCHED_NORMAL; } - binder_update_page_range(proc, 0, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), - NULL); - rb_erase(&buffer->rb_node, &proc->allocated_buffers); - buffer->free = 1; - if (!list_is_last(&buffer->entry, &proc->buffers)) { - struct binder_buffer *next = list_entry(buffer->entry.next, - struct binder_buffer, entry); - - if (next->free) { - rb_erase(&next->rb_node, &proc->free_buffers); - binder_delete_free_buffer(proc, next); - } + if (node_prio.prio < t->priority.prio || + (node_prio.prio == t->priority.prio && + node_prio.sched_policy == SCHED_FIFO)) { + /* + * In case the minimum priority on the node is + * higher (lower value), use that priority. If + * the priority is the same, but the node uses + * SCHED_FIFO, prefer SCHED_FIFO, since it can + * run unbounded, unlike SCHED_RR. + */ + desired_prio = node_prio; } - if (proc->buffers.next != &buffer->entry) { - struct binder_buffer *prev = list_entry(buffer->entry.prev, - struct binder_buffer, entry); - if (prev->free) { - binder_delete_free_buffer(proc, buffer); - rb_erase(&prev->rb_node, &proc->free_buffers); - buffer = prev; - } - } - binder_insert_free_buffer(proc, buffer); + binder_set_priority(task, desired_prio); } -static struct binder_node *binder_get_node(struct binder_proc *proc, - binder_uintptr_t ptr) +static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc, + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; + assert_spin_locked(&proc->inner_lock); + while (n) { node = rb_entry(n, struct binder_node, rb_node); @@ -984,21 +1294,47 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, n = n->rb_left; else if (ptr > node->ptr) n = n->rb_right; - else + else { + /* + * take an implicit weak reference + * to ensure node stays alive until + * call to binder_put_node() + */ + binder_inc_node_tmpref_ilocked(node); return node; + } } return NULL; } -static struct binder_node *binder_new_node(struct binder_proc *proc, - binder_uintptr_t ptr, - binder_uintptr_t cookie) +static struct binder_node *binder_get_node(struct binder_proc *proc, + binder_uintptr_t ptr) +{ + struct binder_node *node; + + binder_inner_proc_lock(proc); + node = binder_get_node_ilocked(proc, ptr); + binder_inner_proc_unlock(proc); + return node; +} + +static struct binder_node *binder_init_node_ilocked( + struct binder_proc *proc, + struct binder_node *new_node, + struct flat_binder_object *fp) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; struct binder_node *node; + binder_uintptr_t ptr = fp ? fp->binder : 0; + binder_uintptr_t cookie = fp ? fp->cookie : 0; + __u32 flags = fp ? fp->flags : 0; + s8 priority; + + assert_spin_locked(&proc->inner_lock); while (*p) { + parent = *p; node = rb_entry(parent, struct binder_node, rb_node); @@ -1006,33 +1342,78 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, p = &(*p)->rb_left; else if (ptr > node->ptr) p = &(*p)->rb_right; - else - return NULL; + else { + /* + * A matching node is already in + * the rb tree. Abandon the init + * and return it. + */ + binder_inc_node_tmpref_ilocked(node); + return node; + } } - - node = kzalloc_preempt_disabled(sizeof(*node)); - if (node == NULL) - return NULL; + node = new_node; binder_stats_created(BINDER_STAT_NODE); + node->tmp_refs++; rb_link_node(&node->rb_node, parent, p); rb_insert_color(&node->rb_node, &proc->nodes); - node->debug_id = ++binder_last_id; + node->debug_id = atomic_inc_return(&binder_last_id); node->proc = proc; node->ptr = ptr; node->cookie = cookie; node->work.type = BINDER_WORK_NODE; + priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; + node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >> + FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT; + node->min_priority = to_kernel_prio(node->sched_policy, priority); + node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); + node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); + spin_lock_init(&node->lock); INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, (u64)node->ptr, (u64)node->cookie); + return node; } -static int binder_inc_node(struct binder_node *node, int strong, int internal, - struct list_head *target_list) +static struct binder_node *binder_new_node(struct binder_proc *proc, + struct flat_binder_object *fp) { + struct binder_node *node; + struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL); + + if (!new_node) + return NULL; + binder_inner_proc_lock(proc); + node = binder_init_node_ilocked(proc, new_node, fp); + binder_inner_proc_unlock(proc); + if (node != new_node) + /* + * The node was already added by another thread + */ + kfree(new_node); + + return node; +} + +static void binder_free_node(struct binder_node *node) +{ + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); +} + +static int binder_inc_node_nilocked(struct binder_node *node, int strong, + int internal, + struct list_head *target_list) +{ + struct binder_proc *proc = node->proc; + + assert_spin_locked(&node->lock); + if (proc) + assert_spin_locked(&proc->inner_lock); if (strong) { if (internal) { if (target_list == NULL && @@ -1049,8 +1430,19 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, } else node->local_strong_refs++; if (!node->has_strong_ref && target_list) { - list_del_init(&node->work.entry); - list_add_tail(&node->work.entry, target_list); + binder_dequeue_work_ilocked(&node->work); + /* + * Note: this function is the only place where we queue + * directly to a thread->todo without using the + * corresponding binder_enqueue_thread_work() helper + * functions; in this case it's ok to not set the + * process_todo flag, since we know this node work will + * always be followed by other work that starts queue + * processing: in case of synchronous transactions, a + * BR_REPLY or BR_ERROR; in case of oneway + * transactions, a BR_TRANSACTION_COMPLETE. + */ + binder_enqueue_work_ilocked(&node->work, target_list); } } else { if (!internal) @@ -1061,58 +1453,172 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->debug_id); return -EINVAL; } - list_add_tail(&node->work.entry, target_list); + /* + * See comment above + */ + binder_enqueue_work_ilocked(&node->work, target_list); } } return 0; } -static int binder_dec_node(struct binder_node *node, int strong, int internal) +static int binder_inc_node(struct binder_node *node, int strong, int internal, + struct list_head *target_list) +{ + int ret; + + binder_node_inner_lock(node); + ret = binder_inc_node_nilocked(node, strong, internal, target_list); + binder_node_inner_unlock(node); + + return ret; +} + +static bool binder_dec_node_nilocked(struct binder_node *node, + int strong, int internal) { + struct binder_proc *proc = node->proc; + + assert_spin_locked(&node->lock); + if (proc) + assert_spin_locked(&proc->inner_lock); if (strong) { if (internal) node->internal_strong_refs--; else node->local_strong_refs--; if (node->local_strong_refs || node->internal_strong_refs) - return 0; + return false; } else { if (!internal) node->local_weak_refs--; - if (node->local_weak_refs || !hlist_empty(&node->refs)) - return 0; + if (node->local_weak_refs || node->tmp_refs || + !hlist_empty(&node->refs)) + return false; } - if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { + + if (proc && (node->has_strong_ref || node->has_weak_ref)) { if (list_empty(&node->work.entry)) { - list_add_tail(&node->work.entry, &node->proc->todo); - wake_up_interruptible(&node->proc->wait); + binder_enqueue_work_ilocked(&node->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); } } else { if (hlist_empty(&node->refs) && !node->local_strong_refs && - !node->local_weak_refs) { - list_del_init(&node->work.entry); - if (node->proc) { - rb_erase(&node->rb_node, &node->proc->nodes); + !node->local_weak_refs && !node->tmp_refs) { + if (proc) { + binder_dequeue_work_ilocked(&node->work); + rb_erase(&node->rb_node, &proc->nodes); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "refless node %d deleted\n", node->debug_id); } else { + BUG_ON(!list_empty(&node->work.entry)); + spin_lock(&binder_dead_nodes_lock); + /* + * tmp_refs could have changed so + * check it again + */ + if (node->tmp_refs) { + spin_unlock(&binder_dead_nodes_lock); + return false; + } hlist_del(&node->dead_node); + spin_unlock(&binder_dead_nodes_lock); binder_debug(BINDER_DEBUG_INTERNAL_REFS, "dead node %d deleted\n", node->debug_id); } - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); + return true; } } + return false; +} - return 0; +static void binder_dec_node(struct binder_node *node, int strong, int internal) +{ + bool free_node; + + binder_node_inner_lock(node); + free_node = binder_dec_node_nilocked(node, strong, internal); + binder_node_inner_unlock(node); + if (free_node) + binder_free_node(node); } +static void binder_inc_node_tmpref_ilocked(struct binder_node *node) +{ + /* + * No call to binder_inc_node() is needed since we + * don't need to inform userspace of any changes to + * tmp_refs + */ + node->tmp_refs++; +} + +/** + * binder_inc_node_tmpref() - take a temporary reference on node + * @node: node to reference + * + * Take reference on node to prevent the node from being freed + * while referenced only by a local variable. The inner lock is + * needed to serialize with the node work on the queue (which + * isn't needed after the node is dead). If the node is dead + * (node->proc is NULL), use binder_dead_nodes_lock to protect + * node->tmp_refs against dead-node-only cases where the node + * lock cannot be acquired (eg traversing the dead node list to + * print nodes) + */ +static void binder_inc_node_tmpref(struct binder_node *node) +{ + binder_node_lock(node); + if (node->proc) + binder_inner_proc_lock(node->proc); + else + spin_lock(&binder_dead_nodes_lock); + binder_inc_node_tmpref_ilocked(node); + if (node->proc) + binder_inner_proc_unlock(node->proc); + else + spin_unlock(&binder_dead_nodes_lock); + binder_node_unlock(node); +} + +/** + * binder_dec_node_tmpref() - remove a temporary reference on node + * @node: node to reference + * + * Release temporary reference on node taken via binder_inc_node_tmpref() + */ +static void binder_dec_node_tmpref(struct binder_node *node) +{ + bool free_node; + + binder_node_inner_lock(node); + if (!node->proc) + spin_lock(&binder_dead_nodes_lock); + node->tmp_refs--; + BUG_ON(node->tmp_refs < 0); + if (!node->proc) + spin_unlock(&binder_dead_nodes_lock); + /* + * Call binder_dec_node() to check if all refcounts are 0 + * and cleanup is needed. Calling with strong=0 and internal=1 + * causes no actual reference to be released in binder_dec_node(). + * If that changes, a change is needed here too. + */ + free_node = binder_dec_node_nilocked(node, 0, 1); + binder_node_inner_unlock(node); + if (free_node) + binder_free_node(node); +} -static struct binder_ref *binder_get_ref(struct binder_proc *proc, - u32 desc, bool need_strong_ref) +static void binder_put_node(struct binder_node *node) +{ + binder_dec_node_tmpref(node); +} + +static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, + u32 desc, bool need_strong_ref) { struct rb_node *n = proc->refs_by_desc.rb_node; struct binder_ref *ref; @@ -1120,11 +1626,11 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, while (n) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (desc < ref->desc) { + if (desc < ref->data.desc) { n = n->rb_left; - } else if (desc > ref->desc) { + } else if (desc > ref->data.desc) { n = n->rb_right; - } else if (need_strong_ref && !ref->strong) { + } else if (need_strong_ref && !ref->data.strong) { binder_user_error("tried to use weak ref as strong ref\n"); return NULL; } else { @@ -1134,14 +1640,34 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, return NULL; } -static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, - struct binder_node *node) +/** + * binder_get_ref_for_node_olocked() - get the ref associated with given node + * @proc: binder_proc that owns the ref + * @node: binder_node of target + * @new_ref: newly allocated binder_ref to be initialized or %NULL + * + * Look up the ref for the given node and return it if it exists + * + * If it doesn't exist and the caller provides a newly allocated + * ref, initialize the fields of the newly allocated ref and insert + * into the given proc rb_trees and node refs list. + * + * Return: the ref for node. It is possible that another thread + * allocated/initialized the ref first in which case the + * returned ref would be different than the passed-in + * new_ref. new_ref must be kfree'd by the caller in + * this case. + */ +static struct binder_ref *binder_get_ref_for_node_olocked( + struct binder_proc *proc, + struct binder_node *node, + struct binder_ref *new_ref) { - struct rb_node *n; + struct binder_context *context = proc->context; struct rb_node **p = &proc->refs_by_node.rb_node; struct rb_node *parent = NULL; - struct binder_ref *ref, *new_ref; - struct binder_context *context = proc->context; + struct binder_ref *ref; + struct rb_node *n; while (*p) { parent = *p; @@ -1154,22 +1680,22 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, else return ref; } - new_ref = kzalloc_preempt_disabled(sizeof(*ref)); - if (new_ref == NULL) + if (!new_ref) return NULL; + binder_stats_created(BINDER_STAT_REF); - new_ref->debug_id = ++binder_last_id; + new_ref->data.debug_id = atomic_inc_return(&binder_last_id); new_ref->proc = proc; new_ref->node = node; rb_link_node(&new_ref->rb_node_node, parent, p); rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); - new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1; + new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { ref = rb_entry(n, struct binder_ref, rb_node_desc); - if (ref->desc > new_ref->desc) + if (ref->data.desc > new_ref->data.desc) break; - new_ref->desc = ref->desc + 1; + new_ref->data.desc = ref->data.desc + 1; } p = &proc->refs_by_desc.rb_node; @@ -1177,121 +1703,423 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_desc); - if (new_ref->desc < ref->desc) + if (new_ref->data.desc < ref->data.desc) p = &(*p)->rb_left; - else if (new_ref->desc > ref->desc) + else if (new_ref->data.desc > ref->data.desc) p = &(*p)->rb_right; else BUG(); } rb_link_node(&new_ref->rb_node_desc, parent, p); rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); - if (node) { - hlist_add_head(&new_ref->node_entry, &node->refs); - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for node %d\n", - proc->pid, new_ref->debug_id, new_ref->desc, - node->debug_id); - } else { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d new ref %d desc %d for dead node\n", - proc->pid, new_ref->debug_id, new_ref->desc); + binder_node_lock(node); + hlist_add_head(&new_ref->node_entry, &node->refs); + + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d new ref %d desc %d for node %d\n", + proc->pid, new_ref->data.debug_id, new_ref->data.desc, + node->debug_id); + binder_node_unlock(node); + return new_ref; +} + +static void binder_cleanup_ref_olocked(struct binder_ref *ref) +{ + bool delete_node = false; + + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d delete ref %d desc %d for node %d\n", + ref->proc->pid, ref->data.debug_id, ref->data.desc, + ref->node->debug_id); + + rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); + rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); + + binder_node_inner_lock(ref->node); + if (ref->data.strong) + binder_dec_node_nilocked(ref->node, 1, 1); + + hlist_del(&ref->node_entry); + delete_node = binder_dec_node_nilocked(ref->node, 0, 1); + binder_node_inner_unlock(ref->node); + /* + * Clear ref->node unless we want the caller to free the node + */ + if (!delete_node) { + /* + * The caller uses ref->node to determine + * whether the node needs to be freed. Clear + * it since the node is still alive. + */ + ref->node = NULL; + } + + if (ref->death) { + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "%d delete ref %d desc %d has death notification\n", + ref->proc->pid, ref->data.debug_id, + ref->data.desc); + binder_dequeue_work(ref->proc, &ref->death->work); + binder_stats_deleted(BINDER_STAT_DEATH); + } + binder_stats_deleted(BINDER_STAT_REF); +} + +/** + * binder_inc_ref_olocked() - increment the ref for given handle + * @ref: ref to be incremented + * @strong: if true, strong increment, else weak + * @target_list: list to queue node work on + * + * Increment the ref. @ref->proc->outer_lock must be held on entry + * + * Return: 0, if successful, else errno + */ +static int binder_inc_ref_olocked(struct binder_ref *ref, int strong, + struct list_head *target_list) +{ + int ret; + + if (strong) { + if (ref->data.strong == 0) { + ret = binder_inc_node(ref->node, 1, 1, target_list); + if (ret) + return ret; + } + ref->data.strong++; + } else { + if (ref->data.weak == 0) { + ret = binder_inc_node(ref->node, 0, 1, target_list); + if (ret) + return ret; + } + ref->data.weak++; + } + return 0; +} + +/** + * binder_dec_ref() - dec the ref for given handle + * @ref: ref to be decremented + * @strong: if true, strong decrement, else weak + * + * Decrement the ref. + * + * Return: true if ref is cleaned up and ready to be freed + */ +static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong) +{ + if (strong) { + if (ref->data.strong == 0) { + binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", + ref->proc->pid, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak); + return false; + } + ref->data.strong--; + if (ref->data.strong == 0) + binder_dec_node(ref->node, strong, 1); + } else { + if (ref->data.weak == 0) { + binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", + ref->proc->pid, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak); + return false; + } + ref->data.weak--; + } + if (ref->data.strong == 0 && ref->data.weak == 0) { + binder_cleanup_ref_olocked(ref); + return true; + } + return false; +} + +/** + * binder_get_node_from_ref() - get the node from the given proc/desc + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @need_strong_ref: if true, only return node if ref is strong + * @rdata: the id/refcount data for the ref + * + * Given a proc and ref handle, return the associated binder_node + * + * Return: a binder_node or NULL if not found or not strong when strong required + */ +static struct binder_node *binder_get_node_from_ref( + struct binder_proc *proc, + u32 desc, bool need_strong_ref, + struct binder_ref_data *rdata) +{ + struct binder_node *node; + struct binder_ref *ref; + + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, desc, need_strong_ref); + if (!ref) + goto err_no_ref; + node = ref->node; + /* + * Take an implicit reference on the node to ensure + * it stays alive until the call to binder_put_node() + */ + binder_inc_node_tmpref(node); + if (rdata) + *rdata = ref->data; + binder_proc_unlock(proc); + + return node; + +err_no_ref: + binder_proc_unlock(proc); + return NULL; +} + +/** + * binder_free_ref() - free the binder_ref + * @ref: ref to free + * + * Free the binder_ref. Free the binder_node indicated by ref->node + * (if non-NULL) and the binder_ref_death indicated by ref->death. + */ +static void binder_free_ref(struct binder_ref *ref) +{ + if (ref->node) + binder_free_node(ref->node); + kfree(ref->death); + kfree(ref); +} + +/** + * binder_update_ref_for_handle() - inc/dec the ref for given handle + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @increment: true=inc reference, false=dec reference + * @strong: true=strong reference, false=weak reference + * @rdata: the id/refcount data for the ref + * + * Given a proc and ref handle, increment or decrement the ref + * according to "increment" arg. + * + * Return: 0 if successful, else errno + */ +static int binder_update_ref_for_handle(struct binder_proc *proc, + uint32_t desc, bool increment, bool strong, + struct binder_ref_data *rdata) +{ + int ret = 0; + struct binder_ref *ref; + bool delete_ref = false; + + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, desc, strong); + if (!ref) { + ret = -EINVAL; + goto err_no_ref; + } + if (increment) + ret = binder_inc_ref_olocked(ref, strong, NULL); + else + delete_ref = binder_dec_ref_olocked(ref, strong); + + if (rdata) + *rdata = ref->data; + binder_proc_unlock(proc); + + if (delete_ref) + binder_free_ref(ref); + return ret; + +err_no_ref: + binder_proc_unlock(proc); + return ret; +} + +/** + * binder_dec_ref_for_handle() - dec the ref for given handle + * @proc: proc containing the ref + * @desc: the handle associated with the ref + * @strong: true=strong reference, false=weak reference + * @rdata: the id/refcount data for the ref + * + * Just calls binder_update_ref_for_handle() to decrement the ref. + * + * Return: 0 if successful, else errno + */ +static int binder_dec_ref_for_handle(struct binder_proc *proc, + uint32_t desc, bool strong, struct binder_ref_data *rdata) +{ + return binder_update_ref_for_handle(proc, desc, false, strong, rdata); +} + + +/** + * binder_inc_ref_for_node() - increment the ref for given proc/node + * @proc: proc containing the ref + * @node: target node + * @strong: true=strong reference, false=weak reference + * @target_list: worklist to use if node is incremented + * @rdata: the id/refcount data for the ref + * + * Given a proc and node, increment the ref. Create the ref if it + * doesn't already exist + * + * Return: 0 if successful, else errno + */ +static int binder_inc_ref_for_node(struct binder_proc *proc, + struct binder_node *node, + bool strong, + struct list_head *target_list, + struct binder_ref_data *rdata) +{ + struct binder_ref *ref; + struct binder_ref *new_ref = NULL; + int ret = 0; + + binder_proc_lock(proc); + ref = binder_get_ref_for_node_olocked(proc, node, NULL); + if (!ref) { + binder_proc_unlock(proc); + new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!new_ref) + return -ENOMEM; + binder_proc_lock(proc); + ref = binder_get_ref_for_node_olocked(proc, node, new_ref); } - return new_ref; + ret = binder_inc_ref_olocked(ref, strong, target_list); + *rdata = ref->data; + binder_proc_unlock(proc); + if (new_ref && ref != new_ref) + /* + * Another thread created the ref first so + * free the one we allocated + */ + kfree(new_ref); + return ret; } -static void binder_delete_ref(struct binder_ref *ref) +static void binder_pop_transaction_ilocked(struct binder_thread *target_thread, + struct binder_transaction *t) { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d delete ref %d desc %d for node %d\n", - ref->proc->pid, ref->debug_id, ref->desc, - ref->node->debug_id); + BUG_ON(!target_thread); + assert_spin_locked(&target_thread->proc->inner_lock); + BUG_ON(target_thread->transaction_stack != t); + BUG_ON(target_thread->transaction_stack->from != target_thread); + target_thread->transaction_stack = + target_thread->transaction_stack->from_parent; + t->from = NULL; +} - rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); - rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); - if (ref->strong) - binder_dec_node(ref->node, 1, 1); - hlist_del(&ref->node_entry); - binder_dec_node(ref->node, 0, 1); - if (ref->death) { - binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d delete ref %d desc %d has death notification\n", - ref->proc->pid, ref->debug_id, ref->desc); - list_del(&ref->death->work.entry); - kfree(ref->death); - binder_stats_deleted(BINDER_STAT_DEATH); +/** + * binder_thread_dec_tmpref() - decrement thread->tmp_ref + * @thread: thread to decrement + * + * A thread needs to be kept alive while being used to create or + * handle a transaction. binder_get_txn_from() is used to safely + * extract t->from from a binder_transaction and keep the thread + * indicated by t->from from being freed. When done with that + * binder_thread, this function is called to decrement the + * tmp_ref and free if appropriate (thread has been released + * and no transaction being processed by the driver) + */ +static void binder_thread_dec_tmpref(struct binder_thread *thread) +{ + /* + * atomic is used to protect the counter value while + * it cannot reach zero or thread->is_dead is false + */ + binder_inner_proc_lock(thread->proc); + atomic_dec(&thread->tmp_ref); + if (thread->is_dead && !atomic_read(&thread->tmp_ref)) { + binder_inner_proc_unlock(thread->proc); + binder_free_thread(thread); + return; } - kfree(ref); - binder_stats_deleted(BINDER_STAT_REF); + binder_inner_proc_unlock(thread->proc); } -static int binder_inc_ref(struct binder_ref *ref, int strong, - struct list_head *target_list) +/** + * binder_proc_dec_tmpref() - decrement proc->tmp_ref + * @proc: proc to decrement + * + * A binder_proc needs to be kept alive while being used to create or + * handle a transaction. proc->tmp_ref is incremented when + * creating a new transaction or the binder_proc is currently in-use + * by threads that are being released. When done with the binder_proc, + * this function is called to decrement the counter and free the + * proc if appropriate (proc has been released, all threads have + * been released and not currenly in-use to process a transaction). + */ +static void binder_proc_dec_tmpref(struct binder_proc *proc) { - int ret; - - if (strong) { - if (ref->strong == 0) { - ret = binder_inc_node(ref->node, 1, 1, target_list); - if (ret) - return ret; - } - ref->strong++; - } else { - if (ref->weak == 0) { - ret = binder_inc_node(ref->node, 0, 1, target_list); - if (ret) - return ret; - } - ref->weak++; + binder_inner_proc_lock(proc); + proc->tmp_ref--; + if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) && + !proc->tmp_ref) { + binder_inner_proc_unlock(proc); + binder_free_proc(proc); + return; } - return 0; + binder_inner_proc_unlock(proc); } +/** + * binder_get_txn_from() - safely extract the "from" thread in transaction + * @t: binder transaction for t->from + * + * Atomically return the "from" thread and increment the tmp_ref + * count for the thread to ensure it stays alive until + * binder_thread_dec_tmpref() is called. + * + * Return: the value of t->from + */ +static struct binder_thread *binder_get_txn_from( + struct binder_transaction *t) +{ + struct binder_thread *from; + + spin_lock(&t->lock); + from = t->from; + if (from) + atomic_inc(&from->tmp_ref); + spin_unlock(&t->lock); + return from; +} -static int binder_dec_ref(struct binder_ref *ref, int strong) +/** + * binder_get_txn_from_and_acq_inner() - get t->from and acquire inner lock + * @t: binder transaction for t->from + * + * Same as binder_get_txn_from() except it also acquires the proc->inner_lock + * to guarantee that the thread cannot be released while operating on it. + * The caller must call binder_inner_proc_unlock() to release the inner lock + * as well as call binder_dec_thread_txn() to release the reference. + * + * Return: the value of t->from + */ +static struct binder_thread *binder_get_txn_from_and_acq_inner( + struct binder_transaction *t) { - if (strong) { - if (ref->strong == 0) { - binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->debug_id, - ref->desc, ref->strong, ref->weak); - return -EINVAL; - } - ref->strong--; - if (ref->strong == 0) { - int ret; + struct binder_thread *from; - ret = binder_dec_node(ref->node, strong, 1); - if (ret) - return ret; - } - } else { - if (ref->weak == 0) { - binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", - ref->proc->pid, ref->debug_id, - ref->desc, ref->strong, ref->weak); - return -EINVAL; - } - ref->weak--; + from = binder_get_txn_from(t); + if (!from) + return NULL; + binder_inner_proc_lock(from->proc); + if (t->from) { + BUG_ON(from != t->from); + return from; } - if (ref->strong == 0 && ref->weak == 0) - binder_delete_ref(ref); - return 0; + binder_inner_proc_unlock(from->proc); + binder_thread_dec_tmpref(from); + return NULL; } -static void binder_pop_transaction(struct binder_thread *target_thread, - struct binder_transaction *t) +static void binder_free_transaction(struct binder_transaction *t) { - if (target_thread) { - BUG_ON(target_thread->transaction_stack != t); - BUG_ON(target_thread->transaction_stack->from != target_thread); - target_thread->transaction_stack = - target_thread->transaction_stack->from_parent; - t->from = NULL; - } - t->need_reply = 0; if (t->buffer) t->buffer->transaction = NULL; kfree(t); @@ -1306,30 +2134,28 @@ static void binder_send_failed_reply(struct binder_transaction *t, BUG_ON(t->flags & TF_ONE_WAY); while (1) { - target_thread = t->from; + target_thread = binder_get_txn_from_and_acq_inner(t); if (target_thread) { - if (target_thread->return_error != BR_OK && - target_thread->return_error2 == BR_OK) { - target_thread->return_error2 = - target_thread->return_error; - target_thread->return_error = BR_OK; - } - if (target_thread->return_error == BR_OK) { - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "send failed reply for transaction %d to %d:%d\n", - t->debug_id, - target_thread->proc->pid, - target_thread->pid); - - binder_pop_transaction(target_thread, t); - target_thread->return_error = error_code; + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "send failed reply for transaction %d to %d:%d\n", + t->debug_id, + target_thread->proc->pid, + target_thread->pid); + + binder_pop_transaction_ilocked(target_thread, t); + if (target_thread->reply_error.cmd == BR_OK) { + target_thread->reply_error.cmd = error_code; + binder_enqueue_thread_work_ilocked( + target_thread, + &target_thread->reply_error.work); wake_up_interruptible(&target_thread->wait); } else { - pr_err("reply failed, target thread, %d:%d, has error code %d already\n", - target_thread->proc->pid, - target_thread->pid, - target_thread->return_error); + WARN(1, "Unexpected reply error: %u\n", + target_thread->reply_error.cmd); } + binder_inner_proc_unlock(target_thread->proc); + binder_thread_dec_tmpref(target_thread); + binder_free_transaction(t); return; } next = t->from_parent; @@ -1338,7 +2164,7 @@ static void binder_send_failed_reply(struct binder_transaction *t, "send failed reply for transaction %d, target dead\n", t->debug_id); - binder_pop_transaction(target_thread, t); + binder_free_transaction(t); if (next == NULL) { binder_debug(BINDER_DEBUG_DEAD_BINDER, "reply failed, no target thread at root\n"); @@ -1351,6 +2177,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, } } +/** + * binder_cleanup_transaction() - cleans up undelivered transaction + * @t: transaction that needs to be cleaned up + * @reason: reason the transaction wasn't delivered + * @error_code: error to return to caller (if synchronous call) + */ +static void binder_cleanup_transaction(struct binder_transaction *t, + const char *reason, + uint32_t error_code) +{ + if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) { + binder_send_failed_reply(t, error_code); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered transaction %d, %s\n", + t->debug_id, reason); + binder_free_transaction(t); + } +} + /** * binder_validate_object() - checks for a valid metadata object in a buffer. * @buffer: binder_buffer that we're parsing. @@ -1547,24 +2393,26 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, node->debug_id, (u64)node->ptr); binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, 0); + binder_put_node(node); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct flat_binder_object *fp; - struct binder_ref *ref; + struct binder_ref_data rdata; + int ret; fp = to_flat_binder_object(hdr); - ref = binder_get_ref(proc, fp->handle, - hdr->type == BINDER_TYPE_HANDLE); - if (ref == NULL) { - pr_err("transaction release %d bad handle %d\n", - debug_id, fp->handle); + ret = binder_dec_ref_for_handle(proc, fp->handle, + hdr->type == BINDER_TYPE_HANDLE, &rdata); + + if (ret) { + pr_err("transaction release %d bad handle %d, ret = %d\n", + debug_id, fp->handle, ret); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, ref->node->debug_id); - binder_dec_ref(ref, hdr->type == BINDER_TYPE_HANDLE); + " ref %d desc %d\n", + rdata.debug_id, rdata.desc); } break; case BINDER_TYPE_FD: { @@ -1603,7 +2451,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * back to kernel address space to access it */ parent_buffer = parent->buffer - - proc->user_buffer_offset; + binder_alloc_get_user_buffer_offset( + &proc->alloc); fd_buf_size = sizeof(u32) * fda->num_fds; if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { @@ -1618,7 +2467,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, debug_id, (u64)fda->num_fds); continue; } - fd_array = (u32 *)(parent_buffer + fda->parent_offset); + fd_array = (u32 *)(parent_buffer + (uintptr_t)fda->parent_offset); for (fd_index = 0; fd_index < fda->num_fds; fd_index++) task_close_fd(proc, fd_array[fd_index]); } break; @@ -1635,102 +2484,121 @@ static int binder_translate_binder(struct flat_binder_object *fp, struct binder_thread *thread) { struct binder_node *node; - struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; + struct binder_ref_data rdata; + int ret = 0; node = binder_get_node(proc, fp->binder); if (!node) { - node = binder_new_node(proc, fp->binder, fp->cookie); + node = binder_new_node(proc, fp); if (!node) return -ENOMEM; - - node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; - node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, (u64)fp->binder, node->debug_id, (u64)fp->cookie, (u64)node->cookie); - return -EINVAL; + ret = -EINVAL; + goto done; + } + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + ret = -EPERM; + goto done; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) - return -EPERM; - ref = binder_get_ref_for_node(target_proc, node); - if (!ref) - return -EINVAL; + ret = binder_inc_ref_for_node(target_proc, node, + fp->hdr.type == BINDER_TYPE_BINDER, + &thread->todo, &rdata); + if (ret) + goto done; if (fp->hdr.type == BINDER_TYPE_BINDER) fp->hdr.type = BINDER_TYPE_HANDLE; else fp->hdr.type = BINDER_TYPE_WEAK_HANDLE; fp->binder = 0; - fp->handle = ref->desc; + fp->handle = rdata.desc; fp->cookie = 0; - binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo); - trace_binder_transaction_node_to_ref(t, node, ref); + trace_binder_transaction_node_to_ref(t, node, &rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " node %d u%016llx -> ref %d desc %d\n", node->debug_id, (u64)node->ptr, - ref->debug_id, ref->desc); - - return 0; + rdata.debug_id, rdata.desc); +done: + binder_put_node(node); + return ret; } static int binder_translate_handle(struct flat_binder_object *fp, struct binder_transaction *t, struct binder_thread *thread) { - struct binder_ref *ref; struct binder_proc *proc = thread->proc; struct binder_proc *target_proc = t->to_proc; + struct binder_node *node; + struct binder_ref_data src_rdata; + int ret = 0; - ref = binder_get_ref(proc, fp->handle, - fp->hdr.type == BINDER_TYPE_HANDLE); - if (!ref) { + node = binder_get_node_from_ref(proc, fp->handle, + fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); + if (!node) { binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, thread->pid, fp->handle); return -EINVAL; } - if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) - return -EPERM; + if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { + ret = -EPERM; + goto done; + } - if (ref->node->proc == target_proc) { + binder_node_lock(node); + if (node->proc == target_proc) { if (fp->hdr.type == BINDER_TYPE_HANDLE) fp->hdr.type = BINDER_TYPE_BINDER; else fp->hdr.type = BINDER_TYPE_WEAK_BINDER; - fp->binder = ref->node->ptr; - fp->cookie = ref->node->cookie; - binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER, - 0, NULL); - trace_binder_transaction_ref_to_node(t, ref); + fp->binder = node->ptr; + fp->cookie = node->cookie; + if (node->proc) + binder_inner_proc_lock(node->proc); + binder_inc_node_nilocked(node, + fp->hdr.type == BINDER_TYPE_BINDER, + 0, NULL); + if (node->proc) + binder_inner_proc_unlock(node->proc); + trace_binder_transaction_ref_to_node(t, node, &src_rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> node %d u%016llx\n", - ref->debug_id, ref->desc, ref->node->debug_id, - (u64)ref->node->ptr); + src_rdata.debug_id, src_rdata.desc, node->debug_id, + (u64)node->ptr); + binder_node_unlock(node); } else { - struct binder_ref *new_ref; + struct binder_ref_data dest_rdata; - new_ref = binder_get_ref_for_node(target_proc, ref->node); - if (!new_ref) - return -EINVAL; + binder_node_unlock(node); + ret = binder_inc_ref_for_node(target_proc, node, + fp->hdr.type == BINDER_TYPE_HANDLE, + NULL, &dest_rdata); + if (ret) + goto done; fp->binder = 0; - fp->handle = new_ref->desc; + fp->handle = dest_rdata.desc; fp->cookie = 0; - binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE, - NULL); - trace_binder_transaction_ref_to_ref(t, ref, new_ref); + trace_binder_transaction_ref_to_ref(t, node, &src_rdata, + &dest_rdata); binder_debug(BINDER_DEBUG_TRANSACTION, " ref %d desc %d -> ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, new_ref->debug_id, - new_ref->desc, ref->node->debug_id); + src_rdata.debug_id, src_rdata.desc, + dest_rdata.debug_id, dest_rdata.desc, + node->debug_id); } - return 0; +done: + binder_put_node(node); + return ret; } static int binder_translate_fd(int fd, @@ -1765,9 +2633,7 @@ static int binder_translate_fd(int fd, ret = -EBADF; goto err_fget; } - preempt_enable_no_resched(); ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file); - preempt_disable(); if (ret < 0) { ret = -EPERM; goto err_security; @@ -1823,8 +2689,9 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, * Since the parent was already fixed up, convert it * back to the kernel address space to access it */ - parent_buffer = parent->buffer - target_proc->user_buffer_offset; - fd_array = (u32 *)(parent_buffer + fda->parent_offset); + parent_buffer = parent->buffer - + binder_alloc_get_user_buffer_offset(&target_proc->alloc); + fd_array = (u32 *)(parent_buffer + (uintptr_t)fda->parent_offset); if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { binder_user_error("%d:%d parent offset not aligned correctly.\n", proc->pid, thread->pid); @@ -1890,13 +2757,126 @@ static int binder_fixup_parent(struct binder_transaction *t, proc->pid, thread->pid); return -EINVAL; } - parent_buffer = (u8 *)(parent->buffer - - target_proc->user_buffer_offset); + parent_buffer = (u8 *)((uintptr_t)parent->buffer - + binder_alloc_get_user_buffer_offset( + &target_proc->alloc)); *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; return 0; } +/** + * binder_proc_transaction() - sends a transaction to a process and wakes it up + * @t: transaction to send + * @proc: process to send the transaction to + * @thread: thread in @proc to send the transaction to (may be NULL) + * + * This function queues a transaction to the specified process. It will try + * to find a thread in the target process to handle the transaction and + * wake it up. If no thread is found, the work is queued to the proc + * waitqueue. + * + * If the @thread parameter is not NULL, the transaction is always queued + * to the waitlist of that specific thread. + * + * Return: true if the transactions was successfully queued + * false if the target process or thread is dead + */ +static bool binder_proc_transaction(struct binder_transaction *t, + struct binder_proc *proc, + struct binder_thread *thread) +{ + struct binder_node *node = t->buffer->target_node; + struct binder_priority node_prio; + bool oneway = !!(t->flags & TF_ONE_WAY); + bool pending_async = false; + + BUG_ON(!node); + binder_node_lock(node); + node_prio.prio = node->min_priority; + node_prio.sched_policy = node->sched_policy; + + if (oneway) { + BUG_ON(thread); + if (node->has_async_transaction) { + pending_async = true; + } else { + node->has_async_transaction = 1; + } + } + + binder_inner_proc_lock(proc); + + if (proc->is_dead || (thread && thread->is_dead)) { + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + return false; + } + + if (!thread && !pending_async) + thread = binder_select_thread_ilocked(proc); + + if (thread) { + binder_transaction_priority(thread->task, t, node_prio, + node->inherit_rt); + binder_enqueue_thread_work_ilocked(thread, &t->work); + } else if (!pending_async) { + binder_enqueue_work_ilocked(&t->work, &proc->todo); + } else { + binder_enqueue_work_ilocked(&t->work, &node->async_todo); + } + + if (!pending_async) + binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + + return true; +} + +/** + * binder_get_node_refs_for_txn() - Get required refs on node for txn + * @node: struct binder_node for which to get refs + * @proc: returns @node->proc if valid + * @error: if no @proc then returns BR_DEAD_REPLY + * + * User-space normally keeps the node alive when creating a transaction + * since it has a reference to the target. The local strong ref keeps it + * alive if the sending process dies before the target process processes + * the transaction. If the source process is malicious or has a reference + * counting bug, relying on the local strong ref can fail. + * + * Since user-space can cause the local strong ref to go away, we also take + * a tmpref on the node to ensure it survives while we are constructing + * the transaction. We also need a tmpref on the proc while we are + * constructing the transaction, so we take that here as well. + * + * Return: The target_node with refs taken or NULL if no @node->proc is NULL. + * Also sets @proc if valid. If the @node->proc is NULL indicating that the + * target proc has died, @error is set to BR_DEAD_REPLY + */ +static struct binder_node *binder_get_node_refs_for_txn( + struct binder_node *node, + struct binder_proc **procp, + uint32_t *error) +{ + struct binder_node *target_node = NULL; + + binder_node_inner_lock(node); + if (node->proc) { + target_node = node; + binder_inc_node_nilocked(node, 1, 0, NULL); + binder_inc_node_tmpref_ilocked(node); + node->proc->tmp_ref++; + *procp = node->proc; + } else + *error = BR_DEAD_REPLY; + binder_node_inner_unlock(node); + + return target_node; +} + static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply, @@ -1908,19 +2888,21 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t *offp, *off_end, *off_start; binder_size_t off_min; u8 *sg_bufp, *sg_buf_end; - struct binder_proc *target_proc; + struct binder_proc *target_proc = NULL; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; - struct list_head *target_list; - wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; - uint32_t return_error; + uint32_t return_error = 0; + uint32_t return_error_param = 0; + uint32_t return_error_line = 0; struct binder_buffer_object *last_fixup_obj = NULL; binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; + int t_debug_id = atomic_inc_return(&binder_last_id); e = binder_transaction_log_add(&binder_transaction_log); + e->debug_id = t_debug_id; e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); e->from_proc = proc->pid; e->from_thread = thread->pid; @@ -1930,29 +2912,39 @@ static void binder_transaction(struct binder_proc *proc, e->context_name = proc->context->name; if (reply) { + binder_inner_proc_lock(proc); in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) { + binder_inner_proc_unlock(proc); binder_user_error("%d:%d got reply transaction with no transaction stack\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; goto err_empty_call_stack; } - binder_set_nice(in_reply_to->saved_priority); if (in_reply_to->to_thread != thread) { + spin_lock(&in_reply_to->lock); binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, in_reply_to->to_thread ? in_reply_to->to_thread->pid : 0); + spin_unlock(&in_reply_to->lock); + binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; in_reply_to = NULL; goto err_bad_call_stack; } thread->transaction_stack = in_reply_to->to_parent; - target_thread = in_reply_to->from; + binder_inner_proc_unlock(proc); + target_thread = binder_get_txn_from_and_acq_inner(in_reply_to); if (target_thread == NULL) { return_error = BR_DEAD_REPLY; + return_error_line = __LINE__; goto err_dead_binder; } if (target_thread->transaction_stack != in_reply_to) { @@ -1961,89 +2953,129 @@ static void binder_transaction(struct binder_proc *proc, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, in_reply_to->debug_id); + binder_inner_proc_unlock(target_thread->proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; in_reply_to = NULL; target_thread = NULL; goto err_dead_binder; } target_proc = target_thread->proc; + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_thread->proc); } else { if (tr->target.handle) { struct binder_ref *ref; - ref = binder_get_ref(proc, tr->target.handle, true); - if (ref == NULL) { + /* + * There must already be a strong ref + * on this node. If so, do a strong + * increment on the node to ensure it + * stays alive until the transaction is + * done. + */ + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, tr->target.handle, + true); + if (ref) { + target_node = binder_get_node_refs_for_txn( + ref->node, &target_proc, + &return_error); + } else { binder_user_error("%d:%d got transaction to invalid handle\n", - proc->pid, thread->pid); + proc->pid, thread->pid); return_error = BR_FAILED_REPLY; - goto err_invalid_target_handle; } - target_node = ref->node; + binder_proc_unlock(proc); } else { + mutex_lock(&context->context_mgr_node_lock); target_node = context->binder_context_mgr_node; - if (target_node == NULL) { + if (target_node) + target_node = binder_get_node_refs_for_txn( + target_node, &target_proc, + &return_error); + else return_error = BR_DEAD_REPLY; - goto err_no_context_mgr_node; - } + mutex_unlock(&context->context_mgr_node_lock); } - e->to_node = target_node->debug_id; - target_proc = target_node->proc; - if (target_proc == NULL) { - return_error = BR_DEAD_REPLY; + if (!target_node) { + /* + * return_error is set above + */ + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_dead_binder; } + e->to_node = target_node->debug_id; if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { return_error = BR_FAILED_REPLY; + return_error_param = -EPERM; + return_error_line = __LINE__; goto err_invalid_target_handle; } + binder_inner_proc_lock(proc); if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; if (tmp->to_thread != thread) { + spin_lock(&tmp->lock); binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? tmp->to_thread->pid : 0); + spin_unlock(&tmp->lock); + binder_inner_proc_unlock(proc); return_error = BR_FAILED_REPLY; + return_error_param = -EPROTO; + return_error_line = __LINE__; goto err_bad_call_stack; } while (tmp) { - if (tmp->from && tmp->from->proc == target_proc) - target_thread = tmp->from; + struct binder_thread *from; + + spin_lock(&tmp->lock); + from = tmp->from; + if (from && from->proc == target_proc) { + atomic_inc(&from->tmp_ref); + target_thread = from; + spin_unlock(&tmp->lock); + break; + } + spin_unlock(&tmp->lock); tmp = tmp->from_parent; } } + binder_inner_proc_unlock(proc); } - if (target_thread) { + if (target_thread) e->to_thread = target_thread->pid; - target_list = &target_thread->todo; - target_wait = &target_thread->wait; - } else { - target_list = &target_proc->todo; - target_wait = &target_proc->wait; - } e->to_proc = target_proc->pid; /* TODO: reuse incoming transaction for reply */ - t = kzalloc_preempt_disabled(sizeof(*t)); + t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; goto err_alloc_t_failed; } binder_stats_created(BINDER_STAT_TRANSACTION); + spin_lock_init(&t->lock); - tcomplete = kzalloc_preempt_disabled(sizeof(*tcomplete)); + tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; + return_error_param = -ENOMEM; + return_error_line = __LINE__; goto err_alloc_tcomplete_failed; } binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); - t->debug_id = ++binder_last_id; - e->debug_id = t->debug_id; + t->debug_id = t_debug_id; if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, @@ -2073,15 +3105,30 @@ static void binder_transaction(struct binder_proc *proc, t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; - t->priority = task_nice(current); + if (!(t->flags & TF_ONE_WAY) && + binder_supported_policy(current->policy)) { + /* Inherit supported policies for synchronous transactions */ + t->priority.sched_policy = current->policy; + t->priority.prio = current->normal_prio; + } else { + /* Otherwise, fall back to the default priority */ + t->priority = target_proc->default_priority; + } trace_binder_transaction(reply, t, target_node); - t->buffer = binder_alloc_buf(target_proc, tr->data_size, + t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, tr->offsets_size, extra_buffers_size, !reply && (t->flags & TF_ONE_WAY)); - if (t->buffer == NULL) { - return_error = BR_FAILED_REPLY; + if (IS_ERR(t->buffer)) { + /* + * -ESRCH indicates VMA cleared. The target is dying. + */ + return_error_param = PTR_ERR(t->buffer); + return_error = return_error_param == -ESRCH ? + BR_DEAD_REPLY : BR_FAILED_REPLY; + return_error_line = __LINE__; + t->buffer = NULL; goto err_binder_alloc_buf_failed; } t->buffer->allow_user_free = 0; @@ -2089,31 +3136,34 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->transaction = t; t->buffer->target_node = target_node; trace_binder_transaction_alloc_buf(t->buffer); - if (target_node) - binder_inc_node(target_node, 1, 0, NULL); - off_start = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); offp = off_start; - if (copy_from_user_preempt_disabled(t->buffer->data, (const void __user *)(uintptr_t) + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EFAULT; + return_error_line = __LINE__; goto err_copy_data_failed; } - if (copy_from_user_preempt_disabled(offp, (const void __user *)(uintptr_t) + if (copy_from_user(offp, (const void __user *)(uintptr_t) tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EFAULT; + return_error_line = __LINE__; goto err_copy_data_failed; } if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) { @@ -2121,6 +3171,8 @@ static void binder_transaction(struct binder_proc *proc, proc->pid, thread->pid, (u64)extra_buffers_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } off_end = (void *)off_start + tr->offsets_size; @@ -2137,6 +3189,8 @@ static void binder_transaction(struct binder_proc *proc, (u64)off_min, (u64)t->buffer->data_size); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } @@ -2151,6 +3205,8 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_binder(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -2162,6 +3218,8 @@ static void binder_transaction(struct binder_proc *proc, ret = binder_translate_handle(fp, t, thread); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } } break; @@ -2173,6 +3231,8 @@ static void binder_transaction(struct binder_proc *proc, if (target_fd < 0) { return_error = BR_FAILED_REPLY; + return_error_param = target_fd; + return_error_line = __LINE__; goto err_translate_failed; } fp->pad_binder = 0; @@ -2189,6 +3249,8 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid parent offset or type\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_parent; } if (!binder_validate_fixup(t->buffer, off_start, @@ -2198,12 +3260,16 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_parent; } ret = binder_translate_fd_array(fda, parent, t, thread, in_reply_to); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = parent; @@ -2219,20 +3285,24 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with too large buffer\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_offset; } - if (copy_from_user_preempt_disabled( - sg_bufp, - (const void __user *)(uintptr_t) - bp->buffer, bp->length)) { + if (copy_from_user(sg_bufp, + (const void __user *)(uintptr_t) + bp->buffer, bp->length)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); + return_error_param = -EFAULT; return_error = BR_FAILED_REPLY; + return_error_line = __LINE__; goto err_copy_data_failed; } /* Fixup buffer pointer to target proc address space */ bp->buffer = (uintptr_t)sg_bufp + - target_proc->user_buffer_offset; + binder_alloc_get_user_buffer_offset( + &target_proc->alloc); sg_bufp += ALIGN(bp->length, sizeof(u64)); ret = binder_fixup_parent(t, thread, bp, off_start, @@ -2241,6 +3311,8 @@ static void binder_transaction(struct binder_proc *proc, last_fixup_min_off); if (ret < 0) { return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; goto err_translate_failed; } last_fixup_obj = bp; @@ -2250,34 +3322,73 @@ static void binder_transaction(struct binder_proc *proc, binder_user_error("%d:%d got transaction with invalid object type, %x\n", proc->pid, thread->pid, hdr->type); return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; goto err_bad_object_type; } } + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + t->work.type = BINDER_WORK_TRANSACTION; + if (reply) { + binder_enqueue_thread_work(thread, tcomplete); + binder_inner_proc_lock(target_proc); + if (target_thread->is_dead) { + binder_inner_proc_unlock(target_proc); + goto err_dead_proc_or_thread; + } BUG_ON(t->buffer->async_transaction != 0); - binder_pop_transaction(target_thread, in_reply_to); + binder_pop_transaction_ilocked(target_thread, in_reply_to); + binder_enqueue_thread_work_ilocked(target_thread, &t->work); + binder_inner_proc_unlock(target_proc); + wake_up_interruptible_sync(&target_thread->wait); + binder_restore_priority(current, in_reply_to->saved_priority); + binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); + binder_inner_proc_lock(proc); + /* + * Defer the TRANSACTION_COMPLETE, so we don't return to + * userspace immediately; this allows the target process to + * immediately start processing this transaction, reducing + * latency. We will then return the TRANSACTION_COMPLETE when + * the target replies (or there is an error). + */ + binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete); t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; + binder_inner_proc_unlock(proc); + if (!binder_proc_transaction(t, target_proc, target_thread)) { + binder_inner_proc_lock(proc); + binder_pop_transaction_ilocked(thread, t); + binder_inner_proc_unlock(proc); + goto err_dead_proc_or_thread; + } } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); - if (target_node->has_async_transaction) { - target_list = &target_node->async_todo; - target_wait = NULL; - } else - target_node->has_async_transaction = 1; + binder_enqueue_thread_work(thread, tcomplete); + if (!binder_proc_transaction(t, target_proc, NULL)) + goto err_dead_proc_or_thread; } - t->work.type = BINDER_WORK_TRANSACTION; - list_add_tail(&t->work.entry, target_list); - tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; - list_add_tail(&tcomplete->entry, &thread->todo); - if (target_wait) - wake_up_interruptible(target_wait); + if (target_thread) + binder_thread_dec_tmpref(target_thread); + binder_proc_dec_tmpref(target_proc); + if (target_node) + binder_dec_node_tmpref(target_node); + /* + * write barrier to synchronize with initialization + * of log entry + */ + smp_wmb(); + WRITE_ONCE(e->debug_id_done, t_debug_id); return; +err_dead_proc_or_thread: + return_error = BR_DEAD_REPLY; + return_error_line = __LINE__; + binder_dequeue_work(proc, tcomplete); err_translate_failed: err_bad_object_type: err_bad_offset: @@ -2285,8 +3396,11 @@ static void binder_transaction(struct binder_proc *proc, err_copy_data_failed: trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); + if (target_node) + binder_dec_node_tmpref(target_node); + target_node = NULL; t->buffer->transaction = NULL; - binder_free_buf(target_proc, t->buffer); + binder_alloc_free_buf(&target_proc->alloc, t->buffer); err_binder_alloc_buf_failed: kfree(tcomplete); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); @@ -2298,25 +3412,48 @@ static void binder_transaction(struct binder_proc *proc, err_empty_call_stack: err_dead_binder: err_invalid_target_handle: -err_no_context_mgr_node: + if (target_thread) + binder_thread_dec_tmpref(target_thread); + if (target_proc) + binder_proc_dec_tmpref(target_proc); + if (target_node) { + binder_dec_node(target_node, 1, 0); + binder_dec_node_tmpref(target_node); + } + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %lld-%lld\n", - proc->pid, thread->pid, return_error, - (u64)tr->data_size, (u64)tr->offsets_size); + "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n", + proc->pid, thread->pid, return_error, return_error_param, + (u64)tr->data_size, (u64)tr->offsets_size, + return_error_line); { struct binder_transaction_log_entry *fe; + e->return_error = return_error; + e->return_error_param = return_error_param; + e->return_error_line = return_error_line; fe = binder_transaction_log_add(&binder_transaction_log_failed); *fe = *e; + /* + * write barrier to synchronize with initialization + * of log entry + */ + smp_wmb(); + WRITE_ONCE(e->debug_id_done, t_debug_id); + WRITE_ONCE(fe->debug_id_done, t_debug_id); } - BUG_ON(thread->return_error != BR_OK); + BUG_ON(thread->return_error.cmd != BR_OK); if (in_reply_to) { - thread->return_error = BR_TRANSACTION_COMPLETE; + binder_restore_priority(current, in_reply_to->saved_priority); + thread->return_error.cmd = BR_TRANSACTION_COMPLETE; + binder_enqueue_thread_work(thread, &thread->return_error.work); binder_send_failed_reply(in_reply_to, return_error); - } else - thread->return_error = return_error; + } else { + thread->return_error.cmd = return_error; + binder_enqueue_thread_work(thread, &thread->return_error.work); + } } static int binder_thread_write(struct binder_proc *proc, @@ -2330,15 +3467,17 @@ static int binder_thread_write(struct binder_proc *proc, void __user *ptr = buffer + *consumed; void __user *end = buffer + size; - while (ptr < end && thread->return_error == BR_OK) { - if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr)) + while (ptr < end && thread->return_error.cmd == BR_OK) { + int ret; + + if (get_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); trace_binder_command(cmd); if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { - binder_stats.bc[_IOC_NR(cmd)]++; - proc->stats.bc[_IOC_NR(cmd)]++; - thread->stats.bc[_IOC_NR(cmd)]++; + atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]); + atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]); + atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]); } switch (cmd) { case BC_INCREFS: @@ -2346,53 +3485,61 @@ static int binder_thread_write(struct binder_proc *proc, case BC_RELEASE: case BC_DECREFS: { uint32_t target; - struct binder_ref *ref; const char *debug_string; + bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE; + bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; + struct binder_ref_data rdata; - if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) + if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; + ptr += sizeof(uint32_t); - if (target == 0 && context->binder_context_mgr_node && - (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { - ref = binder_get_ref_for_node(proc, - context->binder_context_mgr_node); - if (ref->desc != target) { - binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n", - proc->pid, thread->pid, - ref->desc); - } - } else - ref = binder_get_ref(proc, target, - cmd == BC_ACQUIRE || - cmd == BC_RELEASE); - if (ref == NULL) { - binder_user_error("%d:%d refcount change on invalid ref %d\n", - proc->pid, thread->pid, target); - break; + ret = -1; + if (increment && !target) { + struct binder_node *ctx_mgr_node; + mutex_lock(&context->context_mgr_node_lock); + ctx_mgr_node = context->binder_context_mgr_node; + if (ctx_mgr_node) + ret = binder_inc_ref_for_node( + proc, ctx_mgr_node, + strong, NULL, &rdata); + mutex_unlock(&context->context_mgr_node_lock); + } + if (ret) + ret = binder_update_ref_for_handle( + proc, target, increment, strong, + &rdata); + if (!ret && rdata.desc != target) { + binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n", + proc->pid, thread->pid, + target, rdata.desc); } switch (cmd) { case BC_INCREFS: debug_string = "IncRefs"; - binder_inc_ref(ref, 0, NULL); break; case BC_ACQUIRE: debug_string = "Acquire"; - binder_inc_ref(ref, 1, NULL); break; case BC_RELEASE: debug_string = "Release"; - binder_dec_ref(ref, 1); break; case BC_DECREFS: default: debug_string = "DecRefs"; - binder_dec_ref(ref, 0); + break; + } + if (ret) { + binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n", + proc->pid, thread->pid, debug_string, + strong, target, ret); break; } binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, debug_string, ref->debug_id, - ref->desc, ref->strong, ref->weak, ref->node->debug_id); + "%d:%d %s ref %d desc %d s %d w %d\n", + proc->pid, thread->pid, debug_string, + rdata.debug_id, rdata.desc, rdata.strong, + rdata.weak); break; } case BC_INCREFS_DONE: @@ -2400,11 +3547,12 @@ static int binder_thread_write(struct binder_proc *proc, binder_uintptr_t node_ptr; binder_uintptr_t cookie; struct binder_node *node; + bool free_node; - if (get_user_preempt_disabled(node_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); @@ -2424,13 +3572,17 @@ static int binder_thread_write(struct binder_proc *proc, "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", (u64)node_ptr, node->debug_id, (u64)cookie, (u64)node->cookie); + binder_put_node(node); break; } + binder_node_inner_lock(node); if (cmd == BC_ACQUIRE_DONE) { if (node->pending_strong_ref == 0) { binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", proc->pid, thread->pid, node->debug_id); + binder_node_inner_unlock(node); + binder_put_node(node); break; } node->pending_strong_ref = 0; @@ -2439,16 +3591,23 @@ static int binder_thread_write(struct binder_proc *proc, binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", proc->pid, thread->pid, node->debug_id); + binder_node_inner_unlock(node); + binder_put_node(node); break; } node->pending_weak_ref = 0; } - binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); + free_node = binder_dec_node_nilocked(node, + cmd == BC_ACQUIRE_DONE, 0); + WARN_ON(free_node); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s node %d ls %d lw %d\n", + "%d:%d %s node %d ls %d lw %d tr %d\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node->debug_id, node->local_strong_refs, node->local_weak_refs); + node->debug_id, node->local_strong_refs, + node->local_weak_refs, node->tmp_refs); + binder_node_inner_unlock(node); + binder_put_node(node); break; } case BC_ATTEMPT_ACQUIRE: @@ -2462,11 +3621,12 @@ static int binder_thread_write(struct binder_proc *proc, binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user_preempt_disabled(data_ptr, (binder_uintptr_t __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - buffer = binder_buffer_lookup(proc, data_ptr); + buffer = binder_alloc_prepare_to_free(&proc->alloc, + data_ptr); if (buffer == NULL) { binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", proc->pid, thread->pid, (u64)data_ptr); @@ -2488,15 +3648,27 @@ static int binder_thread_write(struct binder_proc *proc, buffer->transaction = NULL; } if (buffer->async_transaction && buffer->target_node) { - BUG_ON(!buffer->target_node->has_async_transaction); - if (list_empty(&buffer->target_node->async_todo)) - buffer->target_node->has_async_transaction = 0; - else - list_move_tail(buffer->target_node->async_todo.next, &thread->todo); + struct binder_node *buf_node; + struct binder_work *w; + + buf_node = buffer->target_node; + binder_node_inner_lock(buf_node); + BUG_ON(!buf_node->has_async_transaction); + BUG_ON(buf_node->proc != proc); + w = binder_dequeue_work_head_ilocked( + &buf_node->async_todo); + if (!w) { + buf_node->has_async_transaction = 0; + } else { + binder_enqueue_work_ilocked( + w, &proc->todo); + binder_wakeup_proc_ilocked(proc); + } + binder_node_inner_unlock(buf_node); } trace_binder_transaction_buffer_release(buffer); binder_transaction_buffer_release(proc, buffer, NULL); - binder_free_buf(proc, buffer); + binder_alloc_free_buf(&proc->alloc, buffer); break; } @@ -2504,8 +3676,7 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REPLY_SG: { struct binder_transaction_data_sg tr; - if (copy_from_user_preempt_disabled(&tr, ptr, - sizeof(tr))) + if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr.transaction_data, @@ -2516,7 +3687,7 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REPLY: { struct binder_transaction_data tr; - if (copy_from_user_preempt_disabled(&tr, ptr, sizeof(tr))) + if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr, @@ -2528,6 +3699,7 @@ static int binder_thread_write(struct binder_proc *proc, binder_debug(BINDER_DEBUG_THREADS, "%d:%d BC_REGISTER_LOOPER\n", proc->pid, thread->pid); + binder_inner_proc_lock(proc); if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", @@ -2541,6 +3713,7 @@ static int binder_thread_write(struct binder_proc *proc, proc->requested_threads_started++; } thread->looper |= BINDER_LOOPER_STATE_REGISTERED; + binder_inner_proc_unlock(proc); break; case BC_ENTER_LOOPER: binder_debug(BINDER_DEBUG_THREADS, @@ -2565,15 +3738,36 @@ static int binder_thread_write(struct binder_proc *proc, uint32_t target; binder_uintptr_t cookie; struct binder_ref *ref; - struct binder_ref_death *death; + struct binder_ref_death *death = NULL; - if (get_user_preempt_disabled(target, (uint32_t __user *)ptr)) + if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(binder_uintptr_t); - ref = binder_get_ref(proc, target, false); + if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { + /* + * Allocate memory for death notification + * before taking lock + */ + death = kzalloc(sizeof(*death), GFP_KERNEL); + if (death == NULL) { + WARN_ON(thread->return_error.cmd != + BR_OK); + thread->return_error.cmd = BR_ERROR; + binder_enqueue_thread_work( + thread, + &thread->return_error.work); + binder_debug( + BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); + break; + } + } + binder_proc_lock(proc); + ref = binder_get_ref_olocked(proc, target, false); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", proc->pid, thread->pid, @@ -2581,6 +3775,8 @@ static int binder_thread_write(struct binder_proc *proc, "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", target); + binder_proc_unlock(proc); + kfree(death); break; } @@ -2590,21 +3786,18 @@ static int binder_thread_write(struct binder_proc *proc, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - (u64)cookie, ref->debug_id, ref->desc, - ref->strong, ref->weak, ref->node->debug_id); + (u64)cookie, ref->data.debug_id, + ref->data.desc, ref->data.strong, + ref->data.weak, ref->node->debug_id); + binder_node_lock(ref->node); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", proc->pid, thread->pid); - break; - } - death = kzalloc_preempt_disabled(sizeof(*death)); - if (death == NULL) { - thread->return_error = BR_ERROR; - binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); + kfree(death); break; } binder_stats_created(BINDER_STAT_DEATH); @@ -2613,17 +3806,19 @@ static int binder_thread_write(struct binder_proc *proc, ref->death = death; if (ref->node->proc == NULL) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&ref->death->work.entry, &thread->todo); - } else { - list_add_tail(&ref->death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); - } + + binder_inner_proc_lock(proc); + binder_enqueue_work_ilocked( + &ref->death->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); } } else { if (ref->death == NULL) { binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", proc->pid, thread->pid); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); break; } death = ref->death; @@ -2632,33 +3827,52 @@ static int binder_thread_write(struct binder_proc *proc, proc->pid, thread->pid, (u64)death->cookie, (u64)cookie); + binder_node_unlock(ref->node); + binder_proc_unlock(proc); break; } ref->death = NULL; + binder_inner_proc_lock(proc); if (list_empty(&death->work.entry)) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); + if (thread->looper & + (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) + binder_enqueue_thread_work_ilocked( + thread, + &death->work); + else { + binder_enqueue_work_ilocked( + &death->work, + &proc->todo); + binder_wakeup_proc_ilocked( + proc); } } else { BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; } + binder_inner_proc_unlock(proc); } + binder_node_unlock(ref->node); + binder_proc_unlock(proc); } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user_preempt_disabled(cookie, (binder_uintptr_t __user *)ptr)) + + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(cookie); - list_for_each_entry(w, &proc->delivered_death, entry) { - struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + binder_inner_proc_lock(proc); + list_for_each_entry(w, &proc->delivered_death, + entry) { + struct binder_ref_death *tmp_death = + container_of(w, + struct binder_ref_death, + work); if (tmp_death->cookie == cookie) { death = tmp_death; @@ -2672,21 +3886,26 @@ static int binder_thread_write(struct binder_proc *proc, if (death == NULL) { binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", proc->pid, thread->pid, (u64)cookie); + binder_inner_proc_unlock(proc); break; } - - list_del_init(&death->work.entry); + binder_dequeue_work_ilocked(&death->work); if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; - if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { - list_add_tail(&death->work.entry, &thread->todo); - } else { - list_add_tail(&death->work.entry, &proc->todo); - wake_up_interruptible(&proc->wait); + if (thread->looper & + (BINDER_LOOPER_STATE_REGISTERED | + BINDER_LOOPER_STATE_ENTERED)) + binder_enqueue_thread_work_ilocked( + thread, &death->work); + else { + binder_enqueue_work_ilocked( + &death->work, + &proc->todo); + binder_wakeup_proc_ilocked(proc); } } - } - break; + binder_inner_proc_unlock(proc); + } break; default: pr_err("%d:%d unknown command %d\n", @@ -2703,23 +3922,73 @@ static void binder_stat_br(struct binder_proc *proc, { trace_binder_return(cmd); if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { - binder_stats.br[_IOC_NR(cmd)]++; - proc->stats.br[_IOC_NR(cmd)]++; - thread->stats.br[_IOC_NR(cmd)]++; + atomic_inc(&binder_stats.br[_IOC_NR(cmd)]); + atomic_inc(&proc->stats.br[_IOC_NR(cmd)]); + atomic_inc(&thread->stats.br[_IOC_NR(cmd)]); } } -static int binder_has_proc_work(struct binder_proc *proc, - struct binder_thread *thread) +static int binder_put_node_cmd(struct binder_proc *proc, + struct binder_thread *thread, + void __user **ptrp, + binder_uintptr_t node_ptr, + binder_uintptr_t node_cookie, + int node_debug_id, + uint32_t cmd, const char *cmd_name) { - return !list_empty(&proc->todo) || - (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); + void __user *ptr = *ptrp; + + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + + if (put_user(node_ptr, (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + if (put_user(node_cookie, (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_USER_REFS, "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, node_debug_id, + (u64)node_ptr, (u64)node_cookie); + + *ptrp = ptr; + return 0; } -static int binder_has_thread_work(struct binder_thread *thread) -{ - return !list_empty(&thread->todo) || thread->return_error != BR_OK || - (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); +static int binder_wait_for_work(struct binder_thread *thread, + bool do_proc_work) +{ + DEFINE_WAIT(wait); + struct binder_proc *proc = thread->proc; + int ret = 0; + + freezer_do_not_count(); + binder_inner_proc_lock(proc); + for (;;) { + prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE); + if (binder_has_work_ilocked(thread, do_proc_work)) + break; + if (do_proc_work) + list_add(&thread->waiting_thread_node, + &proc->waiting_threads); + binder_inner_proc_unlock(proc); + schedule(); + binder_inner_proc_lock(proc); + list_del_init(&thread->waiting_thread_node); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + finish_wait(&thread->wait, &wait); + binder_inner_proc_unlock(proc); + freezer_count(); + + return ret; } static int binder_thread_read(struct binder_proc *proc, @@ -2735,43 +4004,21 @@ static int binder_thread_read(struct binder_proc *proc, int wait_for_proc_work; if (*consumed == 0) { - if (put_user_preempt_disabled(BR_NOOP, (uint32_t __user *)ptr)) + if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); } retry: - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo); - - if (thread->return_error != BR_OK && ptr < end) { - if (thread->return_error2 != BR_OK) { - if (put_user_preempt_disabled(thread->return_error2, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - binder_stat_br(proc, thread, thread->return_error2); - if (ptr == end) - goto done; - thread->return_error2 = BR_OK; - } - if (put_user_preempt_disabled(thread->return_error, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - binder_stat_br(proc, thread, thread->return_error); - thread->return_error = BR_OK; - goto done; - } - + binder_inner_proc_lock(proc); + wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); + binder_inner_proc_unlock(proc); thread->looper |= BINDER_LOOPER_STATE_WAITING; - if (wait_for_proc_work) - proc->ready_threads++; - - binder_unlock(__func__); trace_binder_wait_for_work(wait_for_proc_work, !!thread->transaction_stack, - !list_empty(&thread->todo)); + !binder_worklist_empty(proc, &thread->todo)); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { @@ -2780,24 +4027,16 @@ static int binder_thread_read(struct binder_proc *proc, wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); } - binder_set_nice(proc->default_priority); - if (non_block) { - if (!binder_has_proc_work(proc, thread)) - ret = -EAGAIN; - } else - ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); - } else { - if (non_block) { - if (!binder_has_thread_work(thread)) - ret = -EAGAIN; - } else - ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); + binder_restore_priority(current, proc->default_priority); } - binder_lock(__func__); + if (non_block) { + if (!binder_has_work(thread, wait_for_proc_work)) + ret = -EAGAIN; + } else { + ret = binder_wait_for_work(thread, wait_for_proc_work); + } - if (wait_for_proc_work) - proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; if (ret) @@ -2806,33 +4045,56 @@ static int binder_thread_read(struct binder_proc *proc, while (1) { uint32_t cmd; struct binder_transaction_data tr; - struct binder_work *w; + struct binder_work *w = NULL; + struct list_head *list = NULL; struct binder_transaction *t = NULL; + struct binder_thread *t_from; + + binder_inner_proc_lock(proc); + if (!binder_worklist_empty_ilocked(&thread->todo)) + list = &thread->todo; + else if (!binder_worklist_empty_ilocked(&proc->todo) && + wait_for_proc_work) + list = &proc->todo; + else { + binder_inner_proc_unlock(proc); - if (!list_empty(&thread->todo)) { - w = list_first_entry(&thread->todo, struct binder_work, - entry); - } else if (!list_empty(&proc->todo) && wait_for_proc_work) { - w = list_first_entry(&proc->todo, struct binder_work, - entry); - } else { /* no data added */ - if (ptr - buffer == 4 && - !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) + if (ptr - buffer == 4 && !thread->looper_need_return) goto retry; break; } - if (end - ptr < sizeof(tr) + 4) + if (end - ptr < sizeof(tr) + 4) { + binder_inner_proc_unlock(proc); break; + } + w = binder_dequeue_work_head_ilocked(list); + if (binder_worklist_empty_ilocked(&thread->todo)) + thread->process_todo = false; switch (w->type) { case BINDER_WORK_TRANSACTION: { + binder_inner_proc_unlock(proc); t = container_of(w, struct binder_transaction, work); } break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + WARN_ON(e->cmd == BR_OK); + binder_inner_proc_unlock(proc); + if (put_user(e->cmd, (uint32_t __user *)ptr)) + return -EFAULT; + e->cmd = BR_OK; + ptr += sizeof(uint32_t); + + binder_stat_br(proc, thread, cmd); + } break; case BINDER_WORK_TRANSACTION_COMPLETE: { + binder_inner_proc_unlock(proc); cmd = BR_TRANSACTION_COMPLETE; - if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) + if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); @@ -2840,112 +4102,134 @@ static int binder_thread_read(struct binder_proc *proc, binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, "%d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid); - - list_del(&w->entry); kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_NODE: { struct binder_node *node = container_of(w, struct binder_node, work); - uint32_t cmd = BR_NOOP; - const char *cmd_name; - int strong = node->internal_strong_refs || node->local_strong_refs; - int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; - - if (weak && !node->has_weak_ref) { - cmd = BR_INCREFS; - cmd_name = "BR_INCREFS"; + int strong, weak; + binder_uintptr_t node_ptr = node->ptr; + binder_uintptr_t node_cookie = node->cookie; + int node_debug_id = node->debug_id; + int has_weak_ref; + int has_strong_ref; + void __user *orig_ptr = ptr; + + BUG_ON(proc != node->proc); + strong = node->internal_strong_refs || + node->local_strong_refs; + weak = !hlist_empty(&node->refs) || + node->local_weak_refs || + node->tmp_refs || strong; + has_strong_ref = node->has_strong_ref; + has_weak_ref = node->has_weak_ref; + + if (weak && !has_weak_ref) { node->has_weak_ref = 1; node->pending_weak_ref = 1; node->local_weak_refs++; - } else if (strong && !node->has_strong_ref) { - cmd = BR_ACQUIRE; - cmd_name = "BR_ACQUIRE"; + } + if (strong && !has_strong_ref) { node->has_strong_ref = 1; node->pending_strong_ref = 1; node->local_strong_refs++; - } else if (!strong && node->has_strong_ref) { - cmd = BR_RELEASE; - cmd_name = "BR_RELEASE"; + } + if (!strong && has_strong_ref) node->has_strong_ref = 0; - } else if (!weak && node->has_weak_ref) { - cmd = BR_DECREFS; - cmd_name = "BR_DECREFS"; + if (!weak && has_weak_ref) node->has_weak_ref = 0; - } - if (cmd != BR_NOOP) { - if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *) - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *) - (binder_uintptr_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - - binder_stat_br(proc, thread, cmd); - binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%016llx c%016llx\n", - proc->pid, thread->pid, cmd_name, - node->debug_id, - (u64)node->ptr, (u64)node->cookie); - } else { - list_del_init(&w->entry); - if (!weak && !strong) { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx deleted\n", - proc->pid, thread->pid, - node->debug_id, - (u64)node->ptr, - (u64)node->cookie); - rb_erase(&node->rb_node, &proc->nodes); - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); - } else { - binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%016llx c%016llx state unchanged\n", - proc->pid, thread->pid, - node->debug_id, - (u64)node->ptr, - (u64)node->cookie); - } - } + if (!weak && !strong) { + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node_debug_id, + (u64)node_ptr, + (u64)node_cookie); + rb_erase(&node->rb_node, &proc->nodes); + binder_inner_proc_unlock(proc); + binder_node_lock(node); + /* + * Acquire the node lock before freeing the + * node to serialize with other threads that + * may have been holding the node lock while + * decrementing this node (avoids race where + * this thread frees while the other thread + * is unlocking the node after the final + * decrement) + */ + binder_node_unlock(node); + binder_free_node(node); + } else + binder_inner_proc_unlock(proc); + + if (weak && !has_weak_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_INCREFS, "BR_INCREFS"); + if (!ret && strong && !has_strong_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_ACQUIRE, "BR_ACQUIRE"); + if (!ret && !strong && has_strong_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_RELEASE, "BR_RELEASE"); + if (!ret && !weak && has_weak_ref) + ret = binder_put_node_cmd( + proc, thread, &ptr, node_ptr, + node_cookie, node_debug_id, + BR_DECREFS, "BR_DECREFS"); + if (orig_ptr == ptr) + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node_debug_id, + (u64)node_ptr, + (u64)node_cookie); + if (ret) + return ret; } break; case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { struct binder_ref_death *death; uint32_t cmd; + binder_uintptr_t cookie; death = container_of(w, struct binder_ref_death, work); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; - if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); - if (put_user_preempt_disabled(death->cookie, (binder_uintptr_t __user *) ptr)) - return -EFAULT; - ptr += sizeof(binder_uintptr_t); - binder_stat_br(proc, thread, cmd); + cookie = death->cookie; + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - (u64)death->cookie); - + (u64)cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { - list_del(&w->entry); + binder_inner_proc_unlock(proc); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); - } else - list_move(&w->entry, &proc->delivered_death); + } else { + binder_enqueue_work_ilocked( + w, &proc->delivered_death); + binder_inner_proc_unlock(proc); + } + if (put_user(cmd, (uint32_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(uint32_t); + if (put_user(cookie, + (binder_uintptr_t __user *)ptr)) + return -EFAULT; + ptr += sizeof(binder_uintptr_t); + binder_stat_br(proc, thread, cmd); if (cmd == BR_DEAD_BINDER) goto done; /* DEAD_BINDER notifications can cause transactions */ } break; @@ -2957,16 +4241,14 @@ static int binder_thread_read(struct binder_proc *proc, BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; + struct binder_priority node_prio; tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; - t->saved_priority = task_nice(current); - if (t->priority < target_node->min_priority && - !(t->flags & TF_ONE_WAY)) - binder_set_nice(t->priority); - else if (!(t->flags & TF_ONE_WAY) || - t->saved_priority > target_node->min_priority) - binder_set_nice(target_node->min_priority); + node_prio.sched_policy = target_node->sched_policy; + node_prio.prio = target_node->min_priority; + binder_transaction_priority(current, t, node_prio, + target_node->inherit_rt); cmd = BR_TRANSACTION; } else { tr.target.ptr = 0; @@ -2977,8 +4259,9 @@ static int binder_thread_read(struct binder_proc *proc, tr.flags = t->flags; tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); - if (t->from) { - struct task_struct *sender = t->from->proc->tsk; + t_from = binder_get_txn_from(t); + if (t_from) { + struct task_struct *sender = t_from->proc->tsk; tr.sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current)); @@ -2988,18 +4271,32 @@ static int binder_thread_read(struct binder_proc *proc, tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (binder_uintptr_t)( - (uintptr_t)t->buffer->data + - proc->user_buffer_offset); + tr.data.ptr.buffer = (binder_uintptr_t) + ((uintptr_t)t->buffer->data + + binder_alloc_get_user_buffer_offset(&proc->alloc)); tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); - if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr)) + if (put_user(cmd, (uint32_t __user *)ptr)) { + if (t_from) + binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "put_user failed", + BR_FAILED_REPLY); + return -EFAULT; + } ptr += sizeof(uint32_t); - if (copy_to_user_preempt_disabled(ptr, &tr, sizeof(tr))) + if (copy_to_user(ptr, &tr, sizeof(tr))) { + if (t_from) + binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "copy_to_user failed", + BR_FAILED_REPLY); + return -EFAULT; + } ptr += sizeof(tr); trace_binder_transaction_received(t); @@ -3009,21 +4306,22 @@ static int binder_thread_read(struct binder_proc *proc, proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", - t->debug_id, t->from ? t->from->proc->pid : 0, - t->from ? t->from->pid : 0, cmd, + t->debug_id, t_from ? t_from->proc->pid : 0, + t_from ? t_from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); - list_del(&t->work.entry); + if (t_from) + binder_thread_dec_tmpref(t_from); t->buffer->allow_user_free = 1; if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { + binder_inner_proc_lock(thread->proc); t->to_parent = thread->transaction_stack; t->to_thread = thread; thread->transaction_stack = t; + binder_inner_proc_unlock(thread->proc); } else { - t->buffer->transaction = NULL; - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); + binder_free_transaction(t); } break; } @@ -3031,45 +4329,52 @@ static int binder_thread_read(struct binder_proc *proc, done: *consumed = ptr - buffer; - if (proc->requested_threads + proc->ready_threads == 0 && + binder_inner_proc_lock(proc); + if (proc->requested_threads == 0 && + list_empty(&thread->proc->waiting_threads) && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) { proc->requested_threads++; + binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_THREADS, "%d:%d BR_SPAWN_LOOPER\n", proc->pid, thread->pid); - if (put_user_preempt_disabled(BR_SPAWN_LOOPER, (uint32_t __user *) buffer)) + if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) return -EFAULT; binder_stat_br(proc, thread, BR_SPAWN_LOOPER); - } + } else + binder_inner_proc_unlock(proc); return 0; } -static void binder_release_work(struct list_head *list) +static void binder_release_work(struct binder_proc *proc, + struct list_head *list) { struct binder_work *w; - while (!list_empty(list)) { - w = list_first_entry(list, struct binder_work, entry); - list_del_init(&w->entry); + while (1) { + w = binder_dequeue_work_head(proc, list); + if (!w) + return; + switch (w->type) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && - !(t->flags & TF_ONE_WAY)) { - binder_send_failed_reply(t, BR_DEAD_REPLY); - } else { - binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered transaction %d\n", - t->debug_id); - t->buffer->transaction = NULL; - kfree(t); - binder_stats_deleted(BINDER_STAT_TRANSACTION); - } + + binder_cleanup_transaction(t, "process died.", + BR_DEAD_REPLY); + } break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered TRANSACTION_ERROR: %u\n", + e->cmd); } break; case BINDER_WORK_TRANSACTION_COMPLETE: { binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, @@ -3097,7 +4402,8 @@ static void binder_release_work(struct list_head *list) } -static struct binder_thread *binder_get_thread(struct binder_proc *proc) +static struct binder_thread *binder_get_thread_ilocked( + struct binder_proc *proc, struct binder_thread *new_thread) { struct binder_thread *thread = NULL; struct rb_node *parent = NULL; @@ -3112,38 +4418,102 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) else if (current->pid > thread->pid) p = &(*p)->rb_right; else - break; + return thread; } - if (*p == NULL) { - thread = kzalloc_preempt_disabled(sizeof(*thread)); - if (thread == NULL) + if (!new_thread) + return NULL; + thread = new_thread; + binder_stats_created(BINDER_STAT_THREAD); + thread->proc = proc; + thread->pid = current->pid; + get_task_struct(current); + thread->task = current; + atomic_set(&thread->tmp_ref, 0); + init_waitqueue_head(&thread->wait); + INIT_LIST_HEAD(&thread->todo); + rb_link_node(&thread->rb_node, parent, p); + rb_insert_color(&thread->rb_node, &proc->threads); + thread->looper_need_return = true; + thread->return_error.work.type = BINDER_WORK_RETURN_ERROR; + thread->return_error.cmd = BR_OK; + thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; + thread->reply_error.cmd = BR_OK; + INIT_LIST_HEAD(&new_thread->waiting_thread_node); + return thread; +} + +static struct binder_thread *binder_get_thread(struct binder_proc *proc) +{ + struct binder_thread *thread; + struct binder_thread *new_thread; + + binder_inner_proc_lock(proc); + thread = binder_get_thread_ilocked(proc, NULL); + binder_inner_proc_unlock(proc); + if (!thread) { + new_thread = kzalloc(sizeof(*thread), GFP_KERNEL); + if (new_thread == NULL) return NULL; - binder_stats_created(BINDER_STAT_THREAD); - thread->proc = proc; - thread->pid = current->pid; - init_waitqueue_head(&thread->wait); - INIT_LIST_HEAD(&thread->todo); - rb_link_node(&thread->rb_node, parent, p); - rb_insert_color(&thread->rb_node, &proc->threads); - thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; - thread->return_error = BR_OK; - thread->return_error2 = BR_OK; + binder_inner_proc_lock(proc); + thread = binder_get_thread_ilocked(proc, new_thread); + binder_inner_proc_unlock(proc); + if (thread != new_thread) + kfree(new_thread); } return thread; } -static int binder_free_thread(struct binder_proc *proc, - struct binder_thread *thread) +static void binder_free_proc(struct binder_proc *proc) +{ + BUG_ON(!list_empty(&proc->todo)); + BUG_ON(!list_empty(&proc->delivered_death)); + binder_alloc_deferred_release(&proc->alloc); + put_task_struct(proc->tsk); + binder_stats_deleted(BINDER_STAT_PROC); + kfree(proc); +} + +static void binder_free_thread(struct binder_thread *thread) +{ + BUG_ON(!list_empty(&thread->todo)); + binder_stats_deleted(BINDER_STAT_THREAD); + binder_proc_dec_tmpref(thread->proc); + put_task_struct(thread->task); + kfree(thread); +} + +static int binder_thread_release(struct binder_proc *proc, + struct binder_thread *thread) { struct binder_transaction *t; struct binder_transaction *send_reply = NULL; int active_transactions = 0; + struct binder_transaction *last_t = NULL; + binder_inner_proc_lock(thread->proc); + /* + * take a ref on the proc so it survives + * after we remove this thread from proc->threads. + * The corresponding dec is when we actually + * free the thread in binder_free_thread() + */ + proc->tmp_ref++; + /* + * take a ref on this thread to ensure it + * survives while we are releasing it + */ + atomic_inc(&thread->tmp_ref); rb_erase(&thread->rb_node, &proc->threads); t = thread->transaction_stack; - if (t && t->to_thread == thread) - send_reply = t; + if (t) { + spin_lock(&t->lock); + if (t->to_thread == thread) + send_reply = t; + } + thread->is_dead = true; + while (t) { + last_t = t; active_transactions++; binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, "release %d:%d transaction %d %s, still active\n", @@ -3164,12 +4534,16 @@ static int binder_free_thread(struct binder_proc *proc, t = t->from_parent; } else BUG(); + spin_unlock(&last_t->lock); + if (t) + spin_lock(&t->lock); } + binder_inner_proc_unlock(thread->proc); + if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); - binder_release_work(&thread->todo); - kfree(thread); - binder_stats_deleted(BINDER_STAT_THREAD); + binder_release_work(proc, &thread->todo); + binder_thread_dec_tmpref(thread); return active_transactions; } @@ -3178,30 +4552,21 @@ static unsigned int binder_poll(struct file *filp, { struct binder_proc *proc = filp->private_data; struct binder_thread *thread = NULL; - int wait_for_proc_work; - - binder_lock(__func__); + bool wait_for_proc_work; thread = binder_get_thread(proc); - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo) && thread->return_error == BR_OK; + binder_inner_proc_lock(thread->proc); + thread->looper |= BINDER_LOOPER_STATE_POLL; + wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); - binder_unlock(__func__); + binder_inner_proc_unlock(thread->proc); + + poll_wait(filp, &thread->wait, wait); + + if (binder_has_work(thread, wait_for_proc_work)) + return POLLIN; - if (wait_for_proc_work) { - if (binder_has_proc_work(proc, thread)) - return POLLIN; - poll_wait(filp, &proc->wait, wait); - if (binder_has_proc_work(proc, thread)) - return POLLIN; - } else { - if (binder_has_thread_work(thread)) - return POLLIN; - poll_wait(filp, &thread->wait, wait); - if (binder_has_thread_work(thread)) - return POLLIN; - } return 0; } @@ -3219,7 +4584,7 @@ static int binder_ioctl_write_read(struct file *filp, ret = -EINVAL; goto out; } - if (copy_from_user_preempt_disabled(&bwr, ubuf, sizeof(bwr))) { + if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -3237,7 +4602,7 @@ static int binder_ioctl_write_read(struct file *filp, trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -3248,10 +4613,12 @@ static int binder_ioctl_write_read(struct file *filp, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); - if (!list_empty(&proc->todo)) - wake_up_interruptible(&proc->wait); + binder_inner_proc_lock(proc); + if (!binder_worklist_empty_ilocked(&proc->todo)) + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); if (ret < 0) { - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto out; } @@ -3261,7 +4628,7 @@ static int binder_ioctl_write_read(struct file *filp, proc->pid, thread->pid, (u64)bwr.write_consumed, (u64)bwr.write_size, (u64)bwr.read_consumed, (u64)bwr.read_size); - if (copy_to_user_preempt_disabled(ubuf, &bwr, sizeof(bwr))) { + if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto out; } @@ -3274,9 +4641,10 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) int ret = 0; struct binder_proc *proc = filp->private_data; struct binder_context *context = proc->context; - + struct binder_node *new_node; kuid_t curr_euid = current_euid(); + mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node) { pr_err("BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; @@ -3297,19 +4665,48 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) } else { context->binder_context_mgr_uid = curr_euid; } - context->binder_context_mgr_node = binder_new_node(proc, 0, 0); - if (!context->binder_context_mgr_node) { + new_node = binder_new_node(proc, NULL); + if (!new_node) { ret = -ENOMEM; goto out; } - context->binder_context_mgr_node->local_weak_refs++; - context->binder_context_mgr_node->local_strong_refs++; - context->binder_context_mgr_node->has_strong_ref = 1; - context->binder_context_mgr_node->has_weak_ref = 1; + binder_node_lock(new_node); + new_node->local_weak_refs++; + new_node->local_strong_refs++; + new_node->has_strong_ref = 1; + new_node->has_weak_ref = 1; + context->binder_context_mgr_node = new_node; + binder_node_unlock(new_node); + binder_put_node(new_node); out: + mutex_unlock(&context->context_mgr_node_lock); return ret; } +static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, + struct binder_node_debug_info *info) { + struct rb_node *n; + binder_uintptr_t ptr = info->ptr; + + memset(info, 0, sizeof(*info)); + + binder_inner_proc_lock(proc); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { + struct binder_node *node = rb_entry(n, struct binder_node, + rb_node); + if (node->ptr > ptr) { + info->ptr = node->ptr; + info->cookie = node->cookie; + info->has_strong_ref = node->has_strong_ref; + info->has_weak_ref = node->has_weak_ref; + break; + } + } + binder_inner_proc_unlock(proc); + + return 0; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; @@ -3321,17 +4718,14 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ - if (unlikely(current->mm != proc->vma_vm_mm)) { - pr_err("current mm mismatch proc mm\n"); - return -EINVAL; - } + binder_selftest_alloc(&proc->alloc); + trace_binder_ioctl(cmd, arg); ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) goto err_unlocked; - binder_lock(__func__); thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; @@ -3344,12 +4738,19 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ret) goto err; break; - case BINDER_SET_MAX_THREADS: - if (copy_from_user_preempt_disabled(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { + case BINDER_SET_MAX_THREADS: { + int max_threads; + + if (copy_from_user(&max_threads, ubuf, + sizeof(max_threads))) { ret = -EINVAL; goto err; } + binder_inner_proc_lock(proc); + proc->max_threads = max_threads; + binder_inner_proc_unlock(proc); break; + } case BINDER_SET_CONTEXT_MGR: ret = binder_ioctl_set_ctx_mgr(filp); if (ret) @@ -3358,7 +4759,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case BINDER_THREAD_EXIT: binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", proc->pid, thread->pid); - binder_free_thread(proc, thread); + binder_thread_release(proc, thread); thread = NULL; break; case BINDER_VERSION: { @@ -3368,8 +4769,27 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = -EINVAL; goto err; } - if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION, &ver->protocol_version)) { - ret = -EINVAL; + if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, + &ver->protocol_version)) { + ret = -EINVAL; + goto err; + } + break; + } + case BINDER_GET_NODE_DEBUG_INFO: { + struct binder_node_debug_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_node_debug_info(proc, &info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; goto err; } break; @@ -3381,8 +4801,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = 0; err: if (thread) - thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - binder_unlock(__func__); + thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); @@ -3411,9 +4830,7 @@ static void binder_vma_close(struct vm_area_struct *vma) proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); - proc->vma = NULL; - proc->vma_vm_mm = NULL; - binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); + binder_alloc_vma_close(&proc->alloc); } static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -3430,11 +4847,8 @@ static const struct vm_operations_struct binder_vm_ops = { static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; - - struct vm_struct *area; struct binder_proc *proc = filp->private_data; const char *failure_string; - struct binder_buffer *buffer; if (proc->tsk != current->group_leader) return -EINVAL; @@ -3443,8 +4857,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_end = vma->vm_start + SZ_4M; binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", - proc->pid, vma->vm_start, vma->vm_end, + "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", + __func__, proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, (unsigned long)pgprot_val(vma->vm_page_prot)); @@ -3454,77 +4868,13 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) goto err_bad_arg; } vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; - - mutex_lock(&binder_mmap_lock); - if (proc->buffer) { - ret = -EBUSY; - failure_string = "already mapped"; - goto err_already_mapped; - } - - area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); - if (area == NULL) { - ret = -ENOMEM; - failure_string = "get_vm_area"; - goto err_get_vm_area_failed; - } - proc->buffer = area->addr; - proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; - mutex_unlock(&binder_mmap_lock); - -#ifdef CONFIG_CPU_CACHE_VIPT - if (cache_is_vipt_aliasing()) { - while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { - pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); - vma->vm_start += PAGE_SIZE; - } - } -#endif - proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); - if (proc->pages == NULL) { - ret = -ENOMEM; - failure_string = "alloc page array"; - goto err_alloc_pages_failed; - } - proc->buffer_size = vma->vm_end - vma->vm_start; - vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; - /* binder_update_page_range assumes preemption is disabled */ - preempt_disable(); - ret = binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma); - preempt_enable_no_resched(); - if (ret) { - ret = -ENOMEM; - failure_string = "alloc small buf"; - goto err_alloc_small_buf_failed; - } - buffer = proc->buffer; - INIT_LIST_HEAD(&proc->buffers); - list_add(&buffer->entry, &proc->buffers); - buffer->free = 1; - binder_insert_free_buffer(proc, buffer); - proc->free_async_space = proc->buffer_size / 2; - barrier(); - proc->files = get_files_struct(current); - proc->vma = vma; - proc->vma_vm_mm = vma->vm_mm; - - /*pr_info("binder_mmap: %d %lx-%lx maps %p\n", - proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ - return 0; + ret = binder_alloc_mmap_handler(&proc->alloc, vma); + + return ret; -err_alloc_small_buf_failed: - kfree(proc->pages); - proc->pages = NULL; -err_alloc_pages_failed: - mutex_lock(&binder_mmap_lock); - vfree(proc->buffer); - proc->buffer = NULL; -err_get_vm_area_failed: -err_already_mapped: - mutex_unlock(&binder_mmap_lock); err_bad_arg: pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); @@ -3542,25 +4892,33 @@ static int binder_open(struct inode *nodp, struct file *filp) proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) return -ENOMEM; + spin_lock_init(&proc->inner_lock); + spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); proc->tsk = current->group_leader; - proc->vma_vm_mm = current->group_leader->mm; INIT_LIST_HEAD(&proc->todo); - init_waitqueue_head(&proc->wait); - proc->default_priority = task_nice(current); + if (binder_supported_policy(current->policy)) { + proc->default_priority.sched_policy = current->policy; + proc->default_priority.prio = current->normal_prio; + } else { + proc->default_priority.sched_policy = SCHED_NORMAL; + proc->default_priority.prio = NICE_TO_PRIO(0); + } + binder_dev = container_of(filp->private_data, struct binder_device, miscdev); proc->context = &binder_dev->context; - - binder_lock(__func__); + binder_alloc_init(&proc->alloc); binder_stats_created(BINDER_STAT_PROC); - hlist_add_head(&proc->proc_node, &binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); + INIT_LIST_HEAD(&proc->waiting_threads); filp->private_data = proc; - binder_unlock(__func__); + mutex_lock(&binder_procs_lock); + hlist_add_head(&proc->proc_node, &binder_procs); + mutex_unlock(&binder_procs_lock); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; @@ -3596,16 +4954,17 @@ static void binder_deferred_flush(struct binder_proc *proc) struct rb_node *n; int wake_count = 0; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); - thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; + thread->looper_need_return = true; if (thread->looper & BINDER_LOOPER_STATE_WAITING) { wake_up_interruptible(&thread->wait); wake_count++; } } - wake_up_interruptible_all(&proc->wait); + binder_inner_proc_unlock(proc); binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_flush: %d woke %d threads\n", proc->pid, @@ -3626,13 +4985,21 @@ static int binder_node_release(struct binder_node *node, int refs) { struct binder_ref *ref; int death = 0; + struct binder_proc *proc = node->proc; - list_del_init(&node->work.entry); - binder_release_work(&node->async_todo); + binder_release_work(proc, &node->async_todo); - if (hlist_empty(&node->refs)) { - kfree(node); - binder_stats_deleted(BINDER_STAT_NODE); + binder_node_lock(node); + binder_inner_proc_lock(proc); + binder_dequeue_work_ilocked(&node->work); + /* + * The caller must have taken a temporary ref on the node, + */ + BUG_ON(!node->tmp_refs); + if (hlist_empty(&node->refs) && node->tmp_refs == 1) { + binder_inner_proc_unlock(proc); + binder_node_unlock(node); + binder_free_node(node); return refs; } @@ -3640,45 +5007,56 @@ static int binder_node_release(struct binder_node *node, int refs) node->proc = NULL; node->local_strong_refs = 0; node->local_weak_refs = 0; + binder_inner_proc_unlock(proc); + + spin_lock(&binder_dead_nodes_lock); hlist_add_head(&node->dead_node, &binder_dead_nodes); + spin_unlock(&binder_dead_nodes_lock); hlist_for_each_entry(ref, &node->refs, node_entry) { refs++; - - if (!ref->death) + /* + * Need the node lock to synchronize + * with new notification requests and the + * inner lock to synchronize with queued + * death notifications. + */ + binder_inner_proc_lock(ref->proc); + if (!ref->death) { + binder_inner_proc_unlock(ref->proc); continue; + } death++; - if (list_empty(&ref->death->work.entry)) { - ref->death->work.type = BINDER_WORK_DEAD_BINDER; - list_add_tail(&ref->death->work.entry, - &ref->proc->todo); - wake_up_interruptible(&ref->proc->wait); - } else - BUG(); + BUG_ON(!list_empty(&ref->death->work.entry)); + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + binder_enqueue_work_ilocked(&ref->death->work, + &ref->proc->todo); + binder_wakeup_proc_ilocked(ref->proc); + binder_inner_proc_unlock(ref->proc); } binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); + binder_node_unlock(node); + binder_put_node(node); return refs; } static void binder_deferred_release(struct binder_proc *proc) { - struct binder_transaction *t; struct binder_context *context = proc->context; struct rb_node *n; - int threads, nodes, incoming_refs, outgoing_refs, buffers, - active_transactions, page_count; - - BUG_ON(proc->vma); - BUG_ON(proc->files); + int threads, nodes, incoming_refs, outgoing_refs, active_transactions; + mutex_lock(&binder_procs_lock); hlist_del(&proc->proc_node); + mutex_unlock(&binder_procs_lock); + mutex_lock(&context->context_mgr_node_lock); if (context->binder_context_mgr_node && context->binder_context_mgr_node->proc == proc) { binder_debug(BINDER_DEBUG_DEAD_BINDER, @@ -3686,15 +5064,25 @@ static void binder_deferred_release(struct binder_proc *proc) __func__, proc->pid); context->binder_context_mgr_node = NULL; } + mutex_unlock(&context->context_mgr_node_lock); + binder_inner_proc_lock(proc); + /* + * Make sure proc stays alive after we + * remove all the threads + */ + proc->tmp_ref++; + proc->is_dead = true; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { struct binder_thread *thread; thread = rb_entry(n, struct binder_thread, rb_node); + binder_inner_proc_unlock(proc); threads++; - active_transactions += binder_free_thread(proc, thread); + active_transactions += binder_thread_release(proc, thread); + binder_inner_proc_lock(proc); } nodes = 0; @@ -3704,89 +5092,51 @@ static void binder_deferred_release(struct binder_proc *proc) node = rb_entry(n, struct binder_node, rb_node); nodes++; + /* + * take a temporary ref on the node before + * calling binder_node_release() which will either + * kfree() the node or call binder_put_node() + */ + binder_inc_node_tmpref_ilocked(node); rb_erase(&node->rb_node, &proc->nodes); + binder_inner_proc_unlock(proc); incoming_refs = binder_node_release(node, incoming_refs); + binder_inner_proc_lock(proc); } + binder_inner_proc_unlock(proc); outgoing_refs = 0; + binder_proc_lock(proc); while ((n = rb_first(&proc->refs_by_desc))) { struct binder_ref *ref; ref = rb_entry(n, struct binder_ref, rb_node_desc); outgoing_refs++; - binder_delete_ref(ref); - } - - binder_release_work(&proc->todo); - binder_release_work(&proc->delivered_death); - - buffers = 0; - while ((n = rb_first(&proc->allocated_buffers))) { - struct binder_buffer *buffer; - - buffer = rb_entry(n, struct binder_buffer, rb_node); - - t = buffer->transaction; - if (t) { - t->buffer = NULL; - buffer->transaction = NULL; - pr_err("release proc %d, transaction %d, not freed\n", - proc->pid, t->debug_id); - /*BUG();*/ - } - - binder_free_buf(proc, buffer); - buffers++; - } - - binder_stats_deleted(BINDER_STAT_PROC); - - page_count = 0; - if (proc->pages) { - int i; - - for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { - void *page_addr; - - if (!proc->pages[i]) - continue; - - page_addr = proc->buffer + i * PAGE_SIZE; - binder_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%s: %d: page %d at %p not freed\n", - __func__, proc->pid, i, page_addr); - unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); - __free_page(proc->pages[i]); - page_count++; - } - kfree(proc->pages); - vfree(proc->buffer); + binder_cleanup_ref_olocked(ref); + binder_proc_unlock(proc); + binder_free_ref(ref); + binder_proc_lock(proc); } + binder_proc_unlock(proc); - put_task_struct(proc->tsk); + binder_release_work(proc, &proc->todo); + binder_release_work(proc, &proc->delivered_death); binder_debug(BINDER_DEBUG_OPEN_CLOSE, - "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", + "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", __func__, proc->pid, threads, nodes, incoming_refs, - outgoing_refs, active_transactions, buffers, page_count); + outgoing_refs, active_transactions); - kfree(proc); + binder_proc_dec_tmpref(proc); } static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; - struct files_struct *files; - int defer; do { - trace_binder_lock(__func__); - mutex_lock(&binder_main_lock); - trace_binder_locked(__func__); - mutex_lock(&binder_deferred_lock); - preempt_disable(); if (!hlist_empty(&binder_deferred_list)) { proc = hlist_entry(binder_deferred_list.first, struct binder_proc, deferred_work_node); @@ -3799,24 +5149,11 @@ static void binder_deferred_func(struct work_struct *work) } mutex_unlock(&binder_deferred_lock); - files = NULL; - if (defer & BINDER_DEFERRED_PUT_FILES) { - files = proc->files; - if (files) - proc->files = NULL; - } - if (defer & BINDER_DEFERRED_FLUSH) binder_deferred_flush(proc); if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - - trace_binder_unlock(__func__); - mutex_unlock(&binder_main_lock); - preempt_enable_no_resched(); - if (files) - put_files_struct(files); } while (proc); } static DECLARE_WORK(binder_deferred_work, binder_deferred_func); @@ -3834,41 +5171,52 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) mutex_unlock(&binder_deferred_lock); } -static void print_binder_transaction(struct seq_file *m, const char *prefix, - struct binder_transaction *t) +static void print_binder_transaction_ilocked(struct seq_file *m, + struct binder_proc *proc, + const char *prefix, + struct binder_transaction *t) { + struct binder_proc *to_proc; + struct binder_buffer *buffer = t->buffer; + + spin_lock(&t->lock); + to_proc = t->to_proc; seq_printf(m, - "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", + "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %d:%d r%d", prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, - t->to_proc ? t->to_proc->pid : 0, + to_proc ? to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority, t->need_reply); - if (t->buffer == NULL) { + t->code, t->flags, t->priority.sched_policy, + t->priority.prio, t->need_reply); + spin_unlock(&t->lock); + + if (proc != to_proc) { + /* + * Can only safely deref buffer if we are holding the + * correct proc inner lock for this node + */ + seq_puts(m, "\n"); + return; + } + + if (buffer == NULL) { seq_puts(m, " buffer free\n"); return; } - if (t->buffer->target_node) - seq_printf(m, " node %d", - t->buffer->target_node->debug_id); + if (buffer->target_node) + seq_printf(m, " node %d", buffer->target_node->debug_id); seq_printf(m, " size %zd:%zd data %p\n", - t->buffer->data_size, t->buffer->offsets_size, - t->buffer->data); -} - -static void print_binder_buffer(struct seq_file *m, const char *prefix, - struct binder_buffer *buffer) -{ - seq_printf(m, "%s %d: %p size %zd:%zd %s\n", - prefix, buffer->debug_id, buffer->data, buffer->data_size, buffer->offsets_size, - buffer->transaction ? "active" : "delivered"); + buffer->data); } -static void print_binder_work(struct seq_file *m, const char *prefix, - const char *transaction_prefix, - struct binder_work *w) +static void print_binder_work_ilocked(struct seq_file *m, + struct binder_proc *proc, + const char *prefix, + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -3876,8 +5224,16 @@ static void print_binder_work(struct seq_file *m, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); - print_binder_transaction(m, transaction_prefix, t); + print_binder_transaction_ilocked( + m, proc, transaction_prefix, t); break; + case BINDER_WORK_RETURN_ERROR: { + struct binder_error *e = container_of( + w, struct binder_error, work); + + seq_printf(m, "%stransaction error: %u\n", + prefix, e->cmd); + } break; case BINDER_WORK_TRANSACTION_COMPLETE: seq_printf(m, "%stransaction complete\n", prefix); break; @@ -3902,40 +5258,46 @@ static void print_binder_work(struct seq_file *m, const char *prefix, } } -static void print_binder_thread(struct seq_file *m, - struct binder_thread *thread, - int print_always) +static void print_binder_thread_ilocked(struct seq_file *m, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; size_t start_pos = m->count; size_t header_pos; - seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); + seq_printf(m, " thread %d: l %02x need_return %d tr %d\n", + thread->pid, thread->looper, + thread->looper_need_return, + atomic_read(&thread->tmp_ref)); header_pos = m->count; t = thread->transaction_stack; while (t) { if (t->from == thread) { - print_binder_transaction(m, - " outgoing transaction", t); + print_binder_transaction_ilocked(m, thread->proc, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - print_binder_transaction(m, + print_binder_transaction_ilocked(m, thread->proc, " incoming transaction", t); t = t->to_parent; } else { - print_binder_transaction(m, " bad transaction", t); + print_binder_transaction_ilocked(m, thread->proc, + " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { - print_binder_work(m, " ", " pending transaction", w); + print_binder_work_ilocked(m, thread->proc, " ", + " pending transaction", w); } if (!print_always && m->count == header_pos) m->count = start_pos; } -static void print_binder_node(struct seq_file *m, struct binder_node *node) +static void print_binder_node_nilocked(struct seq_file *m, + struct binder_node *node) { struct binder_ref *ref; struct binder_work *w; @@ -3945,27 +5307,35 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d", node->debug_id, (u64)node->ptr, (u64)node->cookie, + node->sched_policy, node->min_priority, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, - node->internal_strong_refs, count); + node->internal_strong_refs, count, node->tmp_refs); if (count) { seq_puts(m, " proc"); hlist_for_each_entry(ref, &node->refs, node_entry) seq_printf(m, " %d", ref->proc->pid); } seq_puts(m, "\n"); - list_for_each_entry(w, &node->async_todo, entry) - print_binder_work(m, " ", - " pending async transaction", w); + if (node->proc) { + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work_ilocked(m, node->proc, " ", + " pending async transaction", w); + } } -static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) +static void print_binder_ref_olocked(struct seq_file *m, + struct binder_ref *ref) { - seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", - ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", - ref->node->debug_id, ref->strong, ref->weak, ref->death); + binder_node_lock(ref->node); + seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n", + ref->data.debug_id, ref->data.desc, + ref->node->proc ? "" : "dead ", + ref->node->debug_id, ref->data.strong, + ref->data.weak, ref->death); + binder_node_unlock(ref->node); } static void print_binder_proc(struct seq_file *m, @@ -3975,36 +5345,60 @@ static void print_binder_proc(struct seq_file *m, struct rb_node *n; size_t start_pos = m->count; size_t header_pos; + struct binder_node *last_node = NULL; seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); header_pos = m->count; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) - print_binder_thread(m, rb_entry(n, struct binder_thread, + print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, rb_node), print_all); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); - if (print_all || node->has_async_transaction) - print_binder_node(m, node); - } + /* + * take a temporary reference on the node so it + * survives and isn't removed from the tree + * while we print it. + */ + binder_inc_node_tmpref_ilocked(node); + /* Need to drop inner lock to take node lock */ + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + binder_node_inner_lock(node); + print_binder_node_nilocked(m, node); + binder_node_inner_unlock(node); + last_node = node; + binder_inner_proc_lock(proc); + } + binder_inner_proc_unlock(proc); + if (last_node) + binder_put_node(last_node); + if (print_all) { + binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) - print_binder_ref(m, rb_entry(n, struct binder_ref, - rb_node_desc)); + print_binder_ref_olocked(m, rb_entry(n, + struct binder_ref, + rb_node_desc)); + binder_proc_unlock(proc); } - for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) - print_binder_buffer(m, " buffer", - rb_entry(n, struct binder_buffer, rb_node)); + binder_alloc_print_allocated(m, &proc->alloc); + binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) - print_binder_work(m, " ", " pending transaction", w); + print_binder_work_ilocked(m, proc, " ", + " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { seq_puts(m, " has delivered dead binder\n"); break; } + binder_inner_proc_unlock(proc); if (!print_all && m->count == header_pos) m->count = start_pos; } @@ -4070,17 +5464,21 @@ static void print_binder_stats(struct seq_file *m, const char *prefix, BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { - if (stats->bc[i]) + int temp = atomic_read(&stats->bc[i]); + + if (temp) seq_printf(m, "%s%s: %d\n", prefix, - binder_command_strings[i], stats->bc[i]); + binder_command_strings[i], temp); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { - if (stats->br[i]) + int temp = atomic_read(&stats->br[i]); + + if (temp) seq_printf(m, "%s%s: %d\n", prefix, - binder_return_strings[i], stats->br[i]); + binder_return_strings[i], temp); } BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != @@ -4088,11 +5486,15 @@ static void print_binder_stats(struct seq_file *m, const char *prefix, BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != ARRAY_SIZE(stats->obj_deleted)); for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { - if (stats->obj_created[i] || stats->obj_deleted[i]) - seq_printf(m, "%s%s: active %d total %d\n", prefix, + int created = atomic_read(&stats->obj_created[i]); + int deleted = atomic_read(&stats->obj_deleted[i]); + + if (created || deleted) + seq_printf(m, "%s%s: active %d total %d\n", + prefix, binder_objstat_strings[i], - stats->obj_created[i] - stats->obj_deleted[i], - stats->obj_created[i]); + created - deleted, + created); } } @@ -4100,51 +5502,61 @@ static void print_binder_proc_stats(struct seq_file *m, struct binder_proc *proc) { struct binder_work *w; + struct binder_thread *thread; struct rb_node *n; - int count, strong, weak; + int count, strong, weak, ready_threads; + size_t free_async_space = + binder_alloc_get_free_async_space(&proc->alloc); seq_printf(m, "proc %d\n", proc->pid); seq_printf(m, "context %s\n", proc->context->name); count = 0; + ready_threads = 0; + binder_inner_proc_lock(proc); for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; + + list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node) + ready_threads++; + seq_printf(m, " threads: %d\n", count); seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, - proc->ready_threads, proc->free_async_space); + ready_threads, + free_async_space); count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; + binder_inner_proc_unlock(proc); seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; + binder_proc_lock(proc); for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); count++; - strong += ref->strong; - weak += ref->weak; + strong += ref->data.strong; + weak += ref->data.weak; } + binder_proc_unlock(proc); seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); - count = 0; - for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) - count++; + count = binder_alloc_get_allocated_count(&proc->alloc); seq_printf(m, " buffers: %d\n", count); + binder_alloc_print_pages(m, &proc->alloc); + count = 0; + binder_inner_proc_lock(proc); list_for_each_entry(w, &proc->todo, entry) { - switch (w->type) { - case BINDER_WORK_TRANSACTION: + if (w->type == BINDER_WORK_TRANSACTION) count++; - break; - default: - break; - } } + binder_inner_proc_unlock(proc); seq_printf(m, " pending transactions: %d\n", count); print_binder_stats(m, " ", &proc->stats); @@ -4155,57 +5567,67 @@ static int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct binder_node *node; - int do_lock = !binder_debug_no_lock; - - if (do_lock) - binder_lock(__func__); + struct binder_node *last_node = NULL; seq_puts(m, "binder state:\n"); + spin_lock(&binder_dead_nodes_lock); if (!hlist_empty(&binder_dead_nodes)) seq_puts(m, "dead nodes:\n"); - hlist_for_each_entry(node, &binder_dead_nodes, dead_node) - print_binder_node(m, node); - + hlist_for_each_entry(node, &binder_dead_nodes, dead_node) { + /* + * take a temporary reference on the node so it + * survives and isn't removed from the list + * while we print it. + */ + node->tmp_refs++; + spin_unlock(&binder_dead_nodes_lock); + if (last_node) + binder_put_node(last_node); + binder_node_lock(node); + print_binder_node_nilocked(m, node); + binder_node_unlock(node); + last_node = node; + spin_lock(&binder_dead_nodes_lock); + } + spin_unlock(&binder_dead_nodes_lock); + if (last_node) + binder_put_node(last_node); + + mutex_lock(&binder_procs_lock); hlist_for_each_entry(proc, &binder_procs, proc_node) print_binder_proc(m, proc, 1); - if (do_lock) - binder_unlock(__func__); + mutex_unlock(&binder_procs_lock); + return 0; } static int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; - int do_lock = !binder_debug_no_lock; - - if (do_lock) - binder_lock(__func__); seq_puts(m, "binder stats:\n"); print_binder_stats(m, "", &binder_stats); + mutex_lock(&binder_procs_lock); hlist_for_each_entry(proc, &binder_procs, proc_node) print_binder_proc_stats(m, proc); - if (do_lock) - binder_unlock(__func__); + mutex_unlock(&binder_procs_lock); + return 0; } static int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; - int do_lock = !binder_debug_no_lock; - - if (do_lock) - binder_lock(__func__); seq_puts(m, "binder transactions:\n"); + mutex_lock(&binder_procs_lock); hlist_for_each_entry(proc, &binder_procs, proc_node) print_binder_proc(m, proc, 0); - if (do_lock) - binder_unlock(__func__); + mutex_unlock(&binder_procs_lock); + return 0; } @@ -4213,44 +5635,63 @@ static int binder_proc_show(struct seq_file *m, void *unused) { struct binder_proc *itr; int pid = (unsigned long)m->private; - int do_lock = !binder_debug_no_lock; - - if (do_lock) - binder_lock(__func__); + mutex_lock(&binder_procs_lock); hlist_for_each_entry(itr, &binder_procs, proc_node) { if (itr->pid == pid) { seq_puts(m, "binder proc state:\n"); print_binder_proc(m, itr, 1); } } - if (do_lock) - binder_unlock(__func__); + mutex_unlock(&binder_procs_lock); + return 0; } static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { + int debug_id = READ_ONCE(e->debug_id_done); + /* + * read barrier to guarantee debug_id_done read before + * we print the log values + */ + smp_rmb(); seq_printf(m, - "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d\n", + "%d: %s from %d:%d to %d:%d context %s node %d handle %d size %d:%d ret %d/%d l=%d", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->context_name, - e->to_node, e->target_handle, e->data_size, e->offsets_size); + e->to_node, e->target_handle, e->data_size, e->offsets_size, + e->return_error, e->return_error_param, + e->return_error_line); + /* + * read-barrier to guarantee read of debug_id_done after + * done printing the fields of the entry + */ + smp_rmb(); + seq_printf(m, debug_id && debug_id == READ_ONCE(e->debug_id_done) ? + "\n" : " (incomplete)\n"); } static int binder_transaction_log_show(struct seq_file *m, void *unused) { struct binder_transaction_log *log = m->private; + unsigned int log_cur = atomic_read(&log->cur); + unsigned int count; + unsigned int cur; int i; - if (log->full) { - for (i = log->next; i < ARRAY_SIZE(log->entry); i++) - print_binder_transaction_log_entry(m, &log->entry[i]); + count = log_cur + 1; + cur = count < ARRAY_SIZE(log->entry) && !log->full ? + 0 : count % ARRAY_SIZE(log->entry); + if (count > ARRAY_SIZE(log->entry) || log->full) + count = ARRAY_SIZE(log->entry); + for (i = 0; i < count; i++) { + unsigned int index = cur++ % ARRAY_SIZE(log->entry); + + print_binder_transaction_log_entry(m, &log->entry[index]); } - for (i = 0; i < log->next; i++) - print_binder_transaction_log_entry(m, &log->entry[i]); return 0; } @@ -4285,6 +5726,7 @@ static int __init init_binder_device(const char *name) binder_device->context.binder_context_mgr_uid = INVALID_UID; binder_device->context.name = name; + mutex_init(&binder_device->context.context_mgr_node_lock); ret = misc_register(&binder_device->miscdev); if (ret < 0) { @@ -4304,6 +5746,11 @@ static int __init binder_init(void) struct binder_device *device; struct hlist_node *tmp; + binder_alloc_shrinker_init(); + + atomic_set(&binder_transaction_log.cur, ~0U); + atomic_set(&binder_transaction_log_failed.cur, ~0U); + binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); if (binder_debugfs_dir_entry_root) binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c new file mode 100644 index 0000000000000000000000000000000000000000..3ad1bcf391217aa0ca7f18c8f465b2b710998259 --- /dev/null +++ b/drivers/android/binder_alloc.c @@ -0,0 +1,1011 @@ +/* binder_alloc.c + * + * Android IPC Subsystem + * + * Copyright (C) 2007-2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "binder_alloc.h" +#include "binder_trace.h" + +struct list_lru binder_alloc_lru; + +static DEFINE_MUTEX(binder_alloc_mmap_lock); + +enum { + BINDER_DEBUG_OPEN_CLOSE = 1U << 1, + BINDER_DEBUG_BUFFER_ALLOC = 1U << 2, + BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 3, +}; +static uint32_t binder_alloc_debug_mask; + +module_param_named(debug_mask, binder_alloc_debug_mask, + uint, 0644); + +#define binder_alloc_debug(mask, x...) \ + do { \ + if (binder_alloc_debug_mask & mask) \ + pr_info(x); \ + } while (0) + +static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) +{ + return list_entry(buffer->entry.next, struct binder_buffer, entry); +} + +static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) +{ + return list_entry(buffer->entry.prev, struct binder_buffer, entry); +} + +static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + if (list_is_last(&buffer->entry, &alloc->buffers)) + return (u8 *)alloc->buffer + + alloc->buffer_size - (u8 *)buffer->data; + return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data; +} + +static void binder_insert_free_buffer(struct binder_alloc *alloc, + struct binder_buffer *new_buffer) +{ + struct rb_node **p = &alloc->free_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + size_t buffer_size; + size_t new_buffer_size; + + BUG_ON(!new_buffer->free); + + new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: add free buffer, size %zd, at %pK\n", + alloc->pid, new_buffer_size, new_buffer); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + if (new_buffer_size < buffer_size) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &alloc->free_buffers); +} + +static void binder_insert_allocated_buffer_locked( + struct binder_alloc *alloc, struct binder_buffer *new_buffer) +{ + struct rb_node **p = &alloc->allocated_buffers.rb_node; + struct rb_node *parent = NULL; + struct binder_buffer *buffer; + + BUG_ON(new_buffer->free); + + while (*p) { + parent = *p; + buffer = rb_entry(parent, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (new_buffer->data < buffer->data) + p = &parent->rb_left; + else if (new_buffer->data > buffer->data) + p = &parent->rb_right; + else + BUG(); + } + rb_link_node(&new_buffer->rb_node, parent, p); + rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers); +} + +static struct binder_buffer *binder_alloc_prepare_to_free_locked( + struct binder_alloc *alloc, + uintptr_t user_ptr) +{ + struct rb_node *n = alloc->allocated_buffers.rb_node; + struct binder_buffer *buffer; + void *kern_ptr; + + kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(buffer->free); + + if (kern_ptr < buffer->data) + n = n->rb_left; + else if (kern_ptr > buffer->data) + n = n->rb_right; + else { + /* + * Guard against user threads attempting to + * free the buffer twice + */ + if (buffer->free_in_progress) { + pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", + alloc->pid, current->pid, (u64)user_ptr); + return NULL; + } + buffer->free_in_progress = 1; + return buffer; + } + } + return NULL; +} + +/** + * binder_alloc_buffer_lookup() - get buffer given user ptr + * @alloc: binder_alloc for this proc + * @user_ptr: User pointer to buffer data + * + * Validate userspace pointer to buffer data and return buffer corresponding to + * that user pointer. Search the rb tree for buffer that matches user data + * pointer. + * + * Return: Pointer to buffer or NULL + */ +struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, + uintptr_t user_ptr) +{ + struct binder_buffer *buffer; + + mutex_lock(&alloc->mutex); + buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); + mutex_unlock(&alloc->mutex); + return buffer; +} + +static int binder_update_page_range(struct binder_alloc *alloc, int allocate, + void *start, void *end) +{ + void *page_addr; + unsigned long user_page_addr; + struct binder_lru_page *page; + struct vm_area_struct *vma = NULL; + struct mm_struct *mm = NULL; + bool need_mm = false; + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: %s pages %pK-%pK\n", alloc->pid, + allocate ? "allocate" : "free", start, end); + + if (end <= start) + return 0; + + trace_binder_update_page_range(alloc, allocate, start, end); + + if (allocate == 0) + goto free_range; + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; + if (!page->page_ptr) { + need_mm = true; + break; + } + } + + if (need_mm && mmget_not_zero(alloc->vma_vm_mm)) + mm = alloc->vma_vm_mm; + + if (mm) { + down_write(&mm->mmap_sem); + vma = alloc->vma; + } + + if (!vma && need_mm) { + pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", + alloc->pid); + goto err_no_vma; + } + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + int ret; + bool on_lru; + size_t index; + + index = (page_addr - alloc->buffer) / PAGE_SIZE; + page = &alloc->pages[index]; + + if (page->page_ptr) { + trace_binder_alloc_lru_start(alloc, index); + + on_lru = list_lru_del(&binder_alloc_lru, &page->lru); + WARN_ON(!on_lru); + + trace_binder_alloc_lru_end(alloc, index); + continue; + } + + if (WARN_ON(!vma)) + goto err_page_ptr_cleared; + + trace_binder_alloc_page_start(alloc, index); + page->page_ptr = alloc_page(GFP_KERNEL | + __GFP_HIGHMEM | + __GFP_ZERO); + if (!page->page_ptr) { + pr_err("%d: binder_alloc_buf failed for page at %pK\n", + alloc->pid, page_addr); + goto err_alloc_page_failed; + } + page->alloc = alloc; + INIT_LIST_HEAD(&page->lru); + + ret = map_kernel_range_noflush((unsigned long)page_addr, + PAGE_SIZE, PAGE_KERNEL, + &page->page_ptr); + flush_cache_vmap((unsigned long)page_addr, + (unsigned long)page_addr + PAGE_SIZE); + if (ret != 1) { + pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", + alloc->pid, page_addr); + goto err_map_kernel_failed; + } + user_page_addr = + (uintptr_t)page_addr + alloc->user_buffer_offset; + ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr); + if (ret) { + pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", + alloc->pid, user_page_addr); + goto err_vm_insert_page_failed; + } + + trace_binder_alloc_page_end(alloc, index); + /* vm_insert_page does not seem to increment the refcount */ + } + if (mm) { + up_write(&mm->mmap_sem); + mmput(mm); + } + return 0; + +free_range: + for (page_addr = end - PAGE_SIZE; page_addr >= start; + page_addr -= PAGE_SIZE) { + bool ret; + size_t index; + + index = (page_addr - alloc->buffer) / PAGE_SIZE; + page = &alloc->pages[index]; + + trace_binder_free_lru_start(alloc, index); + + ret = list_lru_add(&binder_alloc_lru, &page->lru); + WARN_ON(!ret); + + trace_binder_free_lru_end(alloc, index); + continue; + +err_vm_insert_page_failed: + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); +err_map_kernel_failed: + __free_page(page->page_ptr); + page->page_ptr = NULL; +err_alloc_page_failed: +err_page_ptr_cleared: + ; + } +err_no_vma: + if (mm) { + up_write(&mm->mmap_sem); + mmput(mm); + } + return vma ? -ENOMEM : -ESRCH; +} + +struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) +{ + struct rb_node *n = alloc->free_buffers.rb_node; + struct binder_buffer *buffer; + size_t buffer_size; + struct rb_node *best_fit = NULL; + void *has_page_addr; + void *end_page_addr; + size_t size, data_offsets_size; + int ret; + + if (alloc->vma == NULL) { + pr_err("%d: binder_alloc_buf, no vma\n", + alloc->pid); + return ERR_PTR(-ESRCH); + } + + data_offsets_size = ALIGN(data_size, sizeof(void *)) + + ALIGN(offsets_size, sizeof(void *)); + + if (data_offsets_size < data_size || data_offsets_size < offsets_size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid size %zd-%zd\n", + alloc->pid, data_size, offsets_size); + return ERR_PTR(-EINVAL); + } + size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); + if (size < data_offsets_size || size < extra_buffers_size) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid extra_buffers_size %zd\n", + alloc->pid, extra_buffers_size); + return ERR_PTR(-EINVAL); + } + if (is_async && + alloc->free_async_space < size + sizeof(struct binder_buffer)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd failed, no async space left\n", + alloc->pid, size); + return ERR_PTR(-ENOSPC); + } + + /* Pad 0-size buffers so they get assigned unique addresses */ + size = max(size, sizeof(void *)); + + while (n) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + BUG_ON(!buffer->free); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + if (size < buffer_size) { + best_fit = n; + n = n->rb_left; + } else if (size > buffer_size) + n = n->rb_right; + else { + best_fit = n; + break; + } + } + if (best_fit == NULL) { + size_t allocated_buffers = 0; + size_t largest_alloc_size = 0; + size_t total_alloc_size = 0; + size_t free_buffers = 0; + size_t largest_free_size = 0; + size_t total_free_size = 0; + + for (n = rb_first(&alloc->allocated_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + allocated_buffers++; + total_alloc_size += buffer_size; + if (buffer_size > largest_alloc_size) + largest_alloc_size = buffer_size; + } + for (n = rb_first(&alloc->free_buffers); n != NULL; + n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + free_buffers++; + total_free_size += buffer_size; + if (buffer_size > largest_free_size) + largest_free_size = buffer_size; + } + pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", + alloc->pid, size); + pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", + total_alloc_size, allocated_buffers, largest_alloc_size, + total_free_size, free_buffers, largest_free_size); + return ERR_PTR(-ENOSPC); + } + if (n == NULL) { + buffer = rb_entry(best_fit, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + } + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", + alloc->pid, size, buffer, buffer_size); + + has_page_addr = + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); + WARN_ON(n && buffer_size != size); + end_page_addr = + (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + if (end_page_addr > has_page_addr) + end_page_addr = has_page_addr; + ret = binder_update_page_range(alloc, 1, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr); + if (ret) + return ERR_PTR(ret); + + if (buffer_size != size) { + struct binder_buffer *new_buffer; + + new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!new_buffer) { + pr_err("%s: %d failed to alloc new buffer struct\n", + __func__, alloc->pid); + goto err_alloc_buf_struct_failed; + } + new_buffer->data = (u8 *)buffer->data + size; + list_add(&new_buffer->entry, &buffer->entry); + new_buffer->free = 1; + binder_insert_free_buffer(alloc, new_buffer); + } + + rb_erase(best_fit, &alloc->free_buffers); + buffer->free = 0; + buffer->free_in_progress = 0; + binder_insert_allocated_buffer_locked(alloc, buffer); + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got %pK\n", + alloc->pid, size, buffer); + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; + buffer->async_transaction = is_async; + buffer->extra_buffers_size = extra_buffers_size; + if (is_async) { + alloc->free_async_space -= size + sizeof(struct binder_buffer); + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_alloc_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); + } + return buffer; + +err_alloc_buf_struct_failed: + binder_update_page_range(alloc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + end_page_addr); + return ERR_PTR(-ENOMEM); +} + +/** + * binder_alloc_new_buf() - Allocate a new binder buffer + * @alloc: binder_alloc for this proc + * @data_size: size of user data buffer + * @offsets_size: user specified buffer offset + * @extra_buffers_size: size of extra space for meta-data (eg, security context) + * @is_async: buffer for async transaction + * + * Allocate a new buffer given the requested sizes. Returns + * the kernel version of the buffer pointer. The size allocated + * is the sum of the three given sizes (each rounded up to + * pointer-sized boundary) + * + * Return: The allocated buffer or %NULL if error + */ +struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) +{ + struct binder_buffer *buffer; + + mutex_lock(&alloc->mutex); + buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, + extra_buffers_size, is_async); + mutex_unlock(&alloc->mutex); + return buffer; +} + +static void *buffer_start_page(struct binder_buffer *buffer) +{ + return (void *)((uintptr_t)buffer->data & PAGE_MASK); +} + +static void *prev_buffer_end_page(struct binder_buffer *buffer) +{ + return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK); +} + +static void binder_delete_free_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + struct binder_buffer *prev, *next = NULL; + bool to_free = true; + BUG_ON(alloc->buffers.next == &buffer->entry); + prev = binder_buffer_prev(buffer); + BUG_ON(!prev->free); + if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { + to_free = false; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK share page with %pK\n", + alloc->pid, buffer->data, prev->data); + } + + if (!list_is_last(&buffer->entry, &alloc->buffers)) { + next = binder_buffer_next(buffer); + if (buffer_start_page(next) == buffer_start_page(buffer)) { + to_free = false; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK share page with %pK\n", + alloc->pid, + buffer->data, + next->data); + } + } + + if (PAGE_ALIGNED(buffer->data)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer start %pK is page aligned\n", + alloc->pid, buffer->data); + to_free = false; + } + + if (to_free) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %pK do not share page with %pK or %pK\n", + alloc->pid, buffer->data, + prev->data, next ? next->data : NULL); + binder_update_page_range(alloc, 0, buffer_start_page(buffer), + buffer_start_page(buffer) + PAGE_SIZE); + } + list_del(&buffer->entry); + kfree(buffer); +} + +static void binder_free_buf_locked(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + size_t size, buffer_size; + + buffer_size = binder_alloc_buffer_size(alloc, buffer); + + size = ALIGN(buffer->data_size, sizeof(void *)) + + ALIGN(buffer->offsets_size, sizeof(void *)) + + ALIGN(buffer->extra_buffers_size, sizeof(void *)); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_free_buf %pK size %zd buffer_size %zd\n", + alloc->pid, buffer, size, buffer_size); + + BUG_ON(buffer->free); + BUG_ON(size > buffer_size); + BUG_ON(buffer->transaction != NULL); + BUG_ON(buffer->data < alloc->buffer); + BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size); + + if (buffer->async_transaction) { + alloc->free_async_space += size + sizeof(struct binder_buffer); + + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_free_buf size %zd async free %zd\n", + alloc->pid, size, alloc->free_async_space); + } + + binder_update_page_range(alloc, 0, + (void *)PAGE_ALIGN((uintptr_t)buffer->data), + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK)); + + rb_erase(&buffer->rb_node, &alloc->allocated_buffers); + buffer->free = 1; + if (!list_is_last(&buffer->entry, &alloc->buffers)) { + struct binder_buffer *next = binder_buffer_next(buffer); + + if (next->free) { + rb_erase(&next->rb_node, &alloc->free_buffers); + binder_delete_free_buffer(alloc, next); + } + } + if (alloc->buffers.next != &buffer->entry) { + struct binder_buffer *prev = binder_buffer_prev(buffer); + + if (prev->free) { + binder_delete_free_buffer(alloc, buffer); + rb_erase(&prev->rb_node, &alloc->free_buffers); + buffer = prev; + } + } + binder_insert_free_buffer(alloc, buffer); +} + +/** + * binder_alloc_free_buf() - free a binder buffer + * @alloc: binder_alloc for this proc + * @buffer: kernel pointer to buffer + * + * Free the buffer allocated via binder_alloc_new_buffer() + */ +void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + mutex_lock(&alloc->mutex); + binder_free_buf_locked(alloc, buffer); + mutex_unlock(&alloc->mutex); +} + +/** + * binder_alloc_mmap_handler() - map virtual address space for proc + * @alloc: alloc structure for this proc + * @vma: vma passed to mmap() + * + * Called by binder_mmap() to initialize the space specified in + * vma for allocating binder buffers + * + * Return: + * 0 = success + * -EBUSY = address space already mapped + * -ENOMEM = failed to map memory to given address space + */ +int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma) +{ + int ret; + struct vm_struct *area; + const char *failure_string; + struct binder_buffer *buffer; + + mutex_lock(&binder_alloc_mmap_lock); + if (alloc->buffer) { + ret = -EBUSY; + failure_string = "already mapped"; + goto err_already_mapped; + } + + area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); + if (area == NULL) { + ret = -ENOMEM; + failure_string = "get_vm_area"; + goto err_get_vm_area_failed; + } + alloc->buffer = area->addr; + alloc->user_buffer_offset = + vma->vm_start - (uintptr_t)alloc->buffer; + mutex_unlock(&binder_alloc_mmap_lock); + +#ifdef CONFIG_CPU_CACHE_VIPT + if (cache_is_vipt_aliasing()) { + while (CACHE_COLOUR( + (vma->vm_start ^ (uint32_t)alloc->buffer))) { + pr_info("%s: %d %lx-%lx maps %pK bad alignment\n", + __func__, alloc->pid, vma->vm_start, + vma->vm_end, alloc->buffer); + vma->vm_start += PAGE_SIZE; + } + } +#endif + alloc->pages = kzalloc(sizeof(alloc->pages[0]) * + ((vma->vm_end - vma->vm_start) / PAGE_SIZE), + GFP_KERNEL); + if (alloc->pages == NULL) { + ret = -ENOMEM; + failure_string = "alloc page array"; + goto err_alloc_pages_failed; + } + alloc->buffer_size = vma->vm_end - vma->vm_start; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + failure_string = "alloc buffer struct"; + goto err_alloc_buf_struct_failed; + } + + buffer->data = alloc->buffer; + list_add(&buffer->entry, &alloc->buffers); + buffer->free = 1; + binder_insert_free_buffer(alloc, buffer); + alloc->free_async_space = alloc->buffer_size / 2; + barrier(); + alloc->vma = vma; + alloc->vma_vm_mm = vma->vm_mm; + /* Same as mmgrab() in later kernel versions */ + atomic_inc(&alloc->vma_vm_mm->mm_count); + + return 0; + +err_alloc_buf_struct_failed: + kfree(alloc->pages); + alloc->pages = NULL; +err_alloc_pages_failed: + mutex_lock(&binder_alloc_mmap_lock); + vfree(alloc->buffer); + alloc->buffer = NULL; +err_get_vm_area_failed: +err_already_mapped: + mutex_unlock(&binder_alloc_mmap_lock); + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, + alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret); + return ret; +} + + +void binder_alloc_deferred_release(struct binder_alloc *alloc) +{ + struct rb_node *n; + int buffers, page_count; + struct binder_buffer *buffer; + + BUG_ON(alloc->vma); + + buffers = 0; + mutex_lock(&alloc->mutex); + while ((n = rb_first(&alloc->allocated_buffers))) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + + /* Transaction should already have been freed */ + BUG_ON(buffer->transaction); + + binder_free_buf_locked(alloc, buffer); + buffers++; + } + + while (!list_empty(&alloc->buffers)) { + buffer = list_first_entry(&alloc->buffers, + struct binder_buffer, entry); + WARN_ON(!buffer->free); + + list_del(&buffer->entry); + WARN_ON_ONCE(!list_empty(&alloc->buffers)); + kfree(buffer); + } + + page_count = 0; + if (alloc->pages) { + int i; + + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { + void *page_addr; + bool on_lru; + + if (!alloc->pages[i].page_ptr) + continue; + + on_lru = list_lru_del(&binder_alloc_lru, + &alloc->pages[i].lru); + page_addr = alloc->buffer + i * PAGE_SIZE; + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%s: %d: page %d at %pK %s\n", + __func__, alloc->pid, i, page_addr, + on_lru ? "on lru" : "active"); + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); + __free_page(alloc->pages[i].page_ptr); + page_count++; + } + kfree(alloc->pages); + vfree(alloc->buffer); + } + mutex_unlock(&alloc->mutex); + if (alloc->vma_vm_mm) + mmdrop(alloc->vma_vm_mm); + + binder_alloc_debug(BINDER_DEBUG_OPEN_CLOSE, + "%s: %d buffers %d, pages %d\n", + __func__, alloc->pid, buffers, page_count); +} + +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) +{ + seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->extra_buffers_size, + buffer->transaction ? "active" : "delivered"); +} + +/** + * binder_alloc_print_allocated() - print buffer info + * @m: seq_file for output via seq_printf() + * @alloc: binder_alloc for this proc + * + * Prints information about every buffer associated with + * the binder_alloc state to the given seq_file + */ +void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc) +{ + struct rb_node *n; + + mutex_lock(&alloc->mutex); + for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); + mutex_unlock(&alloc->mutex); +} + +/** + * binder_alloc_print_pages() - print page usage + * @m: seq_file for output via seq_printf() + * @alloc: binder_alloc for this proc + */ +void binder_alloc_print_pages(struct seq_file *m, + struct binder_alloc *alloc) +{ + struct binder_lru_page *page; + int i; + int active = 0; + int lru = 0; + int free = 0; + + mutex_lock(&alloc->mutex); + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { + page = &alloc->pages[i]; + if (!page->page_ptr) + free++; + else if (list_empty(&page->lru)) + active++; + else + lru++; + } + mutex_unlock(&alloc->mutex); + seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); +} + +/** + * binder_alloc_get_allocated_count() - return count of buffers + * @alloc: binder_alloc for this proc + * + * Return: count of allocated buffers + */ +int binder_alloc_get_allocated_count(struct binder_alloc *alloc) +{ + struct rb_node *n; + int count = 0; + + mutex_lock(&alloc->mutex); + for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) + count++; + mutex_unlock(&alloc->mutex); + return count; +} + + +/** + * binder_alloc_vma_close() - invalidate address space + * @alloc: binder_alloc for this proc + * + * Called from binder_vma_close() when releasing address space. + * Clears alloc->vma to prevent new incoming transactions from + * allocating more buffers. + */ +void binder_alloc_vma_close(struct binder_alloc *alloc) +{ + WRITE_ONCE(alloc->vma, NULL); +} + +/** + * binder_alloc_free_page() - shrinker callback to free pages + * @item: item to free + * @lock: lock protecting the item + * @cb_arg: callback argument + * + * Called from list_lru_walk() in binder_shrink_scan() to free + * up pages when the system is under memory pressure. + */ +enum lru_status binder_alloc_free_page(struct list_head *item, + struct list_lru_one *lru, + spinlock_t *lock, + void *cb_arg) +{ + struct mm_struct *mm = NULL; + struct binder_lru_page *page = container_of(item, + struct binder_lru_page, + lru); + struct binder_alloc *alloc; + uintptr_t page_addr; + size_t index; + struct vm_area_struct *vma; + + alloc = page->alloc; + if (!mutex_trylock(&alloc->mutex)) + goto err_get_alloc_mutex_failed; + + if (!page->page_ptr) + goto err_page_already_freed; + + index = page - alloc->pages; + page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; + vma = alloc->vma; + if (vma) { + if (!mmget_not_zero(alloc->vma_vm_mm)) + goto err_mmget; + mm = alloc->vma_vm_mm; + if (!down_write_trylock(&mm->mmap_sem)) + goto err_down_write_mmap_sem_failed; + } + + list_lru_isolate(lru, item); + spin_unlock(lock); + + if (vma) { + trace_binder_unmap_user_start(alloc, index); + + zap_page_range(vma, + page_addr + + alloc->user_buffer_offset, + PAGE_SIZE, NULL); + + trace_binder_unmap_user_end(alloc, index); + + up_write(&mm->mmap_sem); + mmput(mm); + } + + trace_binder_unmap_kernel_start(alloc, index); + + unmap_kernel_range(page_addr, PAGE_SIZE); + __free_page(page->page_ptr); + page->page_ptr = NULL; + + trace_binder_unmap_kernel_end(alloc, index); + + spin_lock(lock); + mutex_unlock(&alloc->mutex); + return LRU_REMOVED_RETRY; + +err_down_write_mmap_sem_failed: + mmput_async(mm); +err_mmget: +err_page_already_freed: + mutex_unlock(&alloc->mutex); +err_get_alloc_mutex_failed: + return LRU_SKIP; +} + +static unsigned long +binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc) +{ + unsigned long ret = list_lru_count(&binder_alloc_lru); + return ret; +} + +static unsigned long +binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) +{ + unsigned long ret; + + ret = list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, + NULL, sc->nr_to_scan); + return ret; +} + +static struct shrinker binder_shrinker = { + .count_objects = binder_shrink_count, + .scan_objects = binder_shrink_scan, + .seeks = DEFAULT_SEEKS, +}; + +/** + * binder_alloc_init() - called by binder_open() for per-proc initialization + * @alloc: binder_alloc for this proc + * + * Called from binder_open() to initialize binder_alloc fields for + * new binder proc + */ +void binder_alloc_init(struct binder_alloc *alloc) +{ + alloc->pid = current->group_leader->pid; + mutex_init(&alloc->mutex); + INIT_LIST_HEAD(&alloc->buffers); +} + +void binder_alloc_shrinker_init(void) +{ + list_lru_init(&binder_alloc_lru); + register_shrinker(&binder_shrinker); +} diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h new file mode 100644 index 0000000000000000000000000000000000000000..2dd33b6df1044e64b785a6193bc30b84ddf9d1c5 --- /dev/null +++ b/drivers/android/binder_alloc.h @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_BINDER_ALLOC_H +#define _LINUX_BINDER_ALLOC_H + +#include +#include +#include +#include +#include +#include +#include + +extern struct list_lru binder_alloc_lru; +struct binder_transaction; + +/** + * struct binder_buffer - buffer used for binder transactions + * @entry: entry alloc->buffers + * @rb_node: node for allocated_buffers/free_buffers rb trees + * @free: true if buffer is free + * @allow_user_free: describe the second member of struct blah, + * @async_transaction: describe the second member of struct blah, + * @debug_id: describe the second member of struct blah, + * @transaction: describe the second member of struct blah, + * @target_node: describe the second member of struct blah, + * @data_size: describe the second member of struct blah, + * @offsets_size: describe the second member of struct blah, + * @extra_buffers_size: describe the second member of struct blah, + * @data:i describe the second member of struct blah, + * + * Bookkeeping structure for binder transaction buffers + */ +struct binder_buffer { + struct list_head entry; /* free and allocated entries by address */ + struct rb_node rb_node; /* free entry by size or allocated entry */ + /* by address */ + unsigned free:1; + unsigned allow_user_free:1; + unsigned async_transaction:1; + unsigned free_in_progress:1; + unsigned debug_id:28; + + struct binder_transaction *transaction; + + struct binder_node *target_node; + size_t data_size; + size_t offsets_size; + size_t extra_buffers_size; + void *data; +}; + +/** + * struct binder_lru_page - page object used for binder shrinker + * @page_ptr: pointer to physical page in mmap'd space + * @lru: entry in binder_alloc_lru + * @alloc: binder_alloc for a proc + */ +struct binder_lru_page { + struct list_head lru; + struct page *page_ptr; + struct binder_alloc *alloc; +}; + +/** + * struct binder_alloc - per-binder proc state for binder allocator + * @vma: vm_area_struct passed to mmap_handler + * (invarient after mmap) + * @tsk: tid for task that called init for this proc + * (invariant after init) + * @vma_vm_mm: copy of vma->vm_mm (invarient after mmap) + * @buffer: base of per-proc address space mapped via mmap + * @user_buffer_offset: offset between user and kernel VAs for buffer + * @buffers: list of all buffers for this proc + * @free_buffers: rb tree of buffers available for allocation + * sorted by size + * @allocated_buffers: rb tree of allocated buffers sorted by address + * @free_async_space: VA space available for async buffers. This is + * initialized at mmap time to 1/2 the full VA space + * @pages: array of binder_lru_page + * @buffer_size: size of address space specified via mmap + * @pid: pid for associated binder_proc (invariant after init) + * + * Bookkeeping structure for per-proc address space management for binder + * buffers. It is normally initialized during binder_init() and binder_mmap() + * calls. The address space is used for both user-visible buffers and for + * struct binder_buffer objects used to track the user buffers + */ +struct binder_alloc { + struct mutex mutex; + struct vm_area_struct *vma; + struct mm_struct *vma_vm_mm; + void *buffer; + ptrdiff_t user_buffer_offset; + struct list_head buffers; + struct rb_root free_buffers; + struct rb_root allocated_buffers; + size_t free_async_space; + struct binder_lru_page *pages; + size_t buffer_size; + uint32_t buffer_free; + int pid; +}; + +#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST +void binder_selftest_alloc(struct binder_alloc *alloc); +#else +static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} +#endif +enum lru_status binder_alloc_free_page(struct list_head *item, + struct list_lru_one *lru, + spinlock_t *lock, void *cb_arg); +extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async); +extern void binder_alloc_init(struct binder_alloc *alloc); +void binder_alloc_shrinker_init(void); +extern void binder_alloc_vma_close(struct binder_alloc *alloc); +extern struct binder_buffer * +binder_alloc_prepare_to_free(struct binder_alloc *alloc, + uintptr_t user_ptr); +extern void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer); +extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma); +extern void binder_alloc_deferred_release(struct binder_alloc *alloc); +extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc); +extern void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc); +void binder_alloc_print_pages(struct seq_file *m, + struct binder_alloc *alloc); + +/** + * binder_alloc_get_free_async_space() - get free space available for async + * @alloc: binder_alloc for this proc + * + * Return: the bytes remaining in the address-space for async transactions + */ +static inline size_t +binder_alloc_get_free_async_space(struct binder_alloc *alloc) +{ + size_t free_async_space; + + mutex_lock(&alloc->mutex); + free_async_space = alloc->free_async_space; + mutex_unlock(&alloc->mutex); + return free_async_space; +} + +/** + * binder_alloc_get_user_buffer_offset() - get offset between kernel/user addrs + * @alloc: binder_alloc for this proc + * + * Return: the offset between kernel and user-space addresses to use for + * virtual address conversion + */ +static inline ptrdiff_t +binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc) +{ + /* + * user_buffer_offset is constant if vma is set and + * undefined if vma is not set. It is possible to + * get here with !alloc->vma if the target process + * is dying while a transaction is being initiated. + * Returning the old value is ok in this case and + * the transaction will fail. + */ + return alloc->user_buffer_offset; +} + +#endif /* _LINUX_BINDER_ALLOC_H */ + diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c new file mode 100644 index 0000000000000000000000000000000000000000..8bd7bcef967d28cf2921938ecd25dd8bea71b2c6 --- /dev/null +++ b/drivers/android/binder_alloc_selftest.c @@ -0,0 +1,310 @@ +/* binder_alloc_selftest.c + * + * Android IPC Subsystem + * + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include "binder_alloc.h" + +#define BUFFER_NUM 5 +#define BUFFER_MIN_SIZE (PAGE_SIZE / 8) + +static bool binder_selftest_run = true; +static int binder_selftest_failures; +static DEFINE_MUTEX(binder_selftest_lock); + +/** + * enum buf_end_align_type - Page alignment of a buffer + * end with regard to the end of the previous buffer. + * + * In the pictures below, buf2 refers to the buffer we + * are aligning. buf1 refers to previous buffer by addr. + * Symbol [ means the start of a buffer, ] means the end + * of a buffer, and | means page boundaries. + */ +enum buf_end_align_type { + /** + * @SAME_PAGE_UNALIGNED: The end of this buffer is on + * the same page as the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 ][ ... + * buf1 ]|[ buf2 ][ ... + */ + SAME_PAGE_UNALIGNED = 0, + /** + * @SAME_PAGE_ALIGNED: When the end of the previous buffer + * is not page aligned, the end of this buffer is on the + * same page as the end of the previous buffer and is page + * aligned. When the previous buffer is page aligned, the + * end of this buffer is aligned to the next page boundary. + * Examples: + * buf1 ][ buf2 ]| ... + * buf1 ]|[ buf2 ]| ... + */ + SAME_PAGE_ALIGNED, + /** + * @NEXT_PAGE_UNALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is not page aligned. Examples: + * buf1 ][ buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 ][ ... + */ + NEXT_PAGE_UNALIGNED, + /** + * @NEXT_PAGE_ALIGNED: The end of this buffer is on + * the page next to the end of the previous buffer and + * is page aligned. Examples: + * buf1 ][ buf2 | buf2 ]| ... + * buf1 ]|[ buf2 | buf2 ]| ... + */ + NEXT_PAGE_ALIGNED, + /** + * @NEXT_NEXT_UNALIGNED: The end of this buffer is on + * the page that follows the page after the end of the + * previous buffer and is not page aligned. Examples: + * buf1 ][ buf2 | buf2 | buf2 ][ ... + * buf1 ]|[ buf2 | buf2 | buf2 ][ ... + */ + NEXT_NEXT_UNALIGNED, + LOOP_END, +}; + +static void pr_err_size_seq(size_t *sizes, int *seq) +{ + int i; + + pr_err("alloc sizes: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%zu]", sizes[i]); + pr_cont("\n"); + pr_err("free seq: "); + for (i = 0; i < BUFFER_NUM; i++) + pr_cont("[%d]", seq[i]); + pr_cont("\n"); +} + +static bool check_buffer_pages_allocated(struct binder_alloc *alloc, + struct binder_buffer *buffer, + size_t size) +{ + void *page_addr, *end; + int page_index; + + end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); + page_addr = buffer->data; + for (; page_addr < end; page_addr += PAGE_SIZE) { + page_index = (page_addr - alloc->buffer) / PAGE_SIZE; + if (!alloc->pages[page_index].page_ptr || + !list_empty(&alloc->pages[page_index].lru)) { + pr_err("expect alloc but is %s at page index %d\n", + alloc->pages[page_index].page_ptr ? + "lru" : "free", page_index); + return false; + } + } + return true; +} + +static void binder_selftest_alloc_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) { + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); + if (IS_ERR(buffers[i]) || + !check_buffer_pages_allocated(alloc, buffers[i], + sizes[i])) { + pr_err_size_seq(sizes, seq); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffers[], + size_t *sizes, int *seq, size_t end) +{ + int i; + + for (i = 0; i < BUFFER_NUM; i++) + binder_alloc_free_buf(alloc, buffers[seq[i]]); + + for (i = 0; i < end / PAGE_SIZE; i++) { + /** + * Error message on a free page can be false positive + * if binder shrinker ran during binder_alloc_free_buf + * calls above. + */ + if (list_empty(&alloc->pages[i].lru)) { + pr_err_size_seq(sizes, seq); + pr_err("expect lru but is %s at page index %d\n", + alloc->pages[i].page_ptr ? "alloc" : "free", i); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_free_page(struct binder_alloc *alloc) +{ + int i; + unsigned long count; + + while ((count = list_lru_count(&binder_alloc_lru))) { + list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, + NULL, count); + } + + for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { + if (alloc->pages[i].page_ptr) { + pr_err("expect free but is %s at page index %d\n", + list_empty(&alloc->pages[i].lru) ? + "alloc" : "lru", i); + binder_selftest_failures++; + } + } +} + +static void binder_selftest_alloc_free(struct binder_alloc *alloc, + size_t *sizes, int *seq, size_t end) +{ + struct binder_buffer *buffers[BUFFER_NUM]; + + binder_selftest_alloc_buf(alloc, buffers, sizes, seq); + binder_selftest_free_buf(alloc, buffers, sizes, seq, end); + + /* Allocate from lru. */ + binder_selftest_alloc_buf(alloc, buffers, sizes, seq); + if (list_lru_count(&binder_alloc_lru)) + pr_err("lru list should be empty but is not\n"); + + binder_selftest_free_buf(alloc, buffers, sizes, seq, end); + binder_selftest_free_page(alloc); +} + +static bool is_dup(int *seq, int index, int val) +{ + int i; + + for (i = 0; i < index; i++) { + if (seq[i] == val) + return true; + } + return false; +} + +/* Generate BUFFER_NUM factorial free orders. */ +static void binder_selftest_free_seq(struct binder_alloc *alloc, + size_t *sizes, int *seq, + int index, size_t end) +{ + int i; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_free(alloc, sizes, seq, end); + return; + } + for (i = 0; i < BUFFER_NUM; i++) { + if (is_dup(seq, index, i)) + continue; + seq[index] = i; + binder_selftest_free_seq(alloc, sizes, seq, index + 1, end); + } +} + +static void binder_selftest_alloc_size(struct binder_alloc *alloc, + size_t *end_offset) +{ + int i; + int seq[BUFFER_NUM] = {0}; + size_t front_sizes[BUFFER_NUM]; + size_t back_sizes[BUFFER_NUM]; + size_t last_offset, offset = 0; + + for (i = 0; i < BUFFER_NUM; i++) { + last_offset = offset; + offset = end_offset[i]; + front_sizes[i] = offset - last_offset; + back_sizes[BUFFER_NUM - i - 1] = front_sizes[i]; + } + /* + * Buffers share the first or last few pages. + * Only BUFFER_NUM - 1 buffer sizes are adjustable since + * we need one giant buffer before getting to the last page. + */ + back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; + binder_selftest_free_seq(alloc, front_sizes, seq, 0, + end_offset[BUFFER_NUM - 1]); + binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size); +} + +static void binder_selftest_alloc_offset(struct binder_alloc *alloc, + size_t *end_offset, int index) +{ + int align; + size_t end, prev; + + if (index == BUFFER_NUM) { + binder_selftest_alloc_size(alloc, end_offset); + return; + } + prev = index == 0 ? 0 : end_offset[index - 1]; + end = prev; + + BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE); + + for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) { + if (align % 2) + end = ALIGN(end, PAGE_SIZE); + else + end += BUFFER_MIN_SIZE; + end_offset[index] = end; + binder_selftest_alloc_offset(alloc, end_offset, index + 1); + } +} + +/** + * binder_selftest_alloc() - Test alloc and free of buffer pages. + * @alloc: Pointer to alloc struct. + * + * Allocate BUFFER_NUM buffers to cover all page alignment cases, + * then free them in all orders possible. Check that pages are + * correctly allocated, put onto lru when buffers are freed, and + * are freed when binder_alloc_free_page is called. + */ +void binder_selftest_alloc(struct binder_alloc *alloc) +{ + size_t end_offset[BUFFER_NUM]; + + if (!binder_selftest_run) + return; + mutex_lock(&binder_selftest_lock); + if (!binder_selftest_run || !alloc->vma) + goto done; + pr_info("STARTED\n"); + binder_selftest_alloc_offset(alloc, end_offset, 0); + binder_selftest_run = false; + if (binder_selftest_failures > 0) + pr_info("%d tests FAILED\n", binder_selftest_failures); + else + pr_info("PASSED\n"); + +done: + mutex_unlock(&binder_selftest_lock); +} diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 7f20f3dc83690cad36cfa82c2a946384a8c30bb8..b11dffc521e85734dd53f8ed64e10dc799f610a6 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -23,7 +23,8 @@ struct binder_buffer; struct binder_node; struct binder_proc; -struct binder_ref; +struct binder_alloc; +struct binder_ref_data; struct binder_thread; struct binder_transaction; @@ -84,6 +85,30 @@ DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done); DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done); DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done); +TRACE_EVENT(binder_set_priority, + TP_PROTO(int proc, int thread, unsigned int old_prio, + unsigned int desired_prio, unsigned int new_prio), + TP_ARGS(proc, thread, old_prio, new_prio, desired_prio), + + TP_STRUCT__entry( + __field(int, proc) + __field(int, thread) + __field(unsigned int, old_prio) + __field(unsigned int, new_prio) + __field(unsigned int, desired_prio) + ), + TP_fast_assign( + __entry->proc = proc; + __entry->thread = thread; + __entry->old_prio = old_prio; + __entry->new_prio = new_prio; + __entry->desired_prio = desired_prio; + ), + TP_printk("proc=%d thread=%d old=%d => new=%d desired=%d", + __entry->proc, __entry->thread, __entry->old_prio, + __entry->new_prio, __entry->desired_prio) +); + TRACE_EVENT(binder_wait_for_work, TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), TP_ARGS(proc_work, transaction_stack, thread_todo), @@ -146,8 +171,8 @@ TRACE_EVENT(binder_transaction_received, TRACE_EVENT(binder_transaction_node_to_ref, TP_PROTO(struct binder_transaction *t, struct binder_node *node, - struct binder_ref *ref), - TP_ARGS(t, node, ref), + struct binder_ref_data *rdata), + TP_ARGS(t, node, rdata), TP_STRUCT__entry( __field(int, debug_id) @@ -160,8 +185,8 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->debug_id = t->debug_id; __entry->node_debug_id = node->debug_id; __entry->node_ptr = node->ptr; - __entry->ref_debug_id = ref->debug_id; - __entry->ref_desc = ref->desc; + __entry->ref_debug_id = rdata->debug_id; + __entry->ref_desc = rdata->desc; ), TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", __entry->debug_id, __entry->node_debug_id, @@ -170,8 +195,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, ); TRACE_EVENT(binder_transaction_ref_to_node, - TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), - TP_ARGS(t, ref), + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref_data *rdata), + TP_ARGS(t, node, rdata), TP_STRUCT__entry( __field(int, debug_id) @@ -182,10 +208,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->ref_debug_id = ref->debug_id; - __entry->ref_desc = ref->desc; - __entry->node_debug_id = ref->node->debug_id; - __entry->node_ptr = ref->node->ptr; + __entry->ref_debug_id = rdata->debug_id; + __entry->ref_desc = rdata->desc; + __entry->node_debug_id = node->debug_id; + __entry->node_ptr = node->ptr; ), TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, @@ -194,9 +220,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, ); TRACE_EVENT(binder_transaction_ref_to_ref, - TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, - struct binder_ref *dest_ref), - TP_ARGS(t, src_ref, dest_ref), + TP_PROTO(struct binder_transaction *t, struct binder_node *node, + struct binder_ref_data *src_ref, + struct binder_ref_data *dest_ref), + TP_ARGS(t, node, src_ref, dest_ref), TP_STRUCT__entry( __field(int, debug_id) @@ -208,7 +235,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref, ), TP_fast_assign( __entry->debug_id = t->debug_id; - __entry->node_debug_id = src_ref->node->debug_id; + __entry->node_debug_id = node->debug_id; __entry->src_ref_debug_id = src_ref->debug_id; __entry->src_ref_desc = src_ref->desc; __entry->dest_ref_debug_id = dest_ref->debug_id; @@ -268,9 +295,9 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, TP_ARGS(buffer)); TRACE_EVENT(binder_update_page_range, - TP_PROTO(struct binder_proc *proc, bool allocate, + TP_PROTO(struct binder_alloc *alloc, bool allocate, void *start, void *end), - TP_ARGS(proc, allocate, start, end), + TP_ARGS(alloc, allocate, start, end), TP_STRUCT__entry( __field(int, proc) __field(bool, allocate) @@ -278,9 +305,9 @@ TRACE_EVENT(binder_update_page_range, __field(size_t, size) ), TP_fast_assign( - __entry->proc = proc->pid; + __entry->proc = alloc->pid; __entry->allocate = allocate; - __entry->offset = start - proc->buffer; + __entry->offset = start - alloc->buffer; __entry->size = end - start; ), TP_printk("proc=%d allocate=%d offset=%zu size=%zu", @@ -288,6 +315,61 @@ TRACE_EVENT(binder_update_page_range, __entry->offset, __entry->size) ); +DECLARE_EVENT_CLASS(binder_lru_page_class, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index), + TP_STRUCT__entry( + __field(int, proc) + __field(size_t, page_index) + ), + TP_fast_assign( + __entry->proc = alloc->pid; + __entry->page_index = page_index; + ), + TP_printk("proc=%d page_index=%zu", + __entry->proc, __entry->page_index) +); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + +DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end, + TP_PROTO(const struct binder_alloc *alloc, size_t page_index), + TP_ARGS(alloc, page_index)); + TRACE_EVENT(binder_command, TP_PROTO(uint32_t cmd), TP_ARGS(cmd), diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2c8be74f401de1bcfc698deec75287bc56f5efbf..5d16fc4fa46c7855a835434112c6801bc2587098 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -289,6 +289,7 @@ config SATA_SX4 config ATA_BMDMA bool "ATA BMDMA support" + depends on HAS_DMA default y help This option adds support for SFF ATA controllers with BMDMA @@ -344,6 +345,7 @@ config SATA_DWC_VDEBUG config SATA_HIGHBANK tristate "Calxeda Highbank SATA support" + depends on HAS_DMA depends on ARCH_HIGHBANK || COMPILE_TEST help This option enables support for the Calxeda Highbank SoC's @@ -353,6 +355,7 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + depends on HAS_DMA depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \ ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST select GENERIC_PHY diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 74f4c662f776ecf546d4c61a7de4190a61870b5c..c94038206c3aec59ed4535978a0f47d4cfca99fd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1362,6 +1362,40 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) {} #endif +/* + * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected + * as DUMMY, or detected but eventually get a "link down" and never get up + * again. When this happens, CAP.NP may hold a value of 0x00 or 0x01, and the + * port_map may hold a value of 0x00. + * + * Overriding CAP.NP to 0x02 and the port_map to 0x7 will reveal all 3 ports + * and can significantly reduce the occurrence of the problem. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=189471 + */ +static void acer_sa5_271_workaround(struct ahci_host_priv *hpriv, + struct pci_dev *pdev) +{ + static const struct dmi_system_id sysids[] = { + { + .ident = "Acer Switch Alpha 12", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271") + }, + }, + { } + }; + + if (dmi_check_system(sysids)) { + dev_info(&pdev->dev, "enabling Acer Switch Alpha 12 workaround\n"); + if ((hpriv->saved_cap & 0xC734FF00) == 0xC734FF00) { + hpriv->port_map = 0x7; + hpriv->cap = 0xC734FF02; + } + } +} + #ifdef CONFIG_ARM64 /* * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently. @@ -1597,6 +1631,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) "online status unreliable, applying workaround\n"); } + + /* Acer SA5-271 workaround modifies private_data */ + acer_sa5_271_workaround(hpriv, pdev); + /* CAP.NP sometimes indicate the index of the last enabled * port, at other times, that of the last possible port, so * determining the maximum port number requires looking at diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0e1ec37070d19b641ed37d9a75c216197c0fc557..6475a13434833d0072bab167affbd16e138a5270 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2329,8 +2329,8 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (dev->flags & ATA_DFLAG_DUBIOUS_XFER) eflags |= ATA_EFLAG_DUBIOUS_XFER; ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); + trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask); } - trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask); DPRINTK("EXIT\n"); } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8e575fbdf31d6b5737046111d55600a8638e595b..e3e10e8f6f6aaa9e3be6e4397d69d4ab182e17ba 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2971,10 +2971,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) { if (!sata_pmp_attached(ap)) { - if (likely(devno < ata_link_max_devices(&ap->link))) + if (likely(devno >= 0 && + devno < ata_link_max_devices(&ap->link))) return &ap->link.device[devno]; } else { - if (likely(devno < ap->nr_pmp_links)) + if (likely(devno >= 0 && + devno < ap->nr_pmp_links)) return &ap->pmp_link[devno].device[0]; } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 051b6158d1b7f45b7116b9debc98376a9d4d240f..8d22acdf90f0bc546ee70bcdd7d2e8245065ca34 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1481,7 +1481,6 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; default: - WARN_ON_ONCE(1); return AC_ERR_SYSTEM; } diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index 7ef16c08505879127a3b433979119455e17d1ff4..20e2b7ad89250e834b822e6a80b9fb978bcc6e9d 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -224,7 +224,6 @@ static DECLARE_TRANSPORT_CLASS(ata_port_class, static void ata_tport_release(struct device *dev) { - put_device(dev->parent); } /** @@ -284,7 +283,7 @@ int ata_tport_add(struct device *parent, device_initialize(dev); dev->type = &ata_port_type; - dev->parent = get_device(parent); + dev->parent = parent; dev->release = ata_tport_release; dev_set_name(dev, "ata%d", ap->print_id); transport_setup_device(dev); @@ -348,7 +347,6 @@ static DECLARE_TRANSPORT_CLASS(ata_link_class, static void ata_tlink_release(struct device *dev) { - put_device(dev->parent); } /** @@ -410,7 +408,7 @@ int ata_tlink_add(struct ata_link *link) int error; device_initialize(dev); - dev->parent = get_device(&ap->tdev); + dev->parent = &ap->tdev; dev->release = ata_tlink_release; if (ata_is_host_link(link)) dev_set_name(dev, "link%d", ap->print_id); @@ -589,7 +587,6 @@ static DECLARE_TRANSPORT_CLASS(ata_dev_class, static void ata_tdev_release(struct device *dev) { - put_device(dev->parent); } /** @@ -662,7 +659,7 @@ static int ata_tdev_add(struct ata_device *ata_dev) int error; device_initialize(dev); - dev->parent = get_device(&link->tdev); + dev->parent = &link->tdev; dev->release = ata_tdev_release; if (ata_is_host_link(link)) dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno); diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 8d4d959a821cab1a356dfde38226caf69ab5129f..8706533db57b6eb850cd74bc224ff67f36bcbaa5 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -616,6 +616,7 @@ static const struct pci_device_id amd[] = { { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 8 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 8 }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), 9 }, { }, }; diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 6c15a554efbe1945f79a12aa7588c25cd10be024..dc12552946281d91d262fce5a04adaa7a60b08a3 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -289,6 +289,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) static const struct pci_device_id cs5536[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), }, { }, }; diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 0636d84fbefe0acc889004b39e83c0137fc0f6a0..f3f538eec7b3bb85b682368ffb42496989c97263 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -644,14 +644,16 @@ static void svia_configure(struct pci_dev *pdev, int board_id, pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } - /* enable IRQ on hotplug */ - pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); - if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { - dev_dbg(&pdev->dev, - "enabling SATA hotplug (0x%x)\n", - (int) tmp8); - tmp8 |= SATA_HOTPLUG; - pci_write_config_byte(pdev, SVIA_MISC_3, tmp8); + if (board_id == vt6421) { + /* enable IRQ on hotplug */ + pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); + if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { + dev_dbg(&pdev->dev, + "enabling SATA hotplug (0x%x)\n", + (int) tmp8); + tmp8 |= SATA_HOTPLUG; + pci_write_config_byte(pdev, SVIA_MISC_3, tmp8); + } } /* diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 5fc81e240c242a12fe972b7054c5d5162cdd4881..e55f418d6ab9c385394d7e26ed73289e351e3d45 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2802,7 +2802,7 @@ static int hrz_probe(struct pci_dev *pci_dev, return err; out_free_irq: - free_irq(dev->irq, dev); + free_irq(irq, dev); out_free: kfree(dev); out_release: diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index d02e7c0f5bfdff1c6c56372113e230e55be54f5f..0651010bba217c53ef52dca2531a216756089235 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -235,6 +235,9 @@ config GENERIC_CPU_DEVICES config GENERIC_CPU_AUTOPROBE bool +config GENERIC_CPU_VULNERABILITIES + bool + config SOC_BUS bool diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6470eb8088f4f4da92215f5009c3b63a2a492876..e32a74eb28a3e91c4a07658aa268598c9766ef61 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -736,7 +736,7 @@ int bus_add_driver(struct device_driver *drv) out_unregister: kobject_put(&priv->kobj); - kfree(drv->p); + /* drv->p is freed in driver_release() */ drv->p = NULL; out_put_bus: bus_put(bus); diff --git a/drivers/base/core.c b/drivers/base/core.c index 5ba619aa7f4e116b7f89f42198dfa9bef631e406..ac43d6ffa6fcf2e54658cb618571241482d7316d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1116,13 +1116,7 @@ int device_add(struct device *dev) error = dpm_sysfs_add(dev); if (error) goto DPMError; - if ((dev->pm_domain) || (dev->type && dev->type->pm) - || (dev->class && (dev->class->pm || dev->class->resume)) - || (dev->bus && (dev->bus->pm || dev->bus->resume)) || - (dev->driver && dev->driver->pm)) { - device_pm_add(dev); - } - + device_pm_add(dev); if (MAJOR(dev->devt)) { error = device_create_file(dev, &dev_attr_dev); @@ -2106,7 +2100,11 @@ void device_shutdown(void) pm_runtime_get_noresume(dev); pm_runtime_barrier(dev); - if (dev->bus && dev->bus->shutdown) { + if (dev->class && dev->class->shutdown) { + if (initcall_debug) + dev_info(dev, "shutdown\n"); + dev->class->shutdown(dev); + } else if (dev->bus && dev->bus->shutdown) { if (initcall_debug) dev_info(dev, "shutdown\n"); dev->bus->shutdown(dev); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 4609244078753300d285ad961ffe684451316057..4fe86f7bf456dfc48cea25cdc4637a5864efaaab 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -182,8 +182,8 @@ static struct attribute_group crash_note_cpu_attr_group = { #ifdef CONFIG_HOTPLUG_CPU -static ssize_t show_cpu_isolated(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t isolate_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct cpu *cpu = container_of(dev, struct cpu, dev); ssize_t rc; @@ -195,31 +195,7 @@ static ssize_t show_cpu_isolated(struct device *dev, return rc; } -static ssize_t __ref store_cpu_isolated(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - int err; - int cpuid = cpu->dev.id; - unsigned int isolated; - - err = kstrtouint(strstrip((char *)buf), 0, &isolated); - if (err) - return err; - - if (isolated > 1) - return -EINVAL; - - if (isolated) - sched_isolate_cpu(cpuid); - else - sched_unisolate_cpu(cpuid); - - return count; -} - -static DEVICE_ATTR(isolate, 0644, show_cpu_isolated, store_cpu_isolated); +static DEVICE_ATTR_RO(isolate); static struct attribute *cpu_isolated_attrs[] = { &dev_attr_isolate.attr, @@ -232,148 +208,67 @@ static struct attribute_group cpu_isolated_attr_group = { #endif -#ifdef CONFIG_SCHED_HMP - -static ssize_t show_sched_static_cpu_pwr_cost(struct device *dev, +static ssize_t show_sched_load_boost(struct device *dev, struct device_attribute *attr, char *buf) { - struct cpu *cpu = container_of(dev, struct cpu, dev); ssize_t rc; - int cpuid = cpu->dev.id; - unsigned int pwr_cost; - - pwr_cost = sched_get_static_cpu_pwr_cost(cpuid); - - rc = snprintf(buf, PAGE_SIZE-2, "%d\n", pwr_cost); - - return rc; -} - -static ssize_t __ref store_sched_static_cpu_pwr_cost(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - int err; - int cpuid = cpu->dev.id; - unsigned int pwr_cost; - - err = kstrtouint(strstrip((char *)buf), 0, &pwr_cost); - if (err) - return err; - - err = sched_set_static_cpu_pwr_cost(cpuid, pwr_cost); - - if (err >= 0) - err = count; - - return err; -} - -static ssize_t show_sched_static_cluster_pwr_cost(struct device *dev, - struct device_attribute *attr, char *buf) -{ + unsigned int boost; struct cpu *cpu = container_of(dev, struct cpu, dev); - ssize_t rc; int cpuid = cpu->dev.id; - unsigned int pwr_cost; - - pwr_cost = sched_get_static_cluster_pwr_cost(cpuid); - rc = snprintf(buf, PAGE_SIZE-2, "%d\n", pwr_cost); + boost = per_cpu(sched_load_boost, cpuid); + rc = snprintf(buf, PAGE_SIZE-2, "%d\n", boost); return rc; } -static ssize_t __ref store_sched_static_cluster_pwr_cost(struct device *dev, +static ssize_t __ref store_sched_load_boost(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct cpu *cpu = container_of(dev, struct cpu, dev); int err; - int cpuid = cpu->dev.id; - unsigned int pwr_cost; - - err = kstrtouint(strstrip((char *)buf), 0, &pwr_cost); - if (err) - return err; - - err = sched_set_static_cluster_pwr_cost(cpuid, pwr_cost); - - if (err >= 0) - err = count; - - return err; -} - -static ssize_t show_sched_cluser_wake_idle(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - ssize_t rc; - int cpuid = cpu->dev.id; - unsigned int wake_up_idle; - - wake_up_idle = sched_get_cluster_wake_idle(cpuid); - - rc = scnprintf(buf, PAGE_SIZE-2, "%d\n", wake_up_idle); - - return rc; -} - -static ssize_t __ref store_sched_cluster_wake_idle(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ + int boost; struct cpu *cpu = container_of(dev, struct cpu, dev); - int err; int cpuid = cpu->dev.id; - unsigned int wake_up_idle; - err = kstrtouint(strstrip((char *)buf), 0, &wake_up_idle); + err = kstrtoint(strstrip((char *)buf), 0, &boost); if (err) return err; - err = sched_set_cluster_wake_idle(cpuid, wake_up_idle); + /* + * -100 is low enough to cancel out CPU's load and make it near zro. + * 1000 is close to the maximum value that cpu_util_freq_{walt,pelt} + * can take without overflow. + */ + if (boost < -100 || boost > 1000) + return -EINVAL; - if (err >= 0) - err = count; + per_cpu(sched_load_boost, cpuid) = boost; - return err; + return count; } -static DEVICE_ATTR(sched_static_cpu_pwr_cost, 0644, - show_sched_static_cpu_pwr_cost, - store_sched_static_cpu_pwr_cost); -static DEVICE_ATTR(sched_static_cluster_pwr_cost, 0644, - show_sched_static_cluster_pwr_cost, - store_sched_static_cluster_pwr_cost); -static DEVICE_ATTR(sched_cluster_wake_up_idle, 0644, - show_sched_cluser_wake_idle, - store_sched_cluster_wake_idle); +static DEVICE_ATTR(sched_load_boost, 0644, + show_sched_load_boost, + store_sched_load_boost); -static struct attribute *hmp_sched_cpu_attrs[] = { - &dev_attr_sched_static_cpu_pwr_cost.attr, - &dev_attr_sched_static_cluster_pwr_cost.attr, - &dev_attr_sched_cluster_wake_up_idle.attr, +static struct attribute *sched_cpu_attrs[] = { + &dev_attr_sched_load_boost.attr, NULL }; -static struct attribute_group sched_hmp_cpu_attr_group = { - .attrs = hmp_sched_cpu_attrs, +static struct attribute_group sched_cpu_attr_group = { + .attrs = sched_cpu_attrs, }; -#endif /* CONFIG_SCHED_HMP */ static const struct attribute_group *common_cpu_attr_groups[] = { #ifdef CONFIG_KEXEC &crash_note_cpu_attr_group, #endif -#ifdef CONFIG_SCHED_HMP - &sched_hmp_cpu_attr_group, -#endif #ifdef CONFIG_HOTPLUG_CPU &cpu_isolated_attr_group, #endif + &sched_cpu_attr_group, NULL }; @@ -381,12 +276,10 @@ static const struct attribute_group *hotplugable_cpu_attr_groups[] = { #ifdef CONFIG_KEXEC &crash_note_cpu_attr_group, #endif -#ifdef CONFIG_SCHED_HMP - &sched_hmp_cpu_attr_group, -#endif #ifdef CONFIG_HOTPLUG_CPU &cpu_isolated_attr_group, #endif + &sched_cpu_attr_group, NULL }; @@ -697,10 +590,58 @@ static void __init cpu_dev_register_generic(void) #endif } +#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES + +ssize_t __weak cpu_show_meltdown(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); +static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); +static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); + +static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_meltdown.attr, + &dev_attr_spectre_v1.attr, + &dev_attr_spectre_v2.attr, + NULL +}; + +static const struct attribute_group cpu_root_vulnerabilities_group = { + .name = "vulnerabilities", + .attrs = cpu_root_vulnerabilities_attrs, +}; + +static void __init cpu_register_vulnerabilities(void) +{ + if (sysfs_create_group(&cpu_subsys.dev_root->kobj, + &cpu_root_vulnerabilities_group)) + pr_err("Unable to register CPU vulnerabilities\n"); +} + +#else +static inline void cpu_register_vulnerabilities(void) { } +#endif + void __init cpu_dev_init(void) { if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) panic("Failed to register CPU subsystem"); cpu_dev_register_generic(); + cpu_register_vulnerabilities(); } diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index e167a1e1bccb062efef2595fcd5299301a97df80..4f638aba7009eeed1811f828998bf3f8900f0459 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -165,7 +165,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, { int ret; - ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, res_cma); + ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, + "reserved", res_cma); if (ret) return ret; @@ -257,7 +258,7 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem) return -EINVAL; } - err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma); + err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma); if (err) { pr_err("Reserved memory: unable to setup CMA region\n"); return err; diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index aa5e22cca4423676032388b4ec1a7330186fb941..7c8f6bf28b814ad1c4fbcfcf6dbca077685fd6c4 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -306,7 +306,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, unsigned long vm_flags, pgprot_t prot, const void *caller) { - int i; + unsigned long i; struct page **pages; void *ptr; unsigned long pfn; diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index a95e1e572697d17453ee2bb59df060086b77f7e0..914433f5110086187e54dabfd753d75b86693ccb 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -206,6 +206,7 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, buf->data = dbuf; buf->allocated_size = size; init_completion(&buf->completion); + INIT_LIST_HEAD(&buf->list); #ifdef CONFIG_FW_LOADER_USER_HELPER INIT_LIST_HEAD(&buf->pending_list); #endif @@ -229,20 +230,22 @@ static struct firmware_buf *__fw_lookup_buf(const char *fw_name) static int fw_lookup_and_allocate_buf(const char *fw_name, struct firmware_cache *fwc, struct firmware_buf **buf, void *dbuf, - size_t size) + size_t size, unsigned int opt_flags) { struct firmware_buf *tmp; spin_lock(&fwc->lock); - tmp = __fw_lookup_buf(fw_name); - if (tmp) { - kref_get(&tmp->ref); - spin_unlock(&fwc->lock); - *buf = tmp; - return 1; + if (!(opt_flags & FW_OPT_NOCACHE)) { + tmp = __fw_lookup_buf(fw_name); + if (tmp) { + kref_get(&tmp->ref); + spin_unlock(&fwc->lock); + *buf = tmp; + return 1; + } } tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size); - if (tmp) + if (tmp && !(opt_flags & FW_OPT_NOCACHE)) list_add(&tmp->list, &fwc->head); spin_unlock(&fwc->lock); @@ -955,7 +958,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, timeout = MAX_JIFFY_OFFSET; } - timeout = wait_for_completion_interruptible_timeout(&buf->completion, + timeout = wait_for_completion_killable_timeout(&buf->completion, timeout); if (timeout == -ERESTARTSYS || !timeout) { retval = timeout; @@ -1051,7 +1054,8 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf) */ static int _request_firmware_prepare(struct firmware **firmware_p, const char *name, - struct device *device, void *dbuf, size_t size) + struct device *device, void *dbuf, size_t size, + unsigned int opt_flags) { struct firmware *firmware; struct firmware_buf *buf; @@ -1069,7 +1073,8 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, return 0; /* assigned */ } - ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size); + ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size, + opt_flags); /* * bind with 'buf' now to avoid warning in failure path @@ -1147,7 +1152,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, goto out; } - ret = _request_firmware_prepare(&fw, name, device, buf, size); + ret = _request_firmware_prepare(&fw, name, device, buf, size, + opt_flags); if (ret <= 0) /* error or already assigned */ goto out; @@ -1173,11 +1179,11 @@ _request_firmware(const struct firmware **firmware_p, const char *name, ret = fw_get_filesystem_firmware(device, fw->priv); if (ret) { if (!(opt_flags & FW_OPT_NO_WARN)) - dev_warn(device, - "Direct firmware load for %s failed with error %d\n", + dev_dbg(device, + "Firmware %s was not found in kernel paths. rc:%d\n", name, ret); if (opt_flags & FW_OPT_USERHELPER) { - dev_warn(device, "Falling back to user helper\n"); + dev_dbg(device, "Falling back to user helper\n"); ret = fw_load_from_user_helper(fw, name, device, opt_flags, timeout); } diff --git a/drivers/base/isa.c b/drivers/base/isa.c index cd6ccdcf9df0c5ef2a37fabb2b4b7bbfa3c88755..372d10af26009dfae317affd625c756a2700fef1 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -39,7 +39,7 @@ static int isa_bus_probe(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->probe) + if (isa_driver && isa_driver->probe) return isa_driver->probe(dev, to_isa_dev(dev)->id); return 0; @@ -49,7 +49,7 @@ static int isa_bus_remove(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->remove) + if (isa_driver && isa_driver->remove) return isa_driver->remove(dev, to_isa_dev(dev)->id); return 0; @@ -59,7 +59,7 @@ static void isa_bus_shutdown(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->shutdown) + if (isa_driver && isa_driver->shutdown) isa_driver->shutdown(dev, to_isa_dev(dev)->id); } @@ -67,7 +67,7 @@ static int isa_bus_suspend(struct device *dev, pm_message_t state) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->suspend) + if (isa_driver && isa_driver->suspend) return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); return 0; @@ -77,7 +77,7 @@ static int isa_bus_resume(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->resume) + if (isa_driver && isa_driver->resume) return isa_driver->resume(dev, to_isa_dev(dev)->id); return 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c4af00385502ffd9039bc73d1eccc2eedef33ce4..14ff40371f013ade81bd6e3102a0d9e22ff16547 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -856,9 +856,10 @@ static ssize_t driver_override_store(struct device *dev, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); - char *driver_override, *old = pdev->driver_override, *cp; + char *driver_override, *old, *cp; - if (count > PATH_MAX) + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); @@ -869,12 +870,15 @@ static ssize_t driver_override_store(struct device *dev, if (cp) *cp = '\0'; + device_lock(dev); + old = pdev->driver_override; if (strlen(driver_override)) { pdev->driver_override = driver_override; } else { kfree(driver_override); pdev->driver_override = NULL; } + device_unlock(dev); kfree(old); @@ -885,8 +889,12 @@ static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); + ssize_t len; - return sprintf(buf, "%s\n", pdev->driver_override); + device_lock(dev); + len = sprintf(buf, "%s\n", pdev->driver_override); + device_unlock(dev); + return len; } static DEVICE_ATTR_RW(driver_override); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e023066e421547c547ded5e94215205ee477eb63..8c7d0f33bd53761e118adcc130572c80a1effa57 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1029,8 +1029,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, spin_unlock_irq(&dev->power.lock); - dev_pm_domain_set(dev, &genpd->domain); - return gpd_data; err_free: @@ -1044,8 +1042,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, static void genpd_free_dev_data(struct device *dev, struct generic_pm_domain_data *gpd_data) { - dev_pm_domain_set(dev, NULL); - spin_lock_irq(&dev->power.lock); dev->power.subsys_data->domain_data = NULL; @@ -1082,6 +1078,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (ret) goto out; + dev_pm_domain_set(dev, &genpd->domain); + genpd->device_count++; genpd->max_off_time_changed = true; @@ -1143,6 +1141,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, if (genpd->detach_dev) genpd->detach_dev(genpd, dev); + dev_pm_domain_set(dev, NULL); + list_del_init(&pdd->list_node); mutex_unlock(&genpd->lock); @@ -1244,7 +1244,7 @@ EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain); int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *subdomain) { - struct gpd_link *link; + struct gpd_link *l, *link; int ret = -EINVAL; if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)) @@ -1260,7 +1260,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, goto out; } - list_for_each_entry(link, &genpd->master_links, master_node) { + list_for_each_entry_safe(link, l, &genpd->master_links, master_node) { if (link->slave != subdomain) continue; @@ -1607,12 +1607,12 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell); */ void of_genpd_del_provider(struct device_node *np) { - struct of_genpd_provider *cp; + struct of_genpd_provider *cp, *tmp; struct generic_pm_domain *gpd; mutex_lock(&gpd_list_lock); mutex_lock(&of_genpd_mutex); - list_for_each_entry(cp, &of_genpd_providers, link) { + list_for_each_entry_safe(cp, tmp, &of_genpd_providers, link) { if (cp->node == np) { /* * For each PM domain associated with the @@ -1752,14 +1752,14 @@ EXPORT_SYMBOL_GPL(of_genpd_add_subdomain); */ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) { - struct generic_pm_domain *gpd, *genpd = ERR_PTR(-ENOENT); + struct generic_pm_domain *gpd, *tmp, *genpd = ERR_PTR(-ENOENT); int ret; if (IS_ERR_OR_NULL(np)) return ERR_PTR(-EINVAL); mutex_lock(&gpd_list_lock); - list_for_each_entry(gpd, &gpd_list, gpd_list_node) { + list_for_each_entry_safe(gpd, tmp, &gpd_list, gpd_list_node) { if (gpd->provider == &np->fwnode) { ret = genpd_remove(gpd); genpd = ret ? ERR_PTR(ret) : gpd; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c1e56c3f845500160d5051b606849d627df6fa0d..dc259d20c9678a95b2ad272969c54f32e6c9fa50 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -162,12 +162,6 @@ void device_pm_move_before(struct device *deva, struct device *devb) pr_debug("PM: Moving %s:%s before %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); - if (!((devb->pm_domain) || (devb->type && devb->type->pm) - || (devb->class && (devb->class->pm || devb->class->resume)) - || (devb->bus && (devb->bus->pm || devb->bus->resume)) || - (devb->driver && devb->driver->pm))) { - device_pm_add(devb); - } /* Delete deva from dpm_list and reinsert before devb. */ list_move_tail(&deva->power.entry, &devb->power.entry); } @@ -182,12 +176,6 @@ void device_pm_move_after(struct device *deva, struct device *devb) pr_debug("PM: Moving %s:%s after %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); - if (!((devb->pm_domain) || (devb->type && devb->type->pm) - || (devb->class && (devb->class->pm || devb->class->resume)) - || (devb->bus && (devb->bus->pm || devb->bus->resume)) || - (devb->driver && devb->driver->pm))) { - device_pm_add(devb); - } /* Delete deva from dpm_list and reinsert after devb. */ list_move(&deva->power.entry, &devb->power.entry); } @@ -1774,10 +1762,13 @@ void device_pm_check_callbacks(struct device *dev) { spin_lock_irq(&dev->power.lock); dev->power.no_pm_callbacks = - (!dev->bus || pm_ops_is_empty(dev->bus->pm)) && - (!dev->class || pm_ops_is_empty(dev->class->pm)) && + (!dev->bus || (pm_ops_is_empty(dev->bus->pm) && + !dev->bus->suspend && !dev->bus->resume)) && + (!dev->class || (pm_ops_is_empty(dev->class->pm) && + !dev->class->suspend && !dev->class->resume)) && (!dev->type || pm_ops_is_empty(dev->type->pm)) && (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) && - (!dev->driver || pm_ops_is_empty(dev->driver->pm)); + (!dev->driver || (pm_ops_is_empty(dev->driver->pm) && + !dev->driver->suspend && !dev->driver->resume)); spin_unlock_irq(&dev->power.lock); } diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 6441dfda489f80a404bacd6132d8900b9d98c6bf..a7c5b79371a7c015211328e123cccd9e706c8e2f 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -331,7 +331,7 @@ int dev_pm_opp_get_opp_count(struct device *dev) opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { count = PTR_ERR(opp_table); - dev_err(dev, "%s: OPP table not found (%d)\n", + dev_dbg(dev, "%s: OPP table not found (%d)\n", __func__, count); goto out_unlock; } diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c index 5552211e6fcdf8cb2d380320d1d7e5d274d4415c..69379443e5eb6fbf60cbb321cb4915a7b382797f 100644 --- a/drivers/base/power/opp/of.c +++ b/drivers/base/power/opp/of.c @@ -348,6 +348,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) if (ret) { dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); + of_node_put(np); goto free_table; } } @@ -386,7 +387,7 @@ static int _of_add_opp_table_v1(struct device *dev) { const struct property *prop; const __be32 *val; - int nr; + int nr, ret; prop = of_find_property(dev->of_node, "operating-points", NULL); if (!prop) @@ -409,9 +410,13 @@ static int _of_add_opp_table_v1(struct device *dev) unsigned long freq = be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); - if (_opp_add_v1(dev, freq, volt, false)) - dev_warn(dev, "%s: Failed to add OPP %ld\n", - __func__, freq); + ret = _opp_add_v1(dev, freq, volt, false); + if (ret) { + dev_err(dev, "%s: Failed to add OPP %ld (%d)\n", + __func__, freq, ret); + dev_pm_opp_of_remove_table(dev); + return ret; + } nr -= 2; } diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index a84332aefc2da73aa3252877cf970efe9e2b9f77..882f1c9e1da4aeecd2820bd5003584487f1d3d25 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -131,6 +131,12 @@ extern int pm_async_enabled; /* drivers/base/power/main.c */ extern struct list_head dpm_list; /* The active device list */ +#ifdef CONFIG_QCOM_SHOW_RESUME_IRQ +extern int msm_show_resume_irq_mask; +#else +#define msm_show_resume_irq_mask 0 +#endif + static inline struct device *to_device(struct list_head *entry) { return container_of(entry, struct device, power.entry); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 23f3b95a1158bc44b88a0f2a510a12516138141a..147d2e3678aa365b4e23f5f9653110d0ae39c134 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -889,13 +889,13 @@ int __pm_runtime_idle(struct device *dev, int rpmflags) unsigned long flags; int retval; - might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); - if (rpmflags & RPM_GET_PUT) { if (!atomic_dec_and_test(&dev->power.usage_count)) return 0; } + might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); + spin_lock_irqsave(&dev->power.lock, flags); retval = rpm_idle(dev, rpmflags); spin_unlock_irqrestore(&dev->power.lock, flags); @@ -921,13 +921,13 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags) unsigned long flags; int retval; - might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); - if (rpmflags & RPM_GET_PUT) { if (!atomic_dec_and_test(&dev->power.usage_count)) return 0; } + might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); + spin_lock_irqsave(&dev->power.lock, flags); retval = rpm_suspend(dev, rpmflags); spin_unlock_irqrestore(&dev->power.lock, flags); @@ -952,7 +952,8 @@ int __pm_runtime_resume(struct device *dev, int rpmflags) unsigned long flags; int retval; - might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); + might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe && + dev->power.runtime_status != RPM_ACTIVE); if (rpmflags & RPM_GET_PUT) atomic_inc(&dev->power.usage_count); diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index a7b46798c81d0452149907e153ae149830fdbceb..39efa7e6c0c0e80ae38669cfb9974b931ee910b9 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -268,6 +268,8 @@ static ssize_t pm_qos_latency_tolerance_store(struct device *dev, value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; else if (!strcmp(buf, "any") || !strcmp(buf, "any\n")) value = PM_QOS_LATENCY_ANY; + else + return -EINVAL; } ret = dev_pm_qos_update_user_latency_tolerance(dev, value); return ret < 0 ? ret : n; diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index 404d94c6c8bc6a4531b0666a77c5b86daab207a6..feba1b21189831229fcd842ccf0995e13c773120 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -141,6 +141,13 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq) struct wake_irq *wirq = _wirq; int res; + /* Maybe abort suspend? */ + if (irqd_is_wakeup_set(irq_get_irq_data(irq))) { + pm_wakeup_event(wirq->dev, 0); + + return IRQ_HANDLED; + } + /* We don't want RPM_ASYNC or RPM_NOWAIT here */ res = pm_runtime_resume(wirq->dev); if (res < 0) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 270cdd40edb4201bd847b9945138ac753e792a42..b758633869657b413e7e5c68e8f81fd42666fe3e 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "power.h" @@ -61,6 +63,8 @@ static LIST_HEAD(wakeup_sources); static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue); +DEFINE_STATIC_SRCU(wakeup_srcu); + static struct wakeup_source deleted_ws = { .name = "deleted", .lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock), @@ -199,7 +203,7 @@ void wakeup_source_remove(struct wakeup_source *ws) spin_lock_irqsave(&events_lock, flags); list_del_rcu(&ws->entry); spin_unlock_irqrestore(&events_lock, flags); - synchronize_rcu(); + synchronize_srcu(&wakeup_srcu); } EXPORT_SYMBOL_GPL(wakeup_source_remove); @@ -333,12 +337,12 @@ void device_wakeup_detach_irq(struct device *dev) void device_wakeup_arm_wake_irqs(void) { struct wakeup_source *ws; + int srcuidx; - rcu_read_lock(); + srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) dev_pm_arm_wake_irq(ws->wakeirq); - - rcu_read_unlock(); + srcu_read_unlock(&wakeup_srcu, srcuidx); } /** @@ -349,12 +353,12 @@ void device_wakeup_arm_wake_irqs(void) void device_wakeup_disarm_wake_irqs(void) { struct wakeup_source *ws; + int srcuidx; - rcu_read_lock(); + srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) dev_pm_disarm_wake_irq(ws->wakeirq); - - rcu_read_unlock(); + srcu_read_unlock(&wakeup_srcu, srcuidx); } /** @@ -808,8 +812,9 @@ void pm_get_active_wakeup_sources(char *pending_wakeup_source, size_t max) struct wakeup_source *ws, *last_active_ws = NULL; int len = 0; bool active = false; + int srcuidx; - rcu_read_lock(); + srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active && len < max) { if (!active) @@ -830,17 +835,17 @@ void pm_get_active_wakeup_sources(char *pending_wakeup_source, size_t max) "Last active Wakeup Source: %s", last_active_ws->name); } - rcu_read_unlock(); + srcu_read_unlock(&wakeup_srcu, srcuidx); } EXPORT_SYMBOL_GPL(pm_get_active_wakeup_sources); void pm_print_active_wakeup_sources(void) { struct wakeup_source *ws; - int active = 0; + int srcuidx, active = 0; struct wakeup_source *last_activity_ws = NULL; - rcu_read_lock(); + srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active) { pr_info("active wakeup source: %s\n", ws->name); @@ -856,7 +861,7 @@ void pm_print_active_wakeup_sources(void) if (!active && last_activity_ws) pr_info("last active wakeup source: %s\n", last_activity_ws->name); - rcu_read_unlock(); + srcu_read_unlock(&wakeup_srcu, srcuidx); } EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); @@ -906,7 +911,21 @@ void pm_wakeup_clear(void) void pm_system_irq_wakeup(unsigned int irq_number) { + struct irq_desc *desc; + const char *name = "null"; + if (pm_wakeup_irq == 0) { + if (msm_show_resume_irq_mask) { + desc = irq_to_desc(irq_number); + if (desc == NULL) + name = "stray irq"; + else if (desc->action && desc->action->name) + name = desc->action->name; + + pr_warn("%s: %d triggered %s\n", __func__, + irq_number, name); + + } pm_wakeup_irq = irq_number; pm_system_wakeup(); } @@ -983,8 +1002,9 @@ void pm_wakep_autosleep_enabled(bool set) { struct wakeup_source *ws; ktime_t now = ktime_get(); + int srcuidx; - rcu_read_lock(); + srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { spin_lock_irq(&ws->lock); if (ws->autosleep_enabled != set) { @@ -998,7 +1018,7 @@ void pm_wakep_autosleep_enabled(bool set) } spin_unlock_irq(&ws->lock); } - rcu_read_unlock(); + srcu_read_unlock(&wakeup_srcu, srcuidx); } #endif /* CONFIG_PM_AUTOSLEEP */ @@ -1059,15 +1079,16 @@ static int print_wakeup_source_stats(struct seq_file *m, static int wakeup_sources_stats_show(struct seq_file *m, void *unused) { struct wakeup_source *ws; + int srcuidx; seq_puts(m, "name\t\t\t\t\tactive_count\tevent_count\twakeup_count\t" "expire_count\tactive_since\ttotal_time\tmax_time\t" "last_change\tprevent_suspend_time\n"); - rcu_read_lock(); + srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) print_wakeup_source_stats(m, ws); - rcu_read_unlock(); + srcu_read_unlock(&wakeup_srcu, srcuidx); print_wakeup_source_stats(m, &deleted_ws); diff --git a/drivers/base/property.c b/drivers/base/property.c index 43a36d68c3fded1602c9e8ce97358264c9f33c8a..7b313b567f4c3b71c81eb48ee740eac79d636511 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -20,6 +20,7 @@ #include struct property_set { + struct device *dev; struct fwnode_handle fwnode; struct property_entry *properties; }; @@ -182,11 +183,12 @@ static int pset_prop_read_string(struct property_set *pset, return 0; } -static inline struct fwnode_handle *dev_fwnode(struct device *dev) +struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? &dev->of_node->fwnode : dev->fwnode; } +EXPORT_SYMBOL_GPL(dev_fwnode); /** * device_property_present - check if a property of a device is present @@ -816,6 +818,7 @@ static struct property_set *pset_copy_set(const struct property_set *pset) void device_remove_properties(struct device *dev) { struct fwnode_handle *fwnode; + struct property_set *pset; fwnode = dev_fwnode(dev); if (!fwnode) @@ -825,16 +828,16 @@ void device_remove_properties(struct device *dev) * the pset. If there is no real firmware node (ACPI/DT) primary * will hold the pset. */ - if (is_pset_node(fwnode)) { + pset = to_pset_node(fwnode); + if (pset) { set_primary_fwnode(dev, NULL); - pset_free_set(to_pset_node(fwnode)); } else { - fwnode = fwnode->secondary; - if (!IS_ERR(fwnode) && is_pset_node(fwnode)) { + pset = to_pset_node(fwnode->secondary); + if (pset && dev == pset->dev) set_secondary_fwnode(dev, NULL); - pset_free_set(to_pset_node(fwnode)); - } } + if (pset && dev == pset->dev) + pset_free_set(pset); } EXPORT_SYMBOL_GPL(device_remove_properties); @@ -862,6 +865,7 @@ int device_add_properties(struct device *dev, struct property_entry *properties) p->fwnode.type = FWNODE_PDATA; set_secondary_fwnode(dev, &p->fwnode); + p->dev = dev; return 0; } EXPORT_SYMBOL_GPL(device_add_properties); diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index fc814a36ad074251b2573181d83d22277f901a47..45fc564bf949206104afa3f9151a56c427ee53a1 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -32,3 +32,12 @@ config REGMAP_IRQ config REGMAP_SWR tristate + +config REGMAP_ALLOW_WRITE_DEBUGFS + depends on REGMAP && DEBUG_FS + bool "Allow REGMAP debugfs write" + default n + help + Say 'y' here to allow the regmap debugfs write. Regmap debugfs write + could be risky when accessing some essential hardwares, so it is not + recommended to enable this option on any production device. diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index b4c5224d22686dbd04e47fc63f63f2977368a85d..1559070d6060ef849bd21b315bb3f273fdbc0a32 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -269,8 +269,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, count, ppos); } -#define REGMAP_ALLOW_WRITE_DEBUGFS -#ifdef REGMAP_ALLOW_WRITE_DEBUGFS +#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS /* * This can be dangerous especially when we have clients such as * PMICs, therefore don't provide any real compile time configuration option @@ -340,7 +339,7 @@ static ssize_t regmap_data_read_file(struct file *file, char __user *user_buf, new_count, ppos); } -#ifdef REGMAP_ALLOW_WRITE_DEBUGFS +#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS static ssize_t regmap_data_write_file(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -633,7 +632,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name) if (map->max_register || regmap_readable(map, 0)) { umode_t registers_mode; -#if defined(REGMAP_ALLOW_WRITE_DEBUGFS) +#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS registers_mode = 0600; #else registers_mode = 0400; diff --git a/drivers/base/regmap/regmap-swr.c b/drivers/base/regmap/regmap-swr.c deleted file mode 100644 index be1eb00ad8769be3b64c6c3ade559e41a4445e78..0000000000000000000000000000000000000000 --- a/drivers/base/regmap/regmap-swr.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2015-2017, 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 -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static int regmap_swr_gather_write(void *context, - const void *reg, size_t reg_size, - const void *val, size_t val_len) -{ - struct device *dev = context; - struct swr_device *swr = to_swr_device(dev); - struct regmap *map = dev_get_regmap(dev, NULL); - size_t addr_bytes; - size_t val_bytes; - int i, ret = 0; - u16 reg_addr = 0; - u8 *value; - - if (map == NULL) { - dev_err(dev, "%s: regmap is NULL\n", __func__); - return -EINVAL; - } - addr_bytes = map->format.reg_bytes; - if (swr == NULL) { - dev_err(dev, "%s: swr device is NULL\n", __func__); - return -EINVAL; - } - if (reg_size != addr_bytes) { - dev_err(dev, "%s: reg size %zd bytes not supported\n", - __func__, reg_size); - return -EINVAL; - } - reg_addr = *(u16 *)reg; - val_bytes = map->format.val_bytes; - /* val_len = val_bytes * val_count */ - for (i = 0; i < (val_len / val_bytes); i++) { - value = (u8 *)val + (val_bytes * i); - ret = swr_write(swr, swr->dev_num, (reg_addr + i), value); - if (ret < 0) { - dev_err(dev, "%s: write reg 0x%x failed, err %d\n", - __func__, (reg_addr + i), ret); - break; - } - } - return ret; -} - -static int regmap_swr_raw_multi_reg_write(void *context, const void *data, - size_t count) -{ - struct device *dev = context; - struct swr_device *swr = to_swr_device(dev); - struct regmap *map = dev_get_regmap(dev, NULL); - size_t addr_bytes; - size_t val_bytes; - size_t pad_bytes; - size_t num_regs; - int i = 0; - int ret = 0; - u16 *reg; - u8 *val; - u8 *buf; - - if (swr == NULL) { - dev_err(dev, "%s: swr device is NULL\n", __func__); - return -EINVAL; - } - - if (map == NULL) { - dev_err(dev, "%s: regmap is NULL\n", __func__); - return -EINVAL; - } - - addr_bytes = map->format.reg_bytes; - val_bytes = map->format.val_bytes; - pad_bytes = map->format.pad_bytes; - - if (addr_bytes + val_bytes + pad_bytes == 0) { - dev_err(dev, "%s: sum of addr, value and pad is 0\n", __func__); - return -EINVAL; - } - num_regs = count / (addr_bytes + val_bytes + pad_bytes); - - reg = kcalloc(num_regs, sizeof(u16), GFP_KERNEL); - if (!reg) - return -ENOMEM; - - val = kcalloc(num_regs, sizeof(u8), GFP_KERNEL); - if (!val) { - ret = -ENOMEM; - goto mem_fail; - } - - buf = (u8 *)data; - for (i = 0; i < num_regs; i++) { - reg[i] = *(u16 *)buf; - buf += (map->format.reg_bytes + map->format.pad_bytes); - val[i] = *buf; - buf += map->format.val_bytes; - } - ret = swr_bulk_write(swr, swr->dev_num, reg, val, num_regs); - if (ret) - dev_err(dev, "%s: multi reg write failed\n", __func__); - - kfree(val); -mem_fail: - kfree(reg); - return ret; -} - -static int regmap_swr_write(void *context, const void *data, size_t count) -{ - struct device *dev = context; - struct regmap *map = dev_get_regmap(dev, NULL); - size_t addr_bytes; - size_t val_bytes; - size_t pad_bytes; - - if (map == NULL) { - dev_err(dev, "%s: regmap is NULL\n", __func__); - return -EINVAL; - } - addr_bytes = map->format.reg_bytes; - val_bytes = map->format.val_bytes; - pad_bytes = map->format.pad_bytes; - - WARN_ON(count < addr_bytes); - - if (count > (addr_bytes + val_bytes + pad_bytes)) - return regmap_swr_raw_multi_reg_write(context, data, count); - else - return regmap_swr_gather_write(context, data, addr_bytes, - (data + addr_bytes), - (count - addr_bytes)); -} - -static int regmap_swr_read(void *context, - const void *reg, size_t reg_size, - void *val, size_t val_size) -{ - struct device *dev = context; - struct swr_device *swr = to_swr_device(dev); - struct regmap *map = dev_get_regmap(dev, NULL); - size_t addr_bytes; - int ret = 0; - u16 reg_addr = 0; - - if (map == NULL) { - dev_err(dev, "%s: regmap is NULL\n", __func__); - return -EINVAL; - } - addr_bytes = map->format.reg_bytes; - if (swr == NULL) { - dev_err(dev, "%s: swr is NULL\n", __func__); - return -EINVAL; - } - if (reg_size != addr_bytes) { - dev_err(dev, "%s: register size %zd bytes not supported\n", - __func__, reg_size); - return -EINVAL; - } - reg_addr = *(u16 *)reg; - ret = swr_read(swr, swr->dev_num, reg_addr, val, val_size); - if (ret < 0) - dev_err(dev, "%s: codec reg 0x%x read failed %d\n", - __func__, reg_addr, ret); - return ret; -} - -static struct regmap_bus regmap_swr = { - .write = regmap_swr_write, - .gather_write = regmap_swr_gather_write, - .read = regmap_swr_read, - .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, - .val_format_endian_default = REGMAP_ENDIAN_NATIVE, -}; - -struct regmap *__regmap_init_swr(struct swr_device *swr, - const struct regmap_config *config, - struct lock_class_key *lock_key, - const char *lock_name) -{ - return __regmap_init(&swr->dev, ®map_swr, &swr->dev, config, - lock_key, lock_name); -} -EXPORT_SYMBOL(__regmap_init_swr); - -struct regmap *__devm_regmap_init_swr(struct swr_device *swr, - const struct regmap_config *config, - struct lock_class_key *lock_key, - const char *lock_name) -{ - return __devm_regmap_init(&swr->dev, ®map_swr, &swr->dev, config, - lock_key, lock_name); -} -EXPORT_SYMBOL(__devm_regmap_init_swr); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/topology.c b/drivers/base/topology.c index df3c97cb4c9982eaf391390bda0cbe0b0db570e5..d6ec1c546f5b485fae183d51df23189481b568ec 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -118,51 +118,19 @@ static int topology_add_dev(unsigned int cpu) return sysfs_create_group(&dev->kobj, &topology_attr_group); } -static void topology_remove_dev(unsigned int cpu) +static int topology_remove_dev(unsigned int cpu) { struct device *dev = get_cpu_device(cpu); sysfs_remove_group(&dev->kobj, &topology_attr_group); -} - -static int topology_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - int rc = 0; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - rc = topology_add_dev(cpu); - break; - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - case CPU_DEAD: - case CPU_DEAD_FROZEN: - topology_remove_dev(cpu); - break; - } - return notifier_from_errno(rc); + return 0; } static int topology_sysfs_init(void) { - int cpu; - int rc = 0; - - cpu_notifier_register_begin(); - - for_each_online_cpu(cpu) { - rc = topology_add_dev(cpu); - if (rc) - goto out; - } - __hotcpu_notifier(topology_cpu_callback, 0); - -out: - cpu_notifier_register_done(); - return rc; + return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE, + "base/topology:prepare", topology_add_dev, + topology_remove_dev); } device_initcall(topology_sysfs_init); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c9441f9d4585a4766c9a8c8d1b7dbcd305f622e1..4d30da26906064642be13628d677c10f64cce9e1 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -272,6 +272,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd) int result, flags; struct nbd_request request; unsigned long size = blk_rq_bytes(req); + struct bio *bio; u32 type; if (req->cmd_type == REQ_TYPE_DRV_PRIV) @@ -305,16 +306,20 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd) return -EIO; } - if (type == NBD_CMD_WRITE) { - struct req_iterator iter; + if (type != NBD_CMD_WRITE) + return 0; + + flags = 0; + bio = req->bio; + while (bio) { + struct bio *next = bio->bi_next; + struct bvec_iter iter; struct bio_vec bvec; - /* - * we are really probing at internals to determine - * whether to set MSG_MORE or not... - */ - rq_for_each_segment(bvec, req, iter) { - flags = 0; - if (!rq_iter_last(bvec, iter)) + + bio_for_each_segment(bvec, bio, iter) { + bool is_last = !next && bio_iter_last(bvec, iter); + + if (is_last) flags = MSG_MORE; dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n", cmd, bvec.bv_len); @@ -325,7 +330,16 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd) result); return -EIO; } + /* + * The completion might already have come in, + * so break for the last one instead of letting + * the iterator do it. This prevents use-after-free + * of the bio. + */ + if (is_last) + break; } + bio = next; } return 0; } @@ -654,7 +668,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, return nbd_size_set(nbd, bdev, nbd->blksize, arg); case NBD_SET_TIMEOUT: - nbd->tag_set.timeout = arg * HZ; + if (arg) { + nbd->tag_set.timeout = arg * HZ; + blk_queue_rq_timeout(nbd->disk->queue, arg * HZ); + } return 0; case NBD_SET_FLAGS: @@ -929,6 +946,7 @@ static int __init nbd_init(void) return -ENOMEM; for (i = 0; i < nbds_max; i++) { + struct request_queue *q; struct gendisk *disk = alloc_disk(1 << part_shift); if (!disk) goto out; @@ -954,12 +972,13 @@ static int __init nbd_init(void) * every gendisk to have its very own request_queue struct. * These structs are big so we dynamically allocate them. */ - disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set); - if (!disk->queue) { + q = blk_mq_init_queue(&nbd_dev[i].tag_set); + if (IS_ERR(q)) { blk_mq_free_tag_set(&nbd_dev[i].tag_set); put_disk(disk); goto out; } + disk->queue = q; /* * Tell the block layer that we are not a rotational device diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 7b274ff4632c6944e32b95d605ee9aa9769f7082..e32badd26c8a3e16c5ae1503d1cd7efc9ab1f0ee 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2788,7 +2788,7 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request) * from the parent. */ page_count = (u32)calc_pages_for(0, length); - pages = ceph_alloc_page_vector(page_count, GFP_KERNEL); + pages = ceph_alloc_page_vector(page_count, GFP_NOIO); if (IS_ERR(pages)) { result = PTR_ERR(pages); pages = NULL; @@ -2922,7 +2922,7 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request) */ size = sizeof (__le64) + sizeof (__le32) + sizeof (__le32); page_count = (u32)calc_pages_for(0, size); - pages = ceph_alloc_page_vector(page_count, GFP_KERNEL); + pages = ceph_alloc_page_vector(page_count, GFP_NOIO); if (IS_ERR(pages)) { ret = PTR_ERR(pages); goto fail_stat_request; @@ -4511,7 +4511,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) segment_size = rbd_obj_bytes(&rbd_dev->header); blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE); q->limits.max_sectors = queue_max_hw_sectors(q); - blk_queue_max_segments(q, segment_size / SECTOR_SIZE); + blk_queue_max_segments(q, USHRT_MAX); blk_queue_max_segment_size(q, segment_size); blk_queue_io_min(q, segment_size); blk_queue_io_opt(q, segment_size); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 3822eae102db33ebba2fe4e2ec9d80a59c077c21..6f78cea75103cfd20fe99120fe6a9f0edd696bc6 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -2163,6 +2163,9 @@ static void skd_send_fitmsg(struct skd_device *skdev, */ qcmd |= FIT_QCMD_MSGSIZE_64; + /* Make sure skd_msg_buf is written before the doorbell is triggered. */ + smp_wmb(); + SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); } @@ -2209,6 +2212,9 @@ static void skd_send_special_fitmsg(struct skd_device *skdev, qcmd = skspcl->mb_dma_address; qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128; + /* Make sure skd_msg_buf is written before the doorbell is triggered. */ + smp_wmb(); + SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); } @@ -4622,15 +4628,16 @@ static void skd_free_disk(struct skd_device *skdev) { struct gendisk *disk = skdev->disk; - if (disk != NULL) { - struct request_queue *q = disk->queue; + if (disk && (disk->flags & GENHD_FL_UP)) + del_gendisk(disk); - if (disk->flags & GENHD_FL_UP) - del_gendisk(disk); - if (q) - blk_cleanup_queue(q); - put_disk(disk); + if (skdev->queue) { + blk_cleanup_queue(skdev->queue); + skdev->queue = NULL; + disk->queue = NULL; } + + put_disk(disk); skdev->disk = NULL; } diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 3c3b8f601469a1e4ac2bc332feebc0eab321773b..10332c24f9610d7e80b154bf36eebb0354ac4576 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -630,11 +630,12 @@ static int virtblk_probe(struct virtio_device *vdev) if (err) goto out_put_disk; - q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set); + q = blk_mq_init_queue(&vblk->tag_set); if (IS_ERR(q)) { err = -ENOMEM; goto out_free_tags; } + vblk->disk->queue = q; q->queuedata = vblk; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 4a80ee752597f02adfc8096e5d14ce9a27e03f0e..d6eaaa25d1cc9ee09d376067e3d7ac01e27c9fb0 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -609,8 +609,6 @@ int xen_blkif_schedule(void *arg) unsigned long timeout; int ret; - xen_blkif_get(blkif); - set_freezable(); while (!kthread_should_stop()) { if (try_to_freeze()) @@ -665,7 +663,6 @@ int xen_blkif_schedule(void *arg) print_stats(ring); ring->xenblkd = NULL; - xen_blkif_put(blkif); return 0; } @@ -1436,34 +1433,35 @@ static int dispatch_rw_block_io(struct xen_blkif_ring *ring, static void make_response(struct xen_blkif_ring *ring, u64 id, unsigned short op, int st) { - struct blkif_response resp; + struct blkif_response *resp; unsigned long flags; union blkif_back_rings *blk_rings; int notify; - resp.id = id; - resp.operation = op; - resp.status = st; - spin_lock_irqsave(&ring->blk_ring_lock, flags); blk_rings = &ring->blk_rings; /* Place on the response ring for the relevant domain. */ switch (ring->blkif->blk_protocol) { case BLKIF_PROTOCOL_NATIVE: - memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt), - &resp, sizeof(resp)); + resp = RING_GET_RESPONSE(&blk_rings->native, + blk_rings->native.rsp_prod_pvt); break; case BLKIF_PROTOCOL_X86_32: - memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt), - &resp, sizeof(resp)); + resp = RING_GET_RESPONSE(&blk_rings->x86_32, + blk_rings->x86_32.rsp_prod_pvt); break; case BLKIF_PROTOCOL_X86_64: - memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt), - &resp, sizeof(resp)); + resp = RING_GET_RESPONSE(&blk_rings->x86_64, + blk_rings->x86_64.rsp_prod_pvt); break; default: BUG(); } + + resp->id = id; + resp->operation = op; + resp->status = st; + blk_rings->common.rsp_prod_pvt++; RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify); spin_unlock_irqrestore(&ring->blk_ring_lock, flags); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index dea61f6ab8cbdbaffedceb4c64bda239b51a63a4..ecb35fe8ca8dbb54f36a85513a09064819acd67a 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -75,9 +75,8 @@ extern unsigned int xenblk_max_queues; struct blkif_common_request { char dummy; }; -struct blkif_common_response { - char dummy; -}; + +/* i386 protocol version */ struct blkif_x86_32_request_rw { uint8_t nr_segments; /* number of segments */ @@ -129,14 +128,6 @@ struct blkif_x86_32_request { } u; } __attribute__((__packed__)); -/* i386 protocol version */ -#pragma pack(push, 4) -struct blkif_x86_32_response { - uint64_t id; /* copied from request */ - uint8_t operation; /* copied from request */ - int16_t status; /* BLKIF_RSP_??? */ -}; -#pragma pack(pop) /* x86_64 protocol version */ struct blkif_x86_64_request_rw { @@ -193,18 +184,12 @@ struct blkif_x86_64_request { } u; } __attribute__((__packed__)); -struct blkif_x86_64_response { - uint64_t __attribute__((__aligned__(8))) id; - uint8_t operation; /* copied from request */ - int16_t status; /* BLKIF_RSP_??? */ -}; - DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, - struct blkif_common_response); + struct blkif_response); DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, - struct blkif_x86_32_response); + struct blkif_response __packed); DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, - struct blkif_x86_64_response); + struct blkif_response); union blkif_back_rings { struct blkif_back_ring native; @@ -281,6 +266,7 @@ struct xen_blkif_ring { wait_queue_head_t wq; atomic_t inflight; + bool active; /* One thread per blkif ring. */ struct task_struct *xenblkd; unsigned int waiting_reqs; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 3cc6d1d86f1efc038f451dab3bb3452bed7de92b..5dfe6e8af140885d4056df3db4aa0a845871282d 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -159,7 +159,7 @@ static int xen_blkif_alloc_rings(struct xen_blkif *blkif) init_waitqueue_head(&ring->shutdown_wq); ring->blkif = blkif; ring->st_print = jiffies; - xen_blkif_get(blkif); + ring->active = true; } return 0; @@ -249,10 +249,12 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif) struct xen_blkif_ring *ring = &blkif->rings[r]; unsigned int i = 0; + if (!ring->active) + continue; + if (ring->xenblkd) { kthread_stop(ring->xenblkd); wake_up(&ring->shutdown_wq); - ring->xenblkd = NULL; } /* The above kthread_stop() guarantees that at this point we @@ -296,7 +298,7 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif) BUG_ON(ring->free_pages_num != 0); BUG_ON(ring->persistent_gnt_c != 0); WARN_ON(i != (XEN_BLKIF_REQS_PER_PAGE * blkif->nr_ring_pages)); - xen_blkif_put(blkif); + ring->active = false; } blkif->nr_ring_pages = 0; /* @@ -313,8 +315,10 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif) static void xen_blkif_free(struct xen_blkif *blkif) { - xen_blkif_disconnect(blkif); + WARN_ON(xen_blkif_disconnect(blkif)); xen_vbd_free(&blkif->vbd); + kfree(blkif->be->mode); + kfree(blkif->be); /* Make sure everything is drained before shutting down */ kmem_cache_free(xen_blkif_cachep, blkif); @@ -509,8 +513,6 @@ static int xen_blkbk_remove(struct xenbus_device *dev) /* Put the reference we set in xen_blkif_alloc(). */ xen_blkif_put(be->blkif); - kfree(be->mode); - kfree(be); return 0; } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 9908597c5209e19f118b01437ce0f362cab8f289..f11d62de227298ffadd370b56194b29f3d40ac48 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2112,9 +2112,9 @@ static int blkfront_resume(struct xenbus_device *dev) /* * Get the bios in the request so we can re-queue them. */ - if (req_op(shadow[i].request) == REQ_OP_FLUSH || - req_op(shadow[i].request) == REQ_OP_DISCARD || - req_op(shadow[i].request) == REQ_OP_SECURE_ERASE || + if (req_op(shadow[j].request) == REQ_OP_FLUSH || + req_op(shadow[j].request) == REQ_OP_DISCARD || + req_op(shadow[j].request) == REQ_OP_SECURE_ERASE || shadow[j].request->cmd_flags & REQ_FUA) { /* * Flush operations don't contain bios, so diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index c9914d6539687de9f2c827acac879aca1f2e0a4f..ed9de1b5436c6b97c8766e24643a1ea024e0d37e 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -41,6 +41,12 @@ static DEFINE_MUTEX(zram_index_mutex); static int zram_major; static const char *default_compressor = "lzo"; +/* + * We don't need to see memory allocation errors more than once every 1 + * second to know that a problem is occurring. + */ +#define ALLOC_ERROR_LOG_RATE_MS 1000 + /* Module params (documentation at end) */ static unsigned int num_devices = 1; @@ -668,6 +674,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, struct zram_meta *meta = zram->meta; struct zcomp_strm *zstrm = NULL; unsigned long alloced_pages; + static unsigned long zram_rs_time; page = bvec->bv_page; if (is_partial_io(bvec)) { @@ -761,8 +768,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, if (handle) goto compress_again; - pr_err("Error allocating memory for compressed page: %u, size=%u\n", - index, clen); + if (printk_timed_ratelimit(&zram_rs_time, + ALLOC_ERROR_LOG_RATE_MS)) + pr_err("Error allocating memory for compressed page: %u, size=%u\n", + index, clen); ret = -ENOMEM; goto out; } @@ -1271,6 +1280,7 @@ static int zram_add(void) zram->disk->private_data = zram; snprintf(zram->disk->disk_name, 16, "zram%d", device_id); + __set_bit(QUEUE_FLAG_FAST, &zram->disk->queue->queue_flags); /* Actual capacity set using syfs (/sys/block/zram/disksize */ set_capacity(zram->disk, 0); /* zram devices sort of resembles non-rotational disks */ @@ -1286,6 +1296,8 @@ static int zram_add(void) blk_queue_io_min(zram->disk->queue, PAGE_SIZE); blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); zram->disk->queue->limits.discard_granularity = PAGE_SIZE; + zram->disk->queue->limits.max_sectors = SECTORS_PER_PAGE; + zram->disk->queue->limits.chunk_sectors = 0; blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); /* * zram_bio_discard() will clear all logical blocks if logical block diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index b793853ff05fa827a33340ddd4766d2694422cd5..3880c90b6d59b48b88302a26a33934f15554c172 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -212,15 +212,28 @@ static int ath3k_load_firmware(struct usb_device *udev, const struct firmware *firmware) { u8 *send_buf; - int len = 0; - int err, pipe, size, sent = 0; - int count = firmware->size; + int err, pipe, len, size, sent = 0; + int count; BT_DBG("udev %p", udev); + if (!firmware || !firmware->data || firmware->size <= 0) { + err = -EINVAL; + BT_ERR("Not a valid FW file"); + return err; + } + + count = firmware->size; + + if (count < FW_HDR_SIZE) { + err = -EINVAL; + BT_ERR("ath3k loading invalid size of file"); + return err; + } + pipe = usb_sndctrlpipe(udev, 0); - send_buf = kmalloc(BULK_SIZE, GFP_KERNEL); + send_buf = kzalloc(BULK_SIZE, GFP_KERNEL); if (!send_buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index bfc36482c96159b54bbdf8630452ffaf6a563c3d..f92775650754688c9c5d2ef6b4ec90940ab4bad4 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -708,6 +708,7 @@ static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } else { BT_PWR_ERR("BT chip state is already :%d no change d\n" , pwr_state); + ret = 0; } break; default: diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c index dc9bb0b906be6a29bd3d39ee3cc09bcc5beb291c..6792e045c7f0499259c08449dcbcd20ab6cc94d6 100644 --- a/drivers/bluetooth/btfm_slim.c +++ b/drivers/bluetooth/btfm_slim.c @@ -127,20 +127,29 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, if (!btfmslim || !ch) return -EINVAL; - BTFMSLIM_DBG("port:%d", ch->port); + BTFMSLIM_DBG("port: %d ch: %d", ch->port, ch->ch); /* Define the channel with below parameters */ - prop.prot = SLIM_AUTO_ISO; - prop.baser = SLIM_RATE_4000HZ; - prop.dataf = (rates == 48000) ? SLIM_CH_DATAF_NOT_DEFINED - : SLIM_CH_DATAF_LPCM_AUDIO; + prop.prot = ((rates == 44100) || (rates == 88200)) ? + SLIM_PUSH : SLIM_AUTO_ISO; + prop.baser = ((rates == 44100) || (rates == 88200)) ? + SLIM_RATE_11025HZ : SLIM_RATE_4000HZ; + prop.dataf = ((rates == 48000) || (rates == 44100) || + (rates == 88200) || (rates == 96000)) ? + SLIM_CH_DATAF_NOT_DEFINED : SLIM_CH_DATAF_LPCM_AUDIO; prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE; - prop.ratem = (rates/4000); + prop.ratem = ((rates == 44100) || (rates == 88200)) ? + (rates/11025) : (rates/4000); prop.sampleszbits = 16; ch_h[0] = ch->ch_hdl; ch_h[1] = (grp) ? (ch+1)->ch_hdl : 0; + BTFMSLIM_INFO("channel define - prot:%d, dataf:%d, auxf:%d", + prop.prot, prop.dataf, prop.auxf); + BTFMSLIM_INFO("channel define - rates:%d, baser:%d, ratem:%d", + rates, prop.baser, prop.ratem); + ret = slim_define_ch(btfmslim->slim_pgd, &prop, ch_h, nchan, grp, &ch->grph); if (ret < 0) { @@ -220,17 +229,34 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, BTFMSLIM_INFO("port:%d, grp: %d, ch->grph:0x%x, ch->ch_hdl:0x%x ", ch->port, grp, ch->grph, ch->ch_hdl); + + /* For 44.1/88.2 Khz A2DP Rx, disconnect the port first */ + if (rxport && + (btfmslim->sample_rate == 44100 || + btfmslim->sample_rate == 88200)) { + BTFMSLIM_DBG("disconnecting the ports, removing the channel"); + ret = slim_disconnect_ports(btfmslim->slim_pgd, + &ch->port_hdl, 1); + if (ret < 0) { + BTFMSLIM_ERR("slim_disconnect_ports failed ret[%d]", + ret); + } + } + /* Remove the channel immediately*/ ret = slim_control_ch(btfmslim->slim_pgd, (grp ? ch->grph : ch->ch_hdl), SLIM_CH_REMOVE, true); if (ret < 0) { BTFMSLIM_ERR("slim_control_ch failed ret[%d]", ret); - ret = slim_disconnect_ports(btfmslim->slim_pgd, - &ch->port_hdl, 1); - if (ret < 0) { - BTFMSLIM_ERR("slim_disconnect_ports failed ret[%d]", - ret); - goto error; + if (btfmslim->sample_rate != 44100 && + btfmslim->sample_rate != 88200) { + ret = slim_disconnect_ports(btfmslim->slim_pgd, + &ch->port_hdl, 1); + if (ret < 0) { + BTFMSLIM_ERR("disconnect_ports failed ret[%d]", + ret); + goto error; + } } } @@ -496,9 +522,18 @@ static int btfm_slim_probe(struct slim_device *slim) /* Driver specific data allocation */ btfm_slim->dev = &slim->dev; ret = btfm_slim_register_codec(&slim->dev); + if (ret) { + BTFMSLIM_ERR("error, registering slimbus codec failed"); + goto free; + } ret = bt_register_slimdev(&slim->dev); + if (ret < 0) { + btfm_slim_unregister_codec(&slim->dev); + goto free; + } return ret; - +free: + slim_remove_device(&btfm_slim->slim_ifd); dealloc: mutex_destroy(&btfm_slim->io_lock); mutex_destroy(&btfm_slim->xfer_lock); diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h index 00d46a5671d9be8b18ee169e49b70872e98de9ec..cc9d14d3de43f682ac82018f563c7633181ba875 100644 --- a/drivers/bluetooth/btfm_slim.h +++ b/drivers/bluetooth/btfm_slim.h @@ -68,6 +68,7 @@ struct btfmslim { uint32_t num_rx_port; uint32_t num_tx_port; + uint32_t sample_rate; struct btfmslim_ch *rx_chs; struct btfmslim_ch *tx_chs; @@ -161,4 +162,12 @@ int btfm_slim_disable_ch(struct btfmslim *btfmslim, * 0 */ int btfm_slim_register_codec(struct device *dev); + +/** + * btfm_slim_unregister_codec: Unregister codec driver in slimbus device node + * @dev: device node + * Returns: + * VOID + */ +void btfm_slim_unregister_codec(struct device *dev); #endif /* BTFM_SLIM_H */ diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 86760cd55a76b9e3cfc213bc6ee9196b5f464fff..53388ed2e8caf44475e2fbf6a54de647c2a09f2e 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -26,6 +26,9 @@ #include #include +static int bt_soc_enable_status; + + static int btfm_slim_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -38,8 +41,31 @@ static unsigned int btfm_slim_codec_read(struct snd_soc_codec *codec, return 0; } +static int bt_soc_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = bt_soc_enable_status; + return 1; +} + +static int bt_soc_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 1; +} + +static const struct snd_kcontrol_new status_controls[] = { + SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, + bt_soc_status_get, + bt_soc_status_put) + +}; + + static int btfm_slim_codec_probe(struct snd_soc_codec *codec) { + snd_soc_add_codec_controls(codec, status_controls, + ARRAY_SIZE(status_controls)); return 0; } @@ -54,8 +80,8 @@ static int btfm_slim_dai_startup(struct snd_pcm_substream *substream, int ret; struct btfmslim *btfmslim = dai->dev->platform_data; - BTFMSLIM_DBG("substream = %s stream = %d", - substream->name, substream->stream); + BTFMSLIM_DBG("substream = %s stream = %d dai->name = %s", + substream->name, substream->stream, dai->name); ret = btfm_slim_hw_init(btfmslim); return ret; } @@ -63,33 +89,12 @@ static int btfm_slim_dai_startup(struct snd_pcm_substream *substream, static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct btfmslim *btfmslim = dai->dev->platform_data; - - BTFMSLIM_DBG("substream = %s stream = %d", - substream->name, substream->stream); - btfm_slim_hw_deinit(btfmslim); -} - -static int btfm_slim_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - BTFMSLIM_DBG("dai_name = %s DAI-ID %x rate %d num_ch %d", - dai->name, dai->id, params_rate(params), - params_channels(params)); - - return 0; -} - -int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - int i, ret = -EINVAL; + int i; struct btfmslim *btfmslim = dai->dev->platform_data; struct btfmslim_ch *ch; uint8_t rxport, grp = false, nchan = 1; - BTFMSLIM_DBG("dai->name:%s, dai->id: %d, dai->rate: %d", dai->name, + BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); switch (dai->id) { @@ -110,7 +115,7 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, case BTFM_SLIM_NUM_CODEC_DAIS: default: BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); - return ret; + return; } /* Search for dai->id matched port handler */ @@ -122,24 +127,39 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) || (ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) { BTFMSLIM_ERR("ch is invalid!!"); - return ret; + return; } - ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, grp, nchan); - return ret; + btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan); + btfm_slim_hw_deinit(btfmslim); } -int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream, +static int btfm_slim_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + BTFMSLIM_DBG("dai->name = %s DAI-ID %x rate %d num_ch %d", + dai->name, dai->id, params_rate(params), + params_channels(params)); + + return 0; +} + +static int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int i, ret = -EINVAL; struct btfmslim *btfmslim = dai->dev->platform_data; struct btfmslim_ch *ch; uint8_t rxport, grp = false, nchan = 1; + bt_soc_enable_status = 0; - BTFMSLIM_DBG("dai->name:%s, dai->id: %d, dai->rate: %d", dai->name, + BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); + /* save sample rate */ + btfmslim->sample_rate = dai->rate; + switch (dai->id) { case BTFM_FM_SLIM_TX: grp = true; nchan = 2; @@ -172,7 +192,12 @@ int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream, BTFMSLIM_ERR("ch is invalid!!"); return ret; } - ret = btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan); + + ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, grp, nchan); + + /* save the enable channel status */ + if (ret == 0) + bt_soc_enable_status = 1; return ret; } @@ -282,6 +307,9 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai, *tx_num = 0; *rx_num = num; break; + default: + BTFMSLIM_ERR("Unsupported DAI %d", dai->id); + return -EINVAL; } do { @@ -318,7 +346,6 @@ static struct snd_soc_dai_ops btfmslim_dai_ops = { .shutdown = btfm_slim_dai_shutdown, .hw_params = btfm_slim_dai_hw_params, .prepare = btfm_slim_dai_prepare, - .hw_free = btfm_slim_dai_hw_free, .set_channel_map = btfm_slim_dai_set_channel_map, .get_channel_map = btfm_slim_dai_get_channel_map, }; @@ -358,10 +385,12 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { .id = BTFM_BT_SCO_A2DP_SLIM_RX, .playback = { .stream_name = "SCO A2DP RX Playback", + /* 8/16/44.1/48/88.2/96 Khz */ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 - | SNDRV_PCM_RATE_48000, /* 8 or 16 or 48 Khz*/ + | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 48000, + .rate_max = 96000, .rate_min = 8000, .channels_min = 1, .channels_max = 1, @@ -387,7 +416,7 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { static struct snd_soc_codec_driver btfmslim_codec = { .probe = btfm_slim_codec_probe, .remove = btfm_slim_codec_remove, - .read = btfm_slim_codec_read, + .read = btfm_slim_codec_read, .write = btfm_slim_codec_write, }; @@ -406,5 +435,12 @@ int btfm_slim_register_codec(struct device *dev) return ret; } +void btfm_slim_unregister_codec(struct device *dev) +{ + BTFMSLIM_DBG(""); + /* Unregister Codec driver */ + snd_soc_unregister_codec(dev); +} + MODULE_DESCRIPTION("BTFM Slimbus Codec driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index c2d5b7b7bde9e15fcfa1d0b756ca79f334d828d6..6615189350861d550fcbd45c039605ca33e5bf5f 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -39,6 +39,7 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim) { int ret = 0; uint8_t reg_val; + uint16_t reg; BTFMSLIM_DBG(""); @@ -46,20 +47,20 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim) return -EINVAL; /* Get SB_SLAVE_HW_REV_MSB value*/ - ret = btfm_slim_read(btfmslim, CHRK_SB_SLAVE_HW_REV_MSB, 1, - ®_val, IFD); + reg = CHRK_SB_SLAVE_HW_REV_MSB; + ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to read (%d)", ret); + BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg); goto error; } BTFMSLIM_DBG("Major Rev: 0x%x, Minor Rev: 0x%x", (reg_val & 0xF0) >> 4, (reg_val & 0x0F)); /* Get SB_SLAVE_HW_REV_LSB value*/ - ret = btfm_slim_read(btfmslim, CHRK_SB_SLAVE_HW_REV_LSB, 1, - ®_val, IFD); + reg = CHRK_SB_SLAVE_HW_REV_LSB; + ret = btfm_slim_read(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to read (%d)", ret); + BTFMSLIM_ERR("failed to read (%d) reg 0x%x", ret, reg); goto error; } BTFMSLIM_DBG("Step Rev: 0x%x", reg_val); @@ -68,62 +69,131 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim) return ret; } +static inline int is_fm_port(uint8_t port_num) +{ + if (port_num == CHRK_SB_PGD_PORT_TX1_FM || + port_num == CHRK_SB_PGD_PORT_TX2_FM) + return 1; + else + return 0; +} int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, uint8_t rxport, uint8_t enable) { int ret = 0; - uint8_t reg_val = 0; + uint8_t reg_val = 0, en; + uint8_t rxport_num = 0; uint16_t reg; + uint8_t prev_reg_val = 0; - BTFMSLIM_DBG("enable(%d)", enable); + BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable); if (rxport) { - /* Port enable */ - reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10); - } else { /* txport */ - /* Multiple Channel Setting - only FM Tx will be multiple - * channel - */ - if (enable && (port_num == CHRK_SB_PGD_PORT_TX1_FM || - port_num == CHRK_SB_PGD_PORT_TX2_FM)) { - - reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) | - (0x1 << CHRK_SB_PGD_PORT_TX2_FM); - reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + BTFMSLIM_DBG("sample rate is %d", btfmslim->sample_rate); + if (enable) { + /* For SCO Rx, A2DP Rx other than 44.1 and 88.2Khz */ + if (port_num < 24) { + rxport_num = port_num - 16; + reg_val = 0x01 << rxport_num; + reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0( + rxport_num); + } else { + rxport_num = port_num - 24; + reg_val = 0x01 << rxport_num; + reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_1( + rxport_num); + } + + if (btfmslim->sample_rate == 44100 || + btfmslim->sample_rate == 88200) { + BTFMSLIM_DBG("unsetting multichannel bit"); + ret = btfm_slim_read(btfmslim, reg, 1, + &prev_reg_val, IFD); + if (ret < 0) { + BTFMSLIM_ERR("error %d reading", ret); + prev_reg_val = 0; + } + BTFMSLIM_DBG("prev_reg_val (%d) from reg(%x)", + prev_reg_val, reg); + reg_val = prev_reg_val & ~reg_val; + } else + BTFMSLIM_DBG("setting multichannel bit"); + + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to write (%d)", ret); + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); goto error; } } + /* Port enable */ + reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10); + goto enable_disable_rxport; + } + if (!enable) + goto enable_disable_txport; - /* Enable Tx port hw auto recovery for underrun or - * overrun error - */ - reg_val = (enable) ? (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY | - CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY) : 0x0; - - ret = btfm_slim_write(btfmslim, - CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num), 1, - ®_val, IFD); + /* txport */ + /* Multiple Channel Setting */ + if (is_fm_port(port_num)) { + reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) | + (0x1 << CHRK_SB_PGD_PORT_TX2_FM); + reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); + goto error; + } + } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) { + /* SCO Tx */ + reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO; + reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) { - BTFMSLIM_ERR("failed to write (%d)", ret); + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); goto error; } + } - /* Port enable */ - reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num); + /* Enable Tx port hw auto recovery for underrun or overrun error */ + reg_val = (CHRK_ENABLE_OVERRUN_AUTO_RECOVERY | + CHRK_ENABLE_UNDERRUN_AUTO_RECOVERY); + reg = CHRK_SB_PGD_PORT_TX_OR_UR_CFGN(port_num); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); + goto error; } +enable_disable_txport: + /* Port enable */ + reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num); + +enable_disable_rxport: if (enable) - /* Set water mark to 1 and enable the port */ - reg_val = CHRK_SB_PGD_PORT_ENABLE | CHRK_SB_PGD_PORT_WM_LB; + en = CHRK_SB_PGD_PORT_ENABLE; else - reg_val = CHRK_SB_PGD_PORT_DISABLE; + en = CHRK_SB_PGD_PORT_DISABLE; + + if (is_fm_port(port_num)) + reg_val = en | CHRK_SB_PGD_PORT_WM_L8; + else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) + reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en; + else + reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en; + + if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO) + BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x", + reg_val, reg); ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) - BTFMSLIM_ERR("failed to write (%d)", ret); + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg); error: return ret; diff --git a/drivers/bluetooth/btfm_slim_wcn3990.h b/drivers/bluetooth/btfm_slim_wcn3990.h index 6bbdb6b6e67843dd3323c6b6b5e56cea06ed46c4..b2723ff961034e943ffe8054b50b9ed9d2188130 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.h +++ b/drivers/bluetooth/btfm_slim_wcn3990.h @@ -68,6 +68,7 @@ #define CHRK_SB_PGD_PORT_WM_L1 (0x1 << 1) #define CHRK_SB_PGD_PORT_WM_L2 (0x2 << 1) #define CHRK_SB_PGD_PORT_WM_L3 (0x3 << 1) +#define CHRK_SB_PGD_PORT_WM_L8 (0x8 << 1) #define CHRK_SB_PGD_PORT_WM_LB (0xB << 1) #define CHRK_SB_PGD_PORT_RX_NUM 16 diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index d02f2c14df32545782f4d7759bb4409e482cc063..c738baeb6d45cd3281b28ac189b42e2c42b27c85 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1682,8 +1682,12 @@ static int btmrvl_sdio_resume(struct device *dev) /* Disable platform specific wakeup interrupt */ if (card->plt_wake_cfg && card->plt_wake_cfg->irq_bt >= 0) { disable_irq_wake(card->plt_wake_cfg->irq_bt); - if (!card->plt_wake_cfg->wake_by_bt) - disable_irq(card->plt_wake_cfg->irq_bt); + disable_irq(card->plt_wake_cfg->irq_bt); + if (card->plt_wake_cfg->wake_by_bt) + /* Undo our disable, since interrupt handler already + * did this. + */ + enable_irq(card->plt_wake_cfg->irq_bt); } return 0; diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 28afd5d585f951a6953bfacc8b9ad1aa0e0e65b5..f64e86f40cd905ad11210acb50e473c3e9926c64 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -1,7 +1,7 @@ /* * Bluetooth supports for Qualcomm Atheros chips * - * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2017 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 @@ -27,6 +27,9 @@ #define VERSION "0.1" +#define MAX_PATCH_FILE_SIZE (100*1024) +#define MAX_NVM_FILE_SIZE (10*1024) + static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) { struct sk_buff *skb; @@ -285,27 +288,63 @@ static int rome_download_firmware(struct hci_dev *hdev, struct rome_config *config) { const struct firmware *fw; + u32 type_len, length; + struct tlv_type_hdr *tlv; int ret; - BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname); - + BT_INFO("%s: ROME Downloading file: %s", hdev->name, config->fwname); ret = request_firmware(&fw, config->fwname, &hdev->dev); - if (ret) { - BT_ERR("%s: Failed to request file: %s (%d)", hdev->name, - config->fwname, ret); + + if (ret || !fw || !fw->data || fw->size <= 0) { + BT_ERR("Failed to request file: err = (%d)", ret); + ret = ret ? ret : -EINVAL; return ret; } - rome_tlv_check_data(config, fw); + if (config->type != TLV_TYPE_NVM && + config->type != TLV_TYPE_PATCH) { + ret = -EINVAL; + BT_ERR("TLV_NVM dload: wrong config type selected"); + goto exit; + } + + if (config->type == TLV_TYPE_PATCH && + (fw->size > MAX_PATCH_FILE_SIZE)) { + ret = -EINVAL; + BT_ERR("TLV_PATCH dload: wrong patch file sizes"); + goto exit; + } else if (config->type == TLV_TYPE_NVM && + (fw->size > MAX_NVM_FILE_SIZE)) { + ret = -EINVAL; + BT_ERR("TLV_NVM dload: wrong NVM file sizes"); + goto exit; + } + + if (fw->size < sizeof(struct tlv_type_hdr)) { + ret = -EINVAL; + BT_ERR("Firware size smaller to fit minimum value"); + goto exit; + } + + tlv = (struct tlv_type_hdr *)fw->data; + type_len = le32_to_cpu(tlv->type_len); + length = (type_len >> 8) & 0x00ffffff; + if (fw->size - 4 != length) { + ret = -EINVAL; + BT_ERR("Requested size not matching size in header"); + goto exit; + } + + rome_tlv_check_data(config, fw); ret = rome_tlv_download_request(hdev, fw); + if (ret) { - BT_ERR("%s: Failed to download file: %s (%d)", hdev->name, - config->fwname, ret); + BT_ERR("Failed to download FW: error = (%d)", ret); } +exit: release_firmware(fw); - return ret; } @@ -316,8 +355,9 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) int err; cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD; - cmd[1] = 0x02; /* TAG ID */ - cmd[2] = sizeof(bdaddr_t); /* size */ + /* Set the TAG ID of 0x02 for NVM set and size of tag */ + cmd[1] = 0x02; + cmd[2] = sizeof(bdaddr_t); memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index dd220fad366cbcdc1e42905e4d0744fe252ba526..693028659cccea3994159ecc89bb7583de053055 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -342,6 +342,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK }, /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, @@ -2924,6 +2925,12 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_QCA_ROME) { data->setup_on_usb = btusb_setup_qca; hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + + /* QCA Rome devices lose their updated firmware over suspend, + * but the USB hub doesn't notice any status change. + * Explicitly request a device reset on resume. + */ + set_bit(BTUSB_RESET_RESUME, &data->flags); } #ifdef CONFIG_BT_HCIBTUSB_RTL diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 8f6c23c20c52d83b4097dabfa64b82d6b360cf4b..deed580135552491a1ace7314d98a07ce04a1297 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -287,6 +287,9 @@ static int bcm_open(struct hci_uart *hu) hu->priv = bcm; + if (!hu->tty->dev) + goto out; + mutex_lock(&bcm_device_lock); list_for_each(p, &bcm_device_list) { struct bcm_device *dev = list_entry(p, struct bcm_device, list); @@ -307,7 +310,7 @@ static int bcm_open(struct hci_uart *hu) } mutex_unlock(&bcm_device_lock); - +out: return 0; } diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 9e271286c5e553dbd6112f8a83393c8bf5b5dd43..73306384af6cc0f6b9a83ed105b7e8d1ca3b2a72 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -307,6 +307,9 @@ static int intel_set_power(struct hci_uart *hu, bool powered) struct list_head *p; int err = -ENODEV; + if (!hu->tty->dev) + return err; + mutex_lock(&intel_device_list_lock); list_for_each(p, &intel_device_list) { @@ -379,6 +382,9 @@ static void intel_busy_work(struct work_struct *work) struct intel_data *intel = container_of(work, struct intel_data, busy_work); + if (!intel->hu->tty->dev) + return; + /* Link is busy, delay the suspend */ mutex_lock(&intel_device_list_lock); list_for_each(p, &intel_device_list) { @@ -889,6 +895,8 @@ static int intel_setup(struct hci_uart *hu) list_for_each(p, &intel_device_list) { struct intel_device *dev = list_entry(p, struct intel_device, list); + if (!hu->tty->dev) + break; if (hu->tty->dev->parent == dev->pdev->dev.parent) { if (device_may_wakeup(&dev->pdev->dev)) { set_bit(STATE_LPM_ENABLED, &intel->flags); @@ -1056,6 +1064,9 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb) BT_DBG("hu %p skb %p", hu, skb); + if (!hu->tty->dev) + goto out_enqueue; + /* Be sure our controller is resumed and potential LPM transaction * completed before enqueuing any packet. */ @@ -1072,7 +1083,7 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb) } } mutex_unlock(&intel_device_list_lock); - +out_enqueue: skb_queue_tail(&intel->txq, skb); return 0; diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 890082315054d0c2043151a4ea25e107fe61b1bb..10f56133b2816020f4bd657634a120ebf0744912 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -1755,14 +1755,17 @@ static int cci_pmu_probe(struct platform_device *pdev) raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock); mutex_init(&cci_pmu->reserve_mutex); atomic_set(&cci_pmu->active_events, 0); - cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus); + cpumask_set_cpu(get_cpu(), &cci_pmu->cpus); ret = cci_pmu_init(cci_pmu, pdev); - if (ret) + if (ret) { + put_cpu(); return ret; + } cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_CCI_ONLINE, &cci_pmu->node); + put_cpu(); pr_info("ARM %s PMU driver probed", cci_pmu->model->name); return 0; } diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index aee83462b796bde9b8f6b2e7d500e9d5d5320288..45d7ecc66b22bbef478dd0808fc69128efa7fbc2 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c @@ -1271,11 +1271,16 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) int len = snprintf(NULL, 0, "ccn_%d", ccn->dt.id); name = devm_kzalloc(ccn->dev, len + 1, GFP_KERNEL); + if (!name) { + err = -ENOMEM; + goto error_choose_name; + } snprintf(name, len + 1, "ccn_%d", ccn->dt.id); } /* Perf driver registration */ ccn->dt.pmu = (struct pmu) { + .module = THIS_MODULE, .attr_groups = arm_ccn_pmu_attr_groups, .task_ctx_nr = perf_invalid_context, .event_init = arm_ccn_pmu_event_init, @@ -1297,7 +1302,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) } /* Pick one CPU which we will use to collect data from CCN... */ - cpumask_set_cpu(smp_processor_id(), &ccn->dt.cpu); + cpumask_set_cpu(get_cpu(), &ccn->dt.cpu); /* Also make sure that the overflow interrupt is handled by this CPU */ if (ccn->irq) { @@ -1314,10 +1319,13 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE, &ccn->dt.node); + put_cpu(); return 0; error_pmu_register: error_set_affinity: + put_cpu(); +error_choose_name: ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id); for (i = 0; i < ccn->num_xps; i++) writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); @@ -1578,8 +1586,8 @@ static int __init arm_ccn_init(void) static void __exit arm_ccn_exit(void) { - cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_CCN_ONLINE); platform_driver_unregister(&arm_ccn_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_CCN_ONLINE); } module_init(arm_ccn_init); diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index c7f39690318473d4b75bca11c0c3fd4830f4d084..70db4d5638a6338632a916e4ee07f0f4b3ca5e04 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -720,7 +720,7 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) if (mbus->hw_io_coherency) w->mbus_attr |= ATTR_HW_COHERENCY; w->base = base & DDR_BASE_CS_LOW_MASK; - w->size = (size | ~DDR_SIZE_MASK) + 1; + w->size = (u64)(size | ~DDR_SIZE_MASK) + 1; } } mvebu_mbus_dram_info.num_cs = cs; diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 795c9d9c96a6d5ae08c036a221ae1f9a4b1f9c1b..2051d926e3037947386bfa64ba04a236a8ed313c 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -178,6 +178,7 @@ static struct bus_type sunxi_rsb_bus = { .match = sunxi_rsb_device_match, .probe = sunxi_rsb_device_probe, .remove = sunxi_rsb_device_remove, + .uevent = of_device_uevent_modalias, }; static void sunxi_rsb_dev_release(struct device *dev) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 3e1367a7cb4c78ef23c9657ad09ce4f15f44840f..1ea2053da338f1e46942eb1599588760eb5cf964 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -582,6 +582,16 @@ config DEVPORT source "drivers/s390/char/Kconfig" +config MSM_SMD_PKT + bool "Enable device interface for some SMD packet ports" + default n + depends on MSM_SMD + help + smd_pkt driver provides the interface for the userspace clients + to communicate over smd via device nodes. This enable the + usersapce clients to read and write to some smd packets channel + for MSM chipset. + config TILE_SROM bool "Character-device access via hypervisor to the Tilera SPI ROM" depends on TILE @@ -604,5 +614,12 @@ config MSM_ADSPRPC 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 b73165a7d3c158c6dc48e80d37cff72c56631cb0..81283c4642f6769426f6dd56e67e5c1425522708 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o +obj-$(CONFIG_MSM_SMD_PKT) += msm_smd_pkt.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o @@ -65,3 +66,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/adsprpc.c b/drivers/char/adsprpc.c index b18a172f2a3ce4f8e5c62b5630dc5b53f1a3abf9..3f35d5486b1f8cc5370a7d5ebff62e8812b63a7c 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, 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 @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -42,23 +44,33 @@ #include #include #include +#include #include "adsprpc_compat.h" #include "adsprpc_shared.h" +#include #include - +#include #define TZ_PIL_PROTECT_MEM_SUBSYS_ID 0x0C #define TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID 0x0D #define TZ_PIL_AUTH_QDSP6_PROC 1 +#define ADSP_MMAP_HEAP_ADDR 4 +#define ADSP_MMAP_REMOTE_HEAP_ADDR 8 #define FASTRPC_ENOSUCH 39 #define VMID_SSC_Q6 5 #define VMID_ADSP_Q6 6 #define DEBUGFS_SIZE 1024 +#define AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME "audio_pdr_adsprpc" +#define AUDIO_PDR_ADSP_SERVICE_NAME "avs/audio" + #define RPC_TIMEOUT (5 * HZ) #define BALIGN 128 #define NUM_CHANNELS 4 /* adsp, mdsp, slpi, cdsp*/ #define NUM_SESSIONS 9 /*8 compute, 1 cpz*/ -#define M_FDLIST 16 +#define M_FDLIST (16) +#define M_CRCLIST (64) +#define SESSION_ID_INDEX (30) +#define FASTRPC_CTX_MAGIC (0xbeeddeed) #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) @@ -68,27 +80,44 @@ #define FASTRPC_LINK_CONNECTING (0x1) #define FASTRPC_LINK_CONNECTED (0x3) #define FASTRPC_LINK_DISCONNECTING (0x7) +#define FASTRPC_LINK_REMOTE_DISCONNECTING (0x8) +#define FASTRPC_GLINK_INTENT_LEN (64) -#define PERF_KEYS "count:flush:map:copy:glink:getargs:putargs:invalidate:invoke" +#define PERF_KEYS \ + "count:flush:map:copy:glink:getargs:putargs:invalidate:invoke:tid:ptr" #define FASTRPC_STATIC_HANDLE_LISTENER (3) #define FASTRPC_STATIC_HANDLE_MAX (20) +#define FASTRPC_LATENCY_CTRL_ENB (1) + +#define INIT_FILELEN_MAX (2*1024*1024) +#define INIT_MEMLEN_MAX (8*1024*1024) #define PERF_END (void)0 #define PERF(enb, cnt, ff) \ {\ struct timespec startT = {0};\ - if (enb) {\ + int64_t *counter = cnt;\ + if (enb && counter) {\ getnstimeofday(&startT);\ } \ ff ;\ - if (enb) {\ - cnt += getnstimediff(&startT);\ + if (enb && counter) {\ + *counter += getnstimediff(&startT);\ } \ } +#define GET_COUNTER(perf_ptr, offset) \ + (perf_ptr != NULL ?\ + (((offset >= 0) && (offset < PERF_KEY_MAX)) ?\ + (int64_t *)(perf_ptr + offset)\ + : (int64_t *)NULL) : (int64_t *)NULL) + static int fastrpc_glink_open(int cid); static void fastrpc_glink_close(void *chan, int cid); +static int fastrpc_audio_pdr_notifier_cb(struct notifier_block *nb, + unsigned long code, + void *data); static struct dentry *debugfs_root; static struct dentry *debugfs_global_file; @@ -104,11 +133,11 @@ static inline uint64_t buf_page_offset(uint64_t buf) return offset; } -static inline int buf_num_pages(uint64_t buf, ssize_t len) +static inline uint64_t buf_num_pages(uint64_t buf, size_t len) { uint64_t start = buf_page_start(buf) >> PAGE_SHIFT; uint64_t end = (((uint64_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT; - int nPages = end - start + 1; + uint64_t nPages = end - start + 1; return nPages; } @@ -133,6 +162,12 @@ static inline uint64_t ptr_to_uint64(void *ptr) return addr; } +struct secure_vm { + int *vmid; + int *vmperm; + int vmcount; +}; + struct fastrpc_file; struct fastrpc_buf { @@ -140,7 +175,7 @@ struct fastrpc_buf { struct fastrpc_file *fl; void *virt; uint64_t phys; - ssize_t size; + size_t size; }; struct fastrpc_ctx_lst; @@ -166,12 +201,14 @@ struct smq_invoke_ctx { unsigned int *attrs; struct fastrpc_mmap **maps; struct fastrpc_buf *buf; - ssize_t used; + size_t used; struct fastrpc_file *fl; uint32_t sc; struct overlap *overs; struct overlap **overps; struct smq_msg msg; + uint32_t *crc; + unsigned int magic; }; struct fastrpc_ctx_lst { @@ -180,6 +217,7 @@ struct fastrpc_ctx_lst { }; struct fastrpc_smmu { + struct device *dev; struct dma_iommu_mapping *mapping; int cb; int enabled; @@ -194,6 +232,16 @@ struct fastrpc_session_ctx { int used; }; +struct fastrpc_static_pd { + char *spdname; + struct notifier_block pdrnb; + struct notifier_block get_service_nb; + void *pdrhandle; + int pdrcount; + int prevpdrcount; + int ispdup; +}; + struct fastrpc_glink_info { int link_state; int port_state; @@ -208,14 +256,20 @@ struct fastrpc_channel_ctx { void *chan; struct device *dev; struct fastrpc_session_ctx session[NUM_SESSIONS]; + struct fastrpc_static_pd spd[NUM_SESSIONS]; struct completion work; + struct completion workport; struct notifier_block nb; struct kref kref; int sesscount; int ssrcount; void *handle; int prevssrcount; + int issubsystemup; int vmid; + struct secure_vm rhvm; + int ramdumpenabled; + void *remoteheap_ramdump_dev; struct fastrpc_glink_info link; }; @@ -226,12 +280,14 @@ struct fastrpc_apps { struct mutex smd_mutex; struct smq_phy_page range; struct hlist_head maps; + uint32_t staticpd_flags; dev_t dev_no; int compat; struct hlist_head drivers; spinlock_t hlock; struct ion_client *client; struct device *dev; + unsigned int latency; }; struct fastrpc_mmap { @@ -245,9 +301,9 @@ struct fastrpc_mmap { struct dma_buf_attachment *attach; struct ion_handle *handle; uint64_t phys; - ssize_t size; + size_t size; uintptr_t va; - ssize_t len; + size_t len; int refs; uintptr_t raddr; int uncached; @@ -255,6 +311,19 @@ struct fastrpc_mmap { uintptr_t attr; }; +enum fastrpc_perfkeys { + PERF_COUNT = 0, + PERF_FLUSH = 1, + PERF_MAP = 2, + PERF_COPY = 3, + PERF_LINK = 4, + PERF_GETARGS = 5, + PERF_PUTARGS = 6, + PERF_INVARGS = 7, + PERF_INVOKE = 8, + PERF_KEY_MAX = 9, +}; + struct fastrpc_perf { int64_t count; int64_t flush; @@ -265,6 +334,8 @@ struct fastrpc_perf { int64_t putargs; int64_t invargs; int64_t invoke; + int64_t tid; + struct hlist_node hn; }; struct fastrpc_file { @@ -277,13 +348,21 @@ struct fastrpc_file { struct fastrpc_session_ctx *secsctx; uint32_t mode; uint32_t profile; + int sessionid; int tgid; int cid; int ssrcount; int pd; + char *spdname; + int file_close; struct fastrpc_apps *apps; - struct fastrpc_perf perf; + struct hlist_head perf; struct dentry *debugfs_file; + struct mutex perf_mutex; + struct pm_qos_request pm_qos_req; + int qos_request; + struct mutex map_mutex; + struct mutex fl_map_mutex; }; static struct fastrpc_apps gfa; @@ -294,6 +373,14 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .subsys = "adsp", .link.link_info.edge = "lpass", .link.link_info.transport = "smem", + .spd = { + { + .spdname = + AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME, + .pdrnb.notifier_call = + fastrpc_audio_pdr_notifier_cb, + } + }, }, { .name = "mdsprpc-smd", @@ -306,7 +393,6 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .subsys = "slpi", .link.link_info.edge = "dsps", .link.link_info.transport = "smem", - .vmid = VMID_SSC_Q6, }, { .name = "cdsprpc-smd", @@ -316,6 +402,9 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { }, }; +static int hlosvm[1] = {VMID_HLOS}; +static int hlosvmperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; + static inline int64_t getnstimediff(struct timespec *start) { int64_t ns; @@ -327,9 +416,49 @@ static inline int64_t getnstimediff(struct timespec *start) return ns; } +static inline int64_t *getperfcounter(struct fastrpc_file *fl, int key) +{ + int err = 0; + int64_t *val = NULL; + struct fastrpc_perf *perf = NULL, *fperf = NULL; + struct hlist_node *n = NULL; + + VERIFY(err, !IS_ERR_OR_NULL(fl)); + if (err) + goto bail; + + mutex_lock(&fl->perf_mutex); + hlist_for_each_entry_safe(perf, n, &fl->perf, hn) { + if (perf->tid == current->pid) { + fperf = perf; + break; + } + } + + if (IS_ERR_OR_NULL(fperf)) { + fperf = kzalloc(sizeof(*fperf), GFP_KERNEL); + + VERIFY(err, !IS_ERR_OR_NULL(fperf)); + if (err) { + mutex_unlock(&fl->perf_mutex); + kfree(fperf); + goto bail; + } + + fperf->tid = current->pid; + hlist_add_head(&fperf->hn, &fl->perf); + } + + val = ((int64_t *)fperf) + key; + mutex_unlock(&fl->perf_mutex); +bail: + return val; +} + + static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache) { - struct fastrpc_file *fl = buf == 0 ? 0 : buf->fl; + struct fastrpc_file *fl = buf == NULL ? NULL : buf->fl; int vmid; if (!fl) @@ -353,7 +482,7 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache) hyp_assign_phys(buf->phys, buf_page_size(buf->size), srcVM, 2, destVM, destVMperm, 1); } - dma_free_coherent(fl->sctx->dev, buf->size, buf->virt, + dma_free_coherent(fl->sctx->smmu.dev, buf->size, buf->virt, buf->phys); } kfree(buf); @@ -366,7 +495,7 @@ static void fastrpc_buf_list_free(struct fastrpc_file *fl) do { struct hlist_node *n; - free = 0; + free = NULL; spin_lock(&fl->hlock); hlist_for_each_entry_safe(buf, n, &fl->bufs, hn) { hlist_del_init(&buf->hn); @@ -381,31 +510,56 @@ static void fastrpc_buf_list_free(struct fastrpc_file *fl) static void fastrpc_mmap_add(struct fastrpc_mmap *map) { - struct fastrpc_file *fl = map->fl; + if (map->flags == ADSP_MMAP_HEAP_ADDR || + map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + struct fastrpc_apps *me = &gfa; - spin_lock(&fl->hlock); - hlist_add_head(&map->hn, &fl->maps); - spin_unlock(&fl->hlock); + spin_lock(&me->hlock); + hlist_add_head(&map->hn, &me->maps); + spin_unlock(&me->hlock); + } else { + struct fastrpc_file *fl = map->fl; + + hlist_add_head(&map->hn, &fl->maps); + } } -static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, - ssize_t len, int mflags, int refs, struct fastrpc_mmap **ppmap) +static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, + uintptr_t va, size_t len, int mflags, int refs, + struct fastrpc_mmap **ppmap) { - struct fastrpc_mmap *match = 0, *map; + struct fastrpc_apps *me = &gfa; + struct fastrpc_mmap *match = NULL, *map = NULL; struct hlist_node *n; - spin_lock(&fl->hlock); - hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) - map->refs++; - match = map; - break; + if ((va + len) < va) + return -EOVERFLOW; + if (mflags == ADSP_MMAP_HEAP_ADDR || + mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + spin_lock(&me->hlock); + hlist_for_each_entry_safe(map, n, &me->maps, hn) { + if (va >= map->va && + va + len <= map->va + map->len && + map->fd == fd) { + if (refs) + map->refs++; + match = map; + break; + } + } + spin_unlock(&me->hlock); + } else { + hlist_for_each_entry_safe(map, n, &fl->maps, hn) { + if (va >= map->va && + va + len <= map->va + map->len && + map->fd == fd) { + if (refs) + map->refs++; + match = map; + break; + } } } - spin_unlock(&fl->hlock); if (match) { *ppmap = match; return 0; @@ -413,10 +567,27 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, return -ENOTTY; } +static int dma_alloc_memory(dma_addr_t *region_phys, void **vaddr, size_t size) +{ + struct fastrpc_apps *me = &gfa; + + if (me->dev == NULL) { + pr_err("device adsprpc-mem is not initialized\n"); + return -ENODEV; + } + *vaddr = dma_alloc_coherent(me->dev, size, region_phys, GFP_KERNEL); + if (!*vaddr) { + pr_err("ADSPRPC: Failed to allocate %x remote heap memory\n", + (unsigned int)size); + return -ENOMEM; + } + return 0; +} + static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, - ssize_t len, struct fastrpc_mmap **ppmap) + size_t len, struct fastrpc_mmap **ppmap) { - struct fastrpc_mmap *match = 0, *map; + struct fastrpc_mmap *match = NULL, *map; struct hlist_node *n; struct fastrpc_apps *me = &gfa; @@ -435,7 +606,6 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, *ppmap = match; return 0; } - spin_lock(&fl->hlock); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { if (map->raddr == va && map->raddr + map->len == va + len && @@ -445,7 +615,6 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, break; } } - spin_unlock(&fl->hlock); if (match) { *ppmap = match; return 0; @@ -453,53 +622,77 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, return -ENOTTY; } -static void fastrpc_mmap_free(struct fastrpc_mmap *map) +static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) { + struct fastrpc_apps *me = &gfa; struct fastrpc_file *fl; int vmid; struct fastrpc_session_ctx *sess; - int destVM[1] = {VMID_HLOS}; - int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; if (!map) return; fl = map->fl; - spin_lock(&fl->hlock); - map->refs--; - if (!map->refs) - hlist_del_init(&map->hn); - spin_unlock(&fl->hlock); - if (map->refs > 0) - return; - if (map->secure) - sess = fl->secsctx; - else - sess = fl->sctx; - - if (!IS_ERR_OR_NULL(map->handle)) - ion_free(fl->apps->client, map->handle); - if (sess->smmu.enabled) { - if (map->size || map->phys) - msm_dma_unmap_sg(sess->dev, - map->table->sgl, - map->table->nents, DMA_BIDIRECTIONAL, - map->buf); + if (map->flags == ADSP_MMAP_HEAP_ADDR || + map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + spin_lock(&me->hlock); + map->refs--; + if (!map->refs) + hlist_del_init(&map->hn); + spin_unlock(&me->hlock); + if (map->refs > 0) + return; + } else { + map->refs--; + if (!map->refs) + hlist_del_init(&map->hn); + if (map->refs > 0 && !flags) + return; } - vmid = fl->apps->channel[fl->cid].vmid; - if (vmid && map->phys) { - int srcVM[2] = {VMID_HLOS, vmid}; + if (map->flags == ADSP_MMAP_HEAP_ADDR || + map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - hyp_assign_phys(map->phys, buf_page_size(map->size), - srcVM, 2, destVM, destVMperm, 1); - } + if (me->dev == NULL) { + pr_err("failed to free remote heap allocation\n"); + return; + } + if (map->phys) { + dma_free_coherent(me->dev, map->size, + (void *)map->va, (dma_addr_t)map->phys); + } + } else { + int destVM[1] = {VMID_HLOS}; + int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; + + if (map->secure) + sess = fl->secsctx; + else + sess = fl->sctx; + + if (!IS_ERR_OR_NULL(map->handle)) + ion_free(fl->apps->client, map->handle); + if (sess && sess->smmu.enabled) { + if (map->size || map->phys) + msm_dma_unmap_sg(sess->smmu.dev, + map->table->sgl, + map->table->nents, DMA_BIDIRECTIONAL, + map->buf); + } + vmid = fl->apps->channel[fl->cid].vmid; + if (vmid && map->phys) { + int srcVM[2] = {VMID_HLOS, vmid}; - if (!IS_ERR_OR_NULL(map->table)) - dma_buf_unmap_attachment(map->attach, map->table, - DMA_BIDIRECTIONAL); - if (!IS_ERR_OR_NULL(map->attach)) - dma_buf_detach(map->buf, map->attach); - if (!IS_ERR_OR_NULL(map->buf)) - dma_buf_put(map->buf); + hyp_assign_phys(map->phys, buf_page_size(map->size), + srcVM, 2, destVM, destVMperm, 1); + } + + if (!IS_ERR_OR_NULL(map->table)) + dma_buf_unmap_attachment(map->attach, map->table, + DMA_BIDIRECTIONAL); + if (!IS_ERR_OR_NULL(map->attach)) + dma_buf_detach(map->buf, map->attach); + if (!IS_ERR_OR_NULL(map->buf)) + dma_buf_put(map->buf); + } kfree(map); } @@ -507,15 +700,18 @@ static int fastrpc_session_alloc(struct fastrpc_channel_ctx *chan, int secure, struct fastrpc_session_ctx **session); static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, - unsigned int attr, uintptr_t va, ssize_t len, int mflags, + unsigned int attr, uintptr_t va, size_t len, int mflags, struct fastrpc_mmap **ppmap) { + struct fastrpc_apps *me = &gfa; struct fastrpc_session_ctx *sess; struct fastrpc_apps *apps = fl->apps; int cid = fl->cid; struct fastrpc_channel_ctx *chan = &apps->channel[cid]; - struct fastrpc_mmap *map = 0; + struct fastrpc_mmap *map = NULL; unsigned long attrs; + dma_addr_t region_phys = 0; + void *region_vaddr = NULL; unsigned long flags; int err = 0, vmid; @@ -531,78 +727,107 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, map->fl = fl; map->fd = fd; map->attr = attr; - VERIFY(err, !IS_ERR_OR_NULL(map->handle = - ion_import_dma_buf_fd(fl->apps->client, fd))); - if (err) - goto bail; - VERIFY(err, !ion_handle_get_flags(fl->apps->client, map->handle, - &flags)); - if (err) - goto bail; + if (mflags == ADSP_MMAP_HEAP_ADDR || + mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + map->apps = me; + map->fl = NULL; + VERIFY(err, !dma_alloc_memory(®ion_phys, ®ion_vaddr, + len)); + if (err) + goto bail; + map->phys = (uintptr_t)region_phys; + map->size = len; + map->va = (uintptr_t)region_vaddr; + } else { + if (map->attr && (map->attr & FASTRPC_ATTR_KEEP_MAP)) { + pr_info("adsprpc: buffer mapped with persist attr %x\n", + (unsigned int)map->attr); + map->refs = 2; + } + VERIFY(err, !IS_ERR_OR_NULL(map->handle = + ion_import_dma_buf_fd(fl->apps->client, fd))); + if (err) + goto bail; + VERIFY(err, !ion_handle_get_flags(fl->apps->client, map->handle, + &flags)); + if (err) + goto bail; - map->uncached = !ION_IS_CACHED(flags); - if (map->attr & FASTRPC_ATTR_NOVA) - map->uncached = 1; + map->secure = flags & ION_FLAG_SECURE; + if (map->secure) { + if (!fl->secsctx) + err = fastrpc_session_alloc(chan, 1, + &fl->secsctx); + if (err) + goto bail; + } + if (map->secure) + sess = fl->secsctx; + else + sess = fl->sctx; - map->secure = flags & ION_FLAG_SECURE; - if (map->secure) { - if (!fl->secsctx) - err = fastrpc_session_alloc(chan, 1, - &fl->secsctx); + VERIFY(err, !IS_ERR_OR_NULL(sess)); if (err) goto bail; - } - if (map->secure) - sess = fl->secsctx; - else - sess = fl->sctx; - VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); - if (err) - goto bail; - VERIFY(err, !IS_ERR_OR_NULL(map->attach = - dma_buf_attach(map->buf, sess->dev))); - if (err) - goto bail; - VERIFY(err, !IS_ERR_OR_NULL(map->table = - dma_buf_map_attachment(map->attach, - DMA_BIDIRECTIONAL))); - if (err) - goto bail; - if (sess->smmu.enabled) { + map->uncached = !ION_IS_CACHED(flags); + if (map->attr & FASTRPC_ATTR_NOVA && !sess->smmu.coherent) + map->uncached = 1; + + VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); + if (err) + goto bail; + VERIFY(err, !IS_ERR_OR_NULL(map->attach = + dma_buf_attach(map->buf, sess->smmu.dev))); + if (err) + goto bail; + VERIFY(err, !IS_ERR_OR_NULL(map->table = + dma_buf_map_attachment(map->attach, + DMA_BIDIRECTIONAL))); + if (err) + goto bail; + if (sess->smmu.enabled) { attrs = DMA_ATTR_EXEC_MAPPING; + + if (map->attr & FASTRPC_ATTR_NON_COHERENT || + (sess->smmu.coherent && map->uncached)) + attrs |= DMA_ATTR_FORCE_NON_COHERENT; + else if (map->attr & FASTRPC_ATTR_COHERENT) + attrs |= DMA_ATTR_FORCE_COHERENT; + VERIFY(err, map->table->nents == - msm_dma_map_sg_attrs(sess->dev, + msm_dma_map_sg_attrs(sess->smmu.dev, map->table->sgl, map->table->nents, DMA_BIDIRECTIONAL, map->buf, attrs)); - if (err) + if (err) + goto bail; + } else { + VERIFY(err, map->table->nents == 1); + if (err) goto bail; - } else { - VERIFY(err, map->table->nents == 1); - if (err) - goto bail; - } - map->phys = sg_dma_address(map->table->sgl); - if (sess->smmu.cb) { - map->phys += ((uint64_t)sess->smmu.cb << 32); - map->size = sg_dma_len(map->table->sgl); - } else { - map->size = buf_page_size(len); - } - vmid = fl->apps->channel[fl->cid].vmid; - if (vmid) { - int srcVM[1] = {VMID_HLOS}; - int destVM[2] = {VMID_HLOS, vmid}; - int destVMperm[2] = {PERM_READ | PERM_WRITE, - PERM_READ | PERM_WRITE | PERM_EXEC}; + } + map->phys = sg_dma_address(map->table->sgl); + if (sess->smmu.cb) { + map->phys += ((uint64_t)sess->smmu.cb << 32); + map->size = sg_dma_len(map->table->sgl); + } else { + map->size = buf_page_size(len); + } + vmid = fl->apps->channel[fl->cid].vmid; + if (vmid) { + int srcVM[1] = {VMID_HLOS}; + int destVM[2] = {VMID_HLOS, vmid}; + int destVMperm[2] = {PERM_READ | PERM_WRITE, + PERM_READ | PERM_WRITE | PERM_EXEC}; - VERIFY(err, !hyp_assign_phys(map->phys, - buf_page_size(map->size), - srcVM, 1, destVM, destVMperm, 2)); - if (err) - goto bail; + VERIFY(err, !hyp_assign_phys(map->phys, + buf_page_size(map->size), + srcVM, 1, destVM, destVMperm, 2)); + if (err) + goto bail; + } + map->va = va; } - map->va = va; map->len = len; fastrpc_mmap_add(map); @@ -610,15 +835,15 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, bail: if (err && map) - fastrpc_mmap_free(map); + fastrpc_mmap_free(map, 0); return err; } -static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size, +static int fastrpc_buf_alloc(struct fastrpc_file *fl, size_t size, struct fastrpc_buf **obuf) { int err = 0, vmid; - struct fastrpc_buf *buf = 0, *fr = 0; + struct fastrpc_buf *buf = NULL, *fr = NULL; struct hlist_node *n; VERIFY(err, size > 0); @@ -638,21 +863,21 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size, *obuf = fr; return 0; } - buf = 0; - VERIFY(err, buf = kzalloc(sizeof(*buf), GFP_KERNEL)); + buf = NULL; + VERIFY(err, NULL != (buf = kzalloc(sizeof(*buf), GFP_KERNEL))); if (err) goto bail; INIT_HLIST_NODE(&buf->hn); buf->fl = fl; - buf->virt = 0; + buf->virt = NULL; buf->phys = 0; buf->size = size; - buf->virt = dma_alloc_coherent(fl->sctx->dev, buf->size, + buf->virt = dma_alloc_coherent(fl->sctx->smmu.dev, buf->size, (void *)&buf->phys, GFP_KERNEL); if (IS_ERR_OR_NULL(buf->virt)) { /* free cache and retry */ fastrpc_buf_list_free(fl); - buf->virt = dma_alloc_coherent(fl->sctx->dev, buf->size, + buf->virt = dma_alloc_coherent(fl->sctx->smmu.dev, buf->size, (void *)&buf->phys, GFP_KERNEL); VERIFY(err, !IS_ERR_OR_NULL(buf->virt)); } @@ -682,11 +907,11 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size, static int context_restore_interrupted(struct fastrpc_file *fl, - struct fastrpc_ioctl_invoke_attrs *inv, + struct fastrpc_ioctl_invoke_crc *inv, struct smq_invoke_ctx **po) { int err = 0; - struct smq_invoke_ctx *ctx = 0, *ictx = 0; + struct smq_invoke_ctx *ctx = NULL, *ictx = NULL; struct hlist_node *n; struct fastrpc_ioctl_invoke *invoke = &inv->inv; @@ -741,7 +966,7 @@ static int context_build_overlap(struct smq_invoke_ctx *ctx) ctx->overs[i].raix = i; ctx->overps[i] = &ctx->overs[i]; } - sort(ctx->overps, nbufs, sizeof(*ctx->overps), overlap_ptr_cmp, 0); + sort(ctx->overps, nbufs, sizeof(*ctx->overps), overlap_ptr_cmp, NULL); max.start = 0; max.end = 0; for (i = 0; i < nbufs; ++i) { @@ -770,7 +995,8 @@ static int context_build_overlap(struct smq_invoke_ctx *ctx) #define K_COPY_FROM_USER(err, kernel, dst, src, size) \ do {\ if (!(kernel))\ - VERIFY(err, 0 == copy_from_user((dst), (src),\ + VERIFY(err, 0 == copy_from_user((dst),\ + (void const __user *)(src),\ (size)));\ else\ memmove((dst), (src), (size));\ @@ -779,8 +1005,8 @@ static int context_build_overlap(struct smq_invoke_ctx *ctx) #define K_COPY_TO_USER(err, kernel, dst, src, size) \ do {\ if (!(kernel))\ - VERIFY(err, 0 == copy_to_user((dst), (src),\ - (size)));\ + VERIFY(err, 0 == copy_to_user((void __user *)(dst),\ + (src), (size)));\ else\ memmove((dst), (src), (size));\ } while (0) @@ -789,11 +1015,11 @@ static int context_build_overlap(struct smq_invoke_ctx *ctx) static void context_free(struct smq_invoke_ctx *ctx); static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, - struct fastrpc_ioctl_invoke_attrs *invokefd, + struct fastrpc_ioctl_invoke_crc *invokefd, struct smq_invoke_ctx **po) { int err = 0, bufs, size = 0; - struct smq_invoke_ctx *ctx = 0; + struct smq_invoke_ctx *ctx = NULL; struct fastrpc_ctx_lst *clst = &fl->clst; struct fastrpc_ioctl_invoke *invoke = &invokefd->inv; @@ -804,7 +1030,7 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, sizeof(*ctx->overs) * (bufs) + sizeof(*ctx->overps) * (bufs); - VERIFY(err, ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL)); + VERIFY(err, NULL != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL))); if (err) goto bail; @@ -818,7 +1044,7 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, ctx->overs = (struct overlap *)(&ctx->attrs[bufs]); ctx->overps = (struct overlap **)(&ctx->overs[bufs]); - K_COPY_FROM_USER(err, kernel, ctx->lpra, invoke->pra, + K_COPY_FROM_USER(err, kernel, (void *)ctx->lpra, invoke->pra, bufs * sizeof(*ctx->lpra)); if (err) goto bail; @@ -835,7 +1061,7 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, if (err) goto bail; } - + ctx->crc = (uint32_t *)invokefd->crc; ctx->sc = invoke->sc; if (bufs) { VERIFY(err, 0 == context_build_overlap(ctx)); @@ -844,8 +1070,9 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, } ctx->retval = -1; ctx->pid = current->pid; - ctx->tgid = current->tgid; + ctx->tgid = fl->tgid; init_completion(&ctx->work); + ctx->magic = FASTRPC_CTX_MAGIC; spin_lock(&fl->hlock); hlist_add_head(&ctx->hn, &clst->pending); @@ -878,9 +1105,13 @@ static void context_free(struct smq_invoke_ctx *ctx) spin_lock(&ctx->fl->hlock); hlist_del_init(&ctx->hn); spin_unlock(&ctx->fl->hlock); + mutex_lock(&ctx->fl->fl_map_mutex); for (i = 0; i < nbufs; ++i) - fastrpc_mmap_free(ctx->maps[i]); + fastrpc_mmap_free(ctx->maps[i], 0); + + mutex_unlock(&ctx->fl->fl_map_mutex); fastrpc_buf_free(ctx->buf, 1); + ctx->magic = 0; kfree(ctx); } @@ -920,6 +1151,21 @@ static void fastrpc_notify_drivers(struct fastrpc_apps *me, int cid) spin_unlock(&me->hlock); } + +static void fastrpc_notify_pdr_drivers(struct fastrpc_apps *me, char *spdname) +{ + struct fastrpc_file *fl; + struct hlist_node *n; + + spin_lock(&me->hlock); + hlist_for_each_entry_safe(fl, n, &me->drivers, hn) { + if (fl->spdname && !strcmp(spdname, fl->spdname)) + fastrpc_notify_users(fl); + } + spin_unlock(&me->hlock); + +} + static void context_list_ctor(struct fastrpc_ctx_lst *me) { INIT_HLIST_HEAD(&me->interrupted); @@ -929,11 +1175,11 @@ static void context_list_ctor(struct fastrpc_ctx_lst *me) static void fastrpc_context_list_dtor(struct fastrpc_file *fl) { struct fastrpc_ctx_lst *clst = &fl->clst; - struct smq_invoke_ctx *ictx = 0, *ctxfree; + struct smq_invoke_ctx *ictx = NULL, *ctxfree; struct hlist_node *n; do { - ctxfree = 0; + ctxfree = NULL; spin_lock(&fl->hlock); hlist_for_each_entry_safe(ictx, n, &clst->interrupted, hn) { hlist_del_init(&ictx->hn); @@ -945,7 +1191,7 @@ static void fastrpc_context_list_dtor(struct fastrpc_file *fl) context_free(ctxfree); } while (ctxfree); do { - ctxfree = 0; + ctxfree = NULL; spin_lock(&fl->hlock); hlist_for_each_entry_safe(ictx, n, &clst->pending, hn) { hlist_del_init(&ictx->hn); @@ -965,7 +1211,7 @@ static void fastrpc_file_list_dtor(struct fastrpc_apps *me) struct hlist_node *n; do { - free = 0; + free = NULL; spin_lock(&me->hlock); hlist_for_each_entry_safe(fl, n, &me->drivers, hn) { hlist_del_init(&fl->hn); @@ -989,42 +1235,54 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) int outbufs = REMOTE_SCALARS_OUTBUFS(sc); int handles, bufs = inbufs + outbufs; uintptr_t args; - ssize_t rlen = 0, copylen = 0, metalen = 0; + size_t rlen = 0, copylen = 0, metalen = 0; int i, oix; int err = 0; int mflags = 0; uint64_t *fdlist; + uint32_t *crclist; + int64_t *perf_counter = getperfcounter(ctx->fl, PERF_COUNT); /* calculate size of the metadata */ - rpra = 0; + rpra = NULL; list = smq_invoke_buf_start(rpra, sc); pages = smq_phy_page_start(sc, list); ipage = pages; + PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP), for (i = 0; i < bufs; ++i) { uintptr_t buf = (uintptr_t)lpra[i].buf.pv; - ssize_t len = lpra[i].buf.len; + size_t len = lpra[i].buf.len; + mutex_lock(&ctx->fl->fl_map_mutex); if (ctx->fds[i] && (ctx->fds[i] != -1)) fastrpc_mmap_create(ctx->fl, ctx->fds[i], ctx->attrs[i], buf, len, mflags, &ctx->maps[i]); + mutex_unlock(&ctx->fl->fl_map_mutex); ipage += 1; } + PERF_END); handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc); + mutex_lock(&ctx->fl->fl_map_mutex); for (i = bufs; i < bufs + handles; i++) { VERIFY(err, !fastrpc_mmap_create(ctx->fl, ctx->fds[i], FASTRPC_ATTR_NOVA, 0, 0, 0, &ctx->maps[i])); - if (err) + if (err) { + mutex_unlock(&ctx->fl->fl_map_mutex); goto bail; + } ipage += 1; } - metalen = copylen = (ssize_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST); + mutex_unlock(&ctx->fl->fl_map_mutex); + metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) + + (sizeof(uint32_t) * M_CRCLIST); + /* calculate len requreed for copying */ for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; uintptr_t mstart, mend; - ssize_t len = lpra[i].buf.len; + size_t len = lpra[i].buf.len; if (!len) continue; @@ -1050,6 +1308,9 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (err) goto bail; } + if (ctx->buf->virt && metalen <= copylen) + memset(ctx->buf->virt, 0, metalen); + /* copy metadata */ rpra = ctx->buf->virt; ctx->rpra = rpra; @@ -1065,12 +1326,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) list[i].pgidx = ipage - pages; ipage++; } + /* map ion buffers */ - PERF(ctx->fl->profile, ctx->fl->perf.map, - for (i = 0; i < inbufs + outbufs; ++i) { + PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP), + for (i = 0; rpra && i < inbufs + outbufs; ++i) { struct fastrpc_mmap *map = ctx->maps[i]; uint64_t buf = ptr_to_uint64(lpra[i].buf.pv); - ssize_t len = lpra[i].buf.len; + size_t len = lpra[i].buf.len; rpra[i].buf.pv = 0; rpra[i].buf.len = len; @@ -1079,7 +1341,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map) { struct vm_area_struct *vma; uintptr_t offset; - int num = buf_num_pages(buf, len); + uint64_t num = buf_num_pages(buf, len); int idx = list[i].pgidx; if (map->attr & FASTRPC_ATTR_NOVA) { @@ -1113,16 +1375,18 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) fdlist = (uint64_t *)&pages[bufs + handles]; for (i = 0; i < M_FDLIST; i++) fdlist[i] = 0; + crclist = (uint32_t *)&fdlist[M_FDLIST]; + memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST); /* copy non ion buffers */ - PERF(ctx->fl->profile, ctx->fl->perf.copy, + PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY), rlen = copylen - metalen; for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; - ssize_t mlen; + size_t mlen; uint64_t buf; - ssize_t len = lpra[i].buf.len; + size_t len = lpra[i].buf.len; if (!len) continue; @@ -1155,28 +1419,32 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) } PERF_END); - PERF(ctx->fl->profile, ctx->fl->perf.flush, + PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_FLUSH), for (oix = 0; oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; - if (ctx->fl->sctx->smmu.coherent) - continue; if (map && map->uncached) continue; + if (ctx->fl->sctx->smmu.coherent && + !(map && (map->attr & FASTRPC_ATTR_NON_COHERENT))) + continue; + if (map && (map->attr & FASTRPC_ATTR_COHERENT)) + continue; + if (rpra[i].buf.len && ctx->overps[oix]->mstart) dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv), uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len)); } PERF_END); - for (i = bufs; i < bufs + handles; i++) { + for (i = bufs; rpra && i < bufs + handles; i++) { rpra[i].dma.fd = ctx->fds[i]; rpra[i].dma.len = (uint32_t)lpra[i].buf.len; rpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; } if (!ctx->fl->sctx->smmu.coherent) { - PERF(ctx->fl->profile, ctx->fl->perf.flush, + PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_FLUSH), dmac_flush_range((char *)rpra, (char *)rpra + ctx->used); PERF_END); } @@ -1192,6 +1460,8 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, struct smq_phy_page *pages; struct fastrpc_mmap *mmap; uint64_t *fdlist; + uint32_t *crclist = NULL; + remote_arg64_t *rpra = ctx->rpra; int i, inbufs, outbufs, handles; int err = 0; @@ -1202,6 +1472,8 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, list = smq_invoke_buf_start(ctx->rpra, sc); pages = smq_phy_page_start(sc, list); fdlist = (uint64_t *)(pages + inbufs + outbufs + handles); + crclist = (uint32_t *)(fdlist + M_FDLIST); + for (i = inbufs; i < inbufs + outbufs; ++i) { if (!ctx->maps[i]) { K_COPY_TO_USER(err, kernel, @@ -1211,19 +1483,27 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, if (err) goto bail; } else { - fastrpc_mmap_free(ctx->maps[i]); - ctx->maps[i] = 0; + mutex_lock(&ctx->fl->fl_map_mutex); + fastrpc_mmap_free(ctx->maps[i], 0); + mutex_unlock(&ctx->fl->fl_map_mutex); + ctx->maps[i] = NULL; } } + mutex_lock(&ctx->fl->fl_map_mutex); if (inbufs + outbufs + handles) { for (i = 0; i < M_FDLIST; i++) { if (!fdlist[i]) break; if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], 0, 0, 0, 0, &mmap)) - fastrpc_mmap_free(mmap); + fastrpc_mmap_free(mmap, 0); } } + mutex_unlock(&ctx->fl->fl_map_mutex); + if (ctx->crc && crclist && rpra) + K_COPY_TO_USER(err, kernel, ctx->crc, + crclist, M_CRCLIST*sizeof(uint32_t)); + bail: return err; } @@ -1244,6 +1524,12 @@ static void inv_args_pre(struct smq_invoke_ctx *ctx) continue; if (!rpra[i].buf.len) continue; + if (ctx->fl->sctx->smmu.coherent && + !(map && (map->attr & FASTRPC_ATTR_NON_COHERENT))) + continue; + if (map && (map->attr & FASTRPC_ATTR_COHERENT)) + continue; + if (buf_page_start(ptr_to_uint64((void *)rpra)) == buf_page_start(rpra[i].buf.pv)) continue; @@ -1274,6 +1560,12 @@ static void inv_args(struct smq_invoke_ctx *ctx) continue; if (!rpra[i].buf.len) continue; + if (ctx->fl->sctx->smmu.coherent && + !(map && (map->attr & FASTRPC_ATTR_NON_COHERENT))) + continue; + if (map && (map->attr & FASTRPC_ATTR_COHERENT)) + continue; + if (buf_page_start(ptr_to_uint64((void *)rpra)) == buf_page_start(rpra[i].buf.pv)) { continue; @@ -1300,11 +1592,13 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, struct fastrpc_channel_ctx *channel_ctx = &fl->apps->channel[fl->cid]; int err = 0; - VERIFY(err, 0 != channel_ctx->chan); + VERIFY(err, NULL != channel_ctx->chan); if (err) goto bail; - msg->pid = current->tgid; + msg->pid = fl->tgid; msg->tid = current->pid; + if (fl->sessionid) + msg->tid |= (1 << SESSION_ID_INDEX); if (kernel) msg->pid = 0; msg->invoke.header.ctx = ptr_to_uint64(ctx) | fl->pd; @@ -1333,11 +1627,13 @@ static void fastrpc_init(struct fastrpc_apps *me) int i; INIT_HLIST_HEAD(&me->drivers); + INIT_HLIST_HEAD(&me->maps); spin_lock_init(&me->hlock); mutex_init(&me->smd_mutex); me->channel = &gcinfo[0]; for (i = 0; i < NUM_CHANNELS; i++) { init_completion(&me->channel[i].work); + init_completion(&me->channel[i].workport); me->channel[i].sesscount = 0; } } @@ -1346,17 +1642,27 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl); static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, uint32_t kernel, - struct fastrpc_ioctl_invoke_attrs *inv) + struct fastrpc_ioctl_invoke_crc *inv) { - struct smq_invoke_ctx *ctx = 0; + struct smq_invoke_ctx *ctx = NULL; struct fastrpc_ioctl_invoke *invoke = &inv->inv; int cid = fl->cid; int interrupted = 0; int err = 0; - struct timespec invoket; + struct timespec invoket = {0}; + int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); if (fl->profile) getnstimeofday(&invoket); + + + VERIFY(err, fl->sctx != NULL); + if (err) + goto bail; + VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS); + if (err) + goto bail; + if (!kernel) { VERIFY(err, 0 == context_restore_interrupted(fl, inv, &ctx)); @@ -1375,31 +1681,25 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, goto bail; if (REMOTE_SCALARS_LENGTH(ctx->sc)) { - PERF(fl->profile, fl->perf.getargs, + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_GETARGS), VERIFY(err, 0 == get_args(kernel, ctx)); PERF_END); if (err) goto bail; } - PERF(fl->profile, fl->perf.invargs, if (!fl->sctx->smmu.coherent) { + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_INVARGS), inv_args_pre(ctx); - if (mode == FASTRPC_MODE_SERIAL) - inv_args(ctx); + PERF_END); } - PERF_END); - PERF(fl->profile, fl->perf.link, + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_LINK), VERIFY(err, 0 == fastrpc_invoke_send(ctx, kernel, invoke->handle)); PERF_END); if (err) goto bail; - PERF(fl->profile, fl->perf.invargs, - if (mode == FASTRPC_MODE_PARALLEL && !fl->sctx->smmu.coherent) - inv_args(ctx); - PERF_END); wait: if (kernel) wait_for_completion(&ctx->work); @@ -1409,11 +1709,17 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (err) goto bail; } + + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_INVARGS), + if (!fl->sctx->smmu.coherent) + inv_args(ctx); + PERF_END); + VERIFY(err, 0 == (err = ctx->retval)); if (err) goto bail; - PERF(fl->profile, fl->perf.putargs, + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_PUTARGS), VERIFY(err, 0 == put_args(kernel, ctx, invoke->pra)); PERF_END); if (err) @@ -1427,39 +1733,70 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, err = ECONNRESET; if (fl->profile && !interrupted) { - if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER) - fl->perf.invoke += getnstimediff(&invoket); - if (!(invoke->handle >= 0 && - invoke->handle <= FASTRPC_STATIC_HANDLE_MAX)) - fl->perf.count++; + if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER) { + int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); + + if (count) + *count += getnstimediff(&invoket); + } + if (invoke->handle > FASTRPC_STATIC_HANDLE_MAX) { + int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); + + if (count) + *count = *count+1; + } + } + return err; +} + +static int fastrpc_get_adsp_session(char *name, int *session) +{ + struct fastrpc_apps *me = &gfa; + int err = 0, i; + + for (i = 0; i < NUM_SESSIONS; i++) { + if (!me->channel[0].spd[i].spdname) + continue; + if (!strcmp(name, me->channel[0].spd[i].spdname)) + break; } + VERIFY(err, i < NUM_SESSIONS); + if (err) + goto bail; + *session = i; +bail: return err; } +static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl); static int fastrpc_channel_open(struct fastrpc_file *fl); +static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl); static int fastrpc_init_process(struct fastrpc_file *fl, struct fastrpc_ioctl_init_attrs *uproc) { int err = 0; - struct fastrpc_ioctl_invoke_attrs ioctl; + struct fastrpc_apps *me = &gfa; + struct fastrpc_ioctl_invoke_crc ioctl; struct fastrpc_ioctl_init *init = &uproc->init; struct smq_phy_page pages[1]; - struct fastrpc_mmap *file = 0, *mem = 0; + struct fastrpc_mmap *file = NULL, *mem = NULL; + char *proc_name = NULL; - VERIFY(err, !fastrpc_channel_open(fl)); + VERIFY(err, 0 == (err = fastrpc_channel_open(fl))); if (err) goto bail; if (init->flags == FASTRPC_INIT_ATTACH) { remote_arg_t ra[1]; - int tgid = current->tgid; + int tgid = fl->tgid; ra[0].buf.pv = (void *)&tgid; ra[0].buf.len = sizeof(tgid); ioctl.inv.handle = 1; ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0); ioctl.inv.pra = ra; - ioctl.fds = 0; - ioctl.attrs = 0; + ioctl.fds = NULL; + ioctl.attrs = NULL; + ioctl.crc = NULL; fl->pd = 0; VERIFY(err, !(err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); @@ -1471,26 +1808,39 @@ static int fastrpc_init_process(struct fastrpc_file *fl, int mflags = 0; struct { int pgid; - int namelen; - int filelen; - int pageslen; + unsigned int namelen; + unsigned int filelen; + unsigned int pageslen; int attrs; int siglen; } inbuf; - inbuf.pgid = current->tgid; + inbuf.pgid = fl->tgid; inbuf.namelen = strlen(current->comm) + 1; inbuf.filelen = init->filelen; fl->pd = 1; + + VERIFY(err, access_ok(0, (void __user *)init->file, + init->filelen)); + if (err) + goto bail; if (init->filelen) { + mutex_lock(&fl->fl_map_mutex); VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, 0, init->file, init->filelen, mflags, &file)); + mutex_unlock(&fl->fl_map_mutex); if (err) goto bail; } inbuf.pageslen = 1; + VERIFY(err, access_ok(1, (void __user *)init->mem, + init->memlen)); + if (err) + goto bail; + mutex_lock(&fl->fl_map_mutex); VERIFY(err, !fastrpc_mmap_create(fl, init->memfd, 0, init->mem, init->memlen, mflags, &mem)); + mutex_unlock(&fl->fl_map_mutex); if (err) goto bail; inbuf.pageslen = 1; @@ -1528,7 +1878,90 @@ static int fastrpc_init_process(struct fastrpc_file *fl, ioctl.inv.sc = REMOTE_SCALARS_MAKE(7, 6, 0); ioctl.inv.pra = ra; ioctl.fds = fds; - ioctl.attrs = 0; + ioctl.attrs = NULL; + ioctl.crc = NULL; + VERIFY(err, !(err = fastrpc_internal_invoke(fl, + FASTRPC_MODE_PARALLEL, 1, &ioctl))); + if (err) + goto bail; + } else if (init->flags == FASTRPC_INIT_CREATE_STATIC) { + remote_arg_t ra[3]; + uint64_t phys = 0; + size_t size = 0; + int fds[3]; + struct { + int pgid; + unsigned int namelen; + unsigned int pageslen; + } inbuf; + + if (!init->filelen) + goto bail; + + proc_name = kzalloc(init->filelen, GFP_KERNEL); + VERIFY(err, !IS_ERR_OR_NULL(proc_name)); + if (err) + goto bail; + VERIFY(err, 0 == copy_from_user((void *)proc_name, + (void __user *)init->file, init->filelen)); + if (err) + goto bail; + + inbuf.pgid = current->tgid; + inbuf.namelen = init->filelen; + inbuf.pageslen = 0; + + if (!strcmp(proc_name, "audiopd")) { + fl->spdname = AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME; + VERIFY(err, !fastrpc_mmap_remove_pdr(fl)); + } + + if (!me->staticpd_flags) { + inbuf.pageslen = 1; + mutex_lock(&fl->fl_map_mutex); + VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem, + init->memlen, ADSP_MMAP_REMOTE_HEAP_ADDR, + &mem)); + mutex_unlock(&fl->fl_map_mutex); + if (err) + goto bail; + phys = mem->phys; + size = mem->size; + VERIFY(err, !hyp_assign_phys(phys, (uint64_t)size, + hlosvm, 1, me->channel[fl->cid].rhvm.vmid, + me->channel[fl->cid].rhvm.vmperm, + me->channel[fl->cid].rhvm.vmcount)); + if (err) { + pr_err("ADSPRPC: hyp_assign_phys fail err %d", + err); + pr_err("map->phys %llx, map->size %d\n", + phys, (int)size); + goto bail; + } + me->staticpd_flags = 1; + } + + ra[0].buf.pv = (void *)&inbuf; + ra[0].buf.len = sizeof(inbuf); + fds[0] = 0; + + ra[1].buf.pv = (void *)proc_name; + ra[1].buf.len = inbuf.namelen; + fds[1] = 0; + + pages[0].addr = phys; + pages[0].size = size; + + ra[2].buf.pv = (void *)pages; + ra[2].buf.len = sizeof(*pages); + fds[2] = 0; + ioctl.inv.handle = 1; + + ioctl.inv.sc = REMOTE_SCALARS_MAKE(8, 3, 0); + ioctl.inv.pra = ra; + ioctl.fds = NULL; + ioctl.attrs = NULL; + ioctl.crc = NULL; VERIFY(err, !(err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); if (err) @@ -1537,24 +1970,38 @@ static int fastrpc_init_process(struct fastrpc_file *fl, err = -ENOTTY; } bail: - if (mem && err) - fastrpc_mmap_free(mem); - if (file) - fastrpc_mmap_free(file); + kfree(proc_name); + if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC)) + me->staticpd_flags = 0; + if (mem && err) { + if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + hyp_assign_phys(mem->phys, (uint64_t)mem->size, + me->channel[fl->cid].rhvm.vmid, + me->channel[fl->cid].rhvm.vmcount, + hlosvm, hlosvmperm, 1); + mutex_lock(&fl->fl_map_mutex); + fastrpc_mmap_free(mem, 0); + mutex_unlock(&fl->fl_map_mutex); + } + if (file) { + mutex_lock(&fl->fl_map_mutex); + fastrpc_mmap_free(file, 0); + mutex_unlock(&fl->fl_map_mutex); + } return err; } static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) { int err = 0; - struct fastrpc_ioctl_invoke_attrs ioctl; + struct fastrpc_ioctl_invoke_crc ioctl; remote_arg_t ra[1]; int tgid = 0; VERIFY(err, fl->cid >= 0 && fl->cid < NUM_CHANNELS); if (err) goto bail; - VERIFY(err, fl->apps->channel[fl->cid].chan != 0); + VERIFY(err, fl->apps->channel[fl->cid].chan != NULL); if (err) goto bail; tgid = fl->tgid; @@ -1563,8 +2010,9 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) ioctl.inv.handle = 1; ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0); ioctl.inv.pra = ra; - ioctl.fds = 0; - ioctl.attrs = 0; + ioctl.fds = NULL; + ioctl.attrs = NULL; + ioctl.crc = NULL; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); bail: @@ -1574,7 +2022,8 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, struct fastrpc_mmap *map) { - struct fastrpc_ioctl_invoke_attrs ioctl; + struct fastrpc_ioctl_invoke_crc ioctl; + struct fastrpc_apps *me = &gfa; struct smq_phy_page page; int num = 1; remote_arg_t ra[3]; @@ -1589,7 +2038,7 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, uintptr_t vaddrout; } routargs; - inargs.pid = current->tgid; + inargs.pid = fl->tgid; inargs.vaddrin = (uintptr_t)map->va; inargs.flags = flags; inargs.num = fl->apps->compat ? num * sizeof(page) : num; @@ -1609,28 +2058,101 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, else ioctl.inv.sc = REMOTE_SCALARS_MAKE(2, 2, 1); ioctl.inv.pra = ra; - ioctl.fds = 0; - ioctl.attrs = 0; + ioctl.fds = NULL; + ioctl.attrs = NULL; + ioctl.crc = NULL; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); map->raddr = (uintptr_t)routargs.vaddrout; + if (err) + goto bail; + if (flags == ADSP_MMAP_HEAP_ADDR) { + struct scm_desc desc = {0}; + + desc.args[0] = TZ_PIL_AUTH_QDSP6_PROC; + desc.args[1] = map->phys; + desc.args[2] = map->size; + desc.arginfo = SCM_ARGS(3); + err = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, + TZ_PIL_PROTECT_MEM_SUBSYS_ID), &desc); + } else if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(err, !hyp_assign_phys(map->phys, (uint64_t)map->size, + hlosvm, 1, me->channel[fl->cid].rhvm.vmid, + me->channel[fl->cid].rhvm.vmperm, + me->channel[fl->cid].rhvm.vmcount)); + if (err) + goto bail; + } +bail: + return err; +} + +static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, + struct fastrpc_mmap *map) +{ + int err = 0; + struct fastrpc_apps *me = &gfa; + int destVM[1] = {VMID_HLOS}; + int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; + + if (map->flags == ADSP_MMAP_HEAP_ADDR) { + struct fastrpc_ioctl_invoke_crc ioctl; + struct scm_desc desc = {0}; + remote_arg_t ra[1]; + int err = 0; + struct { + uint8_t skey; + } routargs; + ra[0].buf.pv = (void *)&routargs; + ra[0].buf.len = sizeof(routargs); + + ioctl.inv.handle = 1; + ioctl.inv.sc = REMOTE_SCALARS_MAKE(7, 0, 1); + ioctl.inv.pra = ra; + ioctl.fds = NULL; + ioctl.attrs = NULL; + ioctl.crc = NULL; + if (fl == NULL) + goto bail; + + VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, + FASTRPC_MODE_PARALLEL, 1, &ioctl))); + if (err) + goto bail; + desc.args[0] = TZ_PIL_AUTH_QDSP6_PROC; + desc.args[1] = map->phys; + desc.args[2] = map->size; + desc.args[3] = routargs.skey; + desc.arginfo = SCM_ARGS(4); + err = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, + TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID), &desc); + } else if (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(err, !hyp_assign_phys(map->phys, (uint64_t)map->size, + me->channel[fl->cid].rhvm.vmid, + me->channel[fl->cid].rhvm.vmcount, + destVM, destVMperm, 1)); + if (err) + goto bail; + } + +bail: return err; } static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, struct fastrpc_mmap *map) { - struct fastrpc_ioctl_invoke_attrs ioctl; + struct fastrpc_ioctl_invoke_crc ioctl; remote_arg_t ra[1]; int err = 0; struct { int pid; uintptr_t vaddrout; - ssize_t size; + size_t size; } inargs; - inargs.pid = current->tgid; + inargs.pid = fl->tgid; inargs.size = map->size; inargs.vaddrout = map->raddr; ra[0].buf.pv = (void *)&inargs; @@ -1642,15 +2164,98 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, else ioctl.inv.sc = REMOTE_SCALARS_MAKE(3, 1, 0); ioctl.inv.pra = ra; - ioctl.fds = 0; - ioctl.attrs = 0; + ioctl.fds = NULL; + ioctl.attrs = NULL; + ioctl.crc = NULL; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); + if (err) + goto bail; + if (map->flags == ADSP_MMAP_HEAP_ADDR || + map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, map)); + if (err) + goto bail; + } +bail: + return err; +} + +static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl) +{ + struct fastrpc_mmap *match = NULL, *map = NULL; + struct hlist_node *n = NULL; + int err = 0, ret = 0; + struct fastrpc_apps *me = &gfa; + struct ramdump_segment *ramdump_segments_rh = NULL; + + do { + match = NULL; + spin_lock(&me->hlock); + hlist_for_each_entry_safe(map, n, &me->maps, hn) { + match = map; + hlist_del_init(&map->hn); + break; + } + spin_unlock(&me->hlock); + + if (match) { + VERIFY(err, !fastrpc_munmap_on_dsp_rh(fl, match)); + if (err) + goto bail; + if (me->channel[0].ramdumpenabled) { + ramdump_segments_rh = kcalloc(1, + sizeof(struct ramdump_segment), GFP_KERNEL); + if (ramdump_segments_rh) { + ramdump_segments_rh->address = + match->phys; + ramdump_segments_rh->size = match->size; + ret = do_elf_ramdump( + me->channel[0].remoteheap_ramdump_dev, + ramdump_segments_rh, 1); + if (ret < 0) + pr_err("ADSPRPC: unable to dump heap"); + kfree(ramdump_segments_rh); + } + } + fastrpc_mmap_free(match, 0); + } + } while (match); +bail: + if (err && match) + fastrpc_mmap_add(match); + return err; +} + +static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl) +{ + struct fastrpc_apps *me = &gfa; + int session = 0, err = 0; + + VERIFY(err, !fastrpc_get_adsp_session( + AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME, &session)); + if (err) + goto bail; + if (me->channel[fl->cid].spd[session].pdrcount != + me->channel[fl->cid].spd[session].prevpdrcount) { + if (fastrpc_mmap_remove_ssr(fl)) + pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n"); + me->channel[fl->cid].spd[session].prevpdrcount = + me->channel[fl->cid].spd[session].pdrcount; + } + if (!me->channel[fl->cid].spd[session].ispdup) { + VERIFY(err, 0); + if (err) { + err = -ENOTCONN; + goto bail; + } + } +bail: return err; } static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, - ssize_t len, struct fastrpc_mmap **ppmap); + size_t len, struct fastrpc_mmap **ppmap); static void fastrpc_mmap_add(struct fastrpc_mmap *map); @@ -1658,34 +2263,74 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl, struct fastrpc_ioctl_munmap *ud) { int err = 0; - struct fastrpc_mmap *map = 0; + struct fastrpc_mmap *map = NULL; + mutex_lock(&fl->map_mutex); + mutex_lock(&fl->fl_map_mutex); VERIFY(err, !fastrpc_mmap_remove(fl, ud->vaddrout, ud->size, &map)); + mutex_unlock(&fl->fl_map_mutex); if (err) goto bail; VERIFY(err, !fastrpc_munmap_on_dsp(fl, map)); if (err) goto bail; - fastrpc_mmap_free(map); + mutex_lock(&fl->fl_map_mutex); + fastrpc_mmap_free(map, 0); + mutex_unlock(&fl->fl_map_mutex); bail: - if (err && map) + if (err && map) { + mutex_lock(&fl->fl_map_mutex); fastrpc_mmap_add(map); + mutex_unlock(&fl->fl_map_mutex); + } + mutex_unlock(&fl->map_mutex); + return err; +} + +static int fastrpc_internal_munmap_fd(struct fastrpc_file *fl, + struct fastrpc_ioctl_munmap_fd *ud) { + int err = 0; + struct fastrpc_mmap *map = NULL; + + VERIFY(err, (fl && ud)); + if (err) + goto bail; + mutex_lock(&fl->fl_map_mutex); + if (!fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) { + pr_err("mapping not found to unamp %x va %llx %x\n", + ud->fd, (unsigned long long)ud->va, + (unsigned int)ud->len); + err = -1; + mutex_unlock(&fl->fl_map_mutex); + goto bail; + } + if (map) + fastrpc_mmap_free(map, 0); + mutex_unlock(&fl->fl_map_mutex); +bail: return err; } + static int fastrpc_internal_mmap(struct fastrpc_file *fl, struct fastrpc_ioctl_mmap *ud) { - struct fastrpc_mmap *map = 0; + struct fastrpc_mmap *map = NULL; int err = 0; - if (!fastrpc_mmap_find(fl, ud->fd, (uintptr_t)ud->vaddrin, ud->size, - ud->flags, 1, &map)) + mutex_lock(&fl->map_mutex); + mutex_lock(&fl->fl_map_mutex); + if (!fastrpc_mmap_find(fl, ud->fd, (uintptr_t)ud->vaddrin, + ud->size, ud->flags, 1, &map)) { + mutex_unlock(&fl->fl_map_mutex); + mutex_unlock(&fl->map_mutex); return 0; - + } VERIFY(err, !fastrpc_mmap_create(fl, ud->fd, 0, - (uintptr_t)ud->vaddrin, ud->size, ud->flags, &map)); + (uintptr_t)ud->vaddrin, ud->size, + ud->flags, &map)); + mutex_unlock(&fl->fl_map_mutex); if (err) goto bail; VERIFY(err, 0 == fastrpc_mmap_on_dsp(fl, ud->flags, map)); @@ -1693,8 +2338,12 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl, goto bail; ud->vaddrout = map->raddr; bail: - if (err && map) - fastrpc_mmap_free(map); + if (err && map) { + mutex_lock(&fl->fl_map_mutex); + fastrpc_mmap_free(map, 0); + mutex_unlock(&fl->fl_map_mutex); + } + mutex_unlock(&fl->map_mutex); return err; } @@ -1707,7 +2356,9 @@ static void fastrpc_channel_close(struct kref *kref) ctx = container_of(kref, struct fastrpc_channel_ctx, kref); cid = ctx - &gcinfo[0]; fastrpc_glink_close(ctx->chan, cid); - ctx->chan = 0; + ctx->chan = NULL; + glink_unregister_link_state_cb(ctx->link.link_notify_handle); + ctx->link.link_notify_handle = NULL; mutex_unlock(&me->smd_mutex); pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); @@ -1738,6 +2389,7 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan, if (err) goto bail; chan->session[0].dev = me->dev; + chan->session[0].smmu.dev = me->dev; } *session = &chan->session[idx]; @@ -1745,34 +2397,43 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan, return err; } -bool fastrpc_glink_notify_rx_intent_req(void *h, const void *priv, size_t size) +static bool fastrpc_glink_notify_rx_intent_req(void *h, const void *priv, + size_t size) { if (glink_queue_rx_intent(h, NULL, size)) return false; return true; } -void fastrpc_glink_notify_tx_done(void *handle, const void *priv, +static void fastrpc_glink_notify_tx_done(void *handle, const void *priv, const void *pkt_priv, const void *ptr) { } -void fastrpc_glink_notify_rx(void *handle, const void *priv, +static void fastrpc_glink_notify_rx(void *handle, const void *priv, const void *pkt_priv, const void *ptr, size_t size) { struct smq_invoke_rsp *rsp = (struct smq_invoke_rsp *)ptr; - int len = size; + struct smq_invoke_ctx *ctx; + int err = 0; - while (len >= sizeof(*rsp) && rsp) { - rsp->ctx = rsp->ctx & ~1; - context_notify_user(uint64_to_ptr(rsp->ctx), rsp->retval); - rsp++; - len = len - sizeof(*rsp); - } + VERIFY(err, (rsp && size >= sizeof(*rsp))); + if (err) + goto bail; + + ctx = (struct smq_invoke_ctx *)(uint64_to_ptr(rsp->ctx & ~1)); + VERIFY(err, (ctx && ctx->magic == FASTRPC_CTX_MAGIC)); + if (err) + goto bail; + + context_notify_user(ctx, rsp->retval); +bail: + if (err) + pr_err("adsprpc: invalid response or context\n"); glink_rx_done(handle, ptr, true); } -void fastrpc_glink_notify_state(void *handle, const void *priv, +static void fastrpc_glink_notify_state(void *handle, const void *priv, unsigned int event) { struct fastrpc_apps *me = &gfa; @@ -1785,18 +2446,12 @@ void fastrpc_glink_notify_state(void *handle, const void *priv, switch (event) { case GLINK_CONNECTED: link->port_state = FASTRPC_LINK_CONNECTED; - complete(&me->channel[cid].work); + complete(&me->channel[cid].workport); break; case GLINK_LOCAL_DISCONNECTED: link->port_state = FASTRPC_LINK_DISCONNECTED; break; case GLINK_REMOTE_DISCONNECTED: - if (me->channel[cid].chan && - link->link_state == FASTRPC_LINK_STATE_UP) { - fastrpc_glink_close(me->channel[cid].chan, cid); - me->channel[cid].chan = 0; - link->port_state = FASTRPC_LINK_DISCONNECTED; - } break; default: break; @@ -1828,14 +2483,17 @@ static void fastrpc_session_free(struct fastrpc_channel_ctx *chan, static int fastrpc_file_free(struct fastrpc_file *fl) { - struct hlist_node *n; - struct fastrpc_mmap *map = 0; + struct hlist_node *n = NULL; + struct fastrpc_mmap *map = NULL; + struct fastrpc_perf *perf = NULL, *fperf = NULL; int cid; if (!fl) return 0; cid = fl->cid; + (void)fastrpc_release_current_dsp_process(fl); + spin_lock(&fl->apps->hlock); hlist_del_init(&fl->hn); spin_unlock(&fl->apps->hlock); @@ -1844,12 +2502,16 @@ static int fastrpc_file_free(struct fastrpc_file *fl) kfree(fl); return 0; } - (void)fastrpc_release_current_dsp_process(fl); + spin_lock(&fl->hlock); + fl->file_close = 1; + spin_unlock(&fl->hlock); fastrpc_context_list_dtor(fl); fastrpc_buf_list_free(fl); + mutex_lock(&fl->fl_map_mutex); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - fastrpc_mmap_free(map); + fastrpc_mmap_free(map, 1); } + mutex_unlock(&fl->fl_map_mutex); if (fl->ssrcount == fl->apps->channel[cid].ssrcount) kref_put_mutex(&fl->apps->channel[cid].kref, fastrpc_channel_close, &fl->apps->smd_mutex); @@ -1857,6 +2519,22 @@ static int fastrpc_file_free(struct fastrpc_file *fl) fastrpc_session_free(&fl->apps->channel[cid], fl->sctx); if (fl->secsctx) fastrpc_session_free(&fl->apps->channel[cid], fl->secsctx); + + mutex_lock(&fl->perf_mutex); + do { + struct hlist_node *pn = NULL; + + fperf = NULL; + hlist_for_each_entry_safe(perf, pn, &fl->perf, hn) { + hlist_del_init(&perf->hn); + fperf = perf; + break; + } + kfree(fperf); + } while (fperf); + mutex_unlock(&fl->perf_mutex); + mutex_destroy(&fl->perf_mutex); + mutex_destroy(&fl->fl_map_mutex); kfree(fl); return 0; } @@ -1866,10 +2544,13 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; if (fl) { + if (fl->qos_request && pm_qos_request_active(&fl->pm_qos_req)) + pm_qos_remove_request(&fl->pm_qos_req); if (fl->debugfs_file != NULL) debugfs_remove(fl->debugfs_file); + mutex_destroy(&fl->map_mutex); fastrpc_file_free(fl); - file->private_data = 0; + file->private_data = NULL; } return 0; } @@ -1938,7 +2619,7 @@ static void fastrpc_glink_close(void *chan, int cid) link = &gfa.channel[cid].link; if (link->port_state == FASTRPC_LINK_CONNECTED || - link->port_state == FASTRPC_LINK_CONNECTING) { + link->port_state == FASTRPC_LINK_REMOTE_DISCONNECTING) { link->port_state = FASTRPC_LINK_DISCONNECTING; glink_close(chan); } @@ -1961,10 +2642,9 @@ static int fastrpc_glink_open(int cid) if (err) goto bail; - if (link->port_state == FASTRPC_LINK_CONNECTED || - link->port_state == FASTRPC_LINK_CONNECTING) { + VERIFY(err, (link->port_state == FASTRPC_LINK_DISCONNECTED)); + if (err) goto bail; - } link->port_state = FASTRPC_LINK_CONNECTING; cfg->priv = (void *)(uintptr_t)cid; @@ -1977,8 +2657,11 @@ static int fastrpc_glink_open(int cid) cfg->notify_rx_intent_req = fastrpc_glink_notify_rx_intent_req; handle = glink_open(cfg); VERIFY(err, !IS_ERR_OR_NULL(handle)); - if (err) + if (err) { + if (link->port_state == FASTRPC_LINK_CONNECTING) + link->port_state = FASTRPC_LINK_DISCONNECTED; goto bail; + } me->channel[cid].chan = handle; bail: return err; @@ -1995,9 +2678,9 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, { struct fastrpc_file *fl = filp->private_data; struct hlist_node *n; - struct fastrpc_buf *buf = 0; - struct fastrpc_mmap *map = 0; - struct smq_invoke_ctx *ictx = 0; + struct fastrpc_buf *buf = NULL; + struct fastrpc_mmap *map = NULL; + struct smq_invoke_ctx *ictx = NULL; struct fastrpc_channel_ctx *chan; struct fastrpc_session_ctx *sess; unsigned int len = 0; @@ -2047,16 +2730,16 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, spin_lock(&fl->hlock); hlist_for_each_entry_safe(buf, n, &fl->bufs, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %p %s %p %s %llx\n", "buf:", - buf, "buf->virt:", buf->virt, - "buf->phys:", buf->phys); + "%s %pK %s %pK %s %llx\n", "buf:", + buf, "buf->virt:", buf->virt, + "buf->phys:", buf->phys); } len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "\n%s\n", "LIST OF MAPS:"); hlist_for_each_entry_safe(map, n, &fl->maps, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %p %s %lx %s %llx\n", + "%s %pK %s %lx %s %llx\n", "map:", map, "map->va:", map->va, "map->phys:", map->phys); @@ -2066,7 +2749,7 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, "LIST OF PENDING SMQCONTEXTS:"); hlist_for_each_entry_safe(ictx, n, &fl->clst.pending, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %p %s %u %s %u %s %u\n", + "%s %pK %s %u %s %u %s %u\n", "smqcontext:", ictx, "sc:", ictx->sc, "tid:", ictx->pid, @@ -2077,7 +2760,7 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, "LIST OF INTERRUPTED SMQCONTEXTS:"); hlist_for_each_entry_safe(ictx, n, &fl->clst.interrupted, hn) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, - "%s %p %s %u %s %u %s %u\n", + "%s %pK %s %u %s %u %s %u\n", "smqcontext:", ictx, "sc:", ictx->sc, "tid:", ictx->pid, @@ -2111,25 +2794,47 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); if (err) goto bail; + if (me->channel[cid].ssrcount != + me->channel[cid].prevssrcount) { + if (!me->channel[cid].issubsystemup) { + VERIFY(err, 0); + if (err) { + err = -ENOTCONN; + goto bail; + } + } + } fl->ssrcount = me->channel[cid].ssrcount; if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || - (me->channel[cid].chan == 0)) { - fastrpc_glink_register(cid, me); + (me->channel[cid].chan == NULL)) { + VERIFY(err, 0 == fastrpc_glink_register(cid, me)); + if (err) + goto bail; VERIFY(err, 0 == fastrpc_glink_open(cid)); if (err) goto bail; - VERIFY(err, wait_for_completion_timeout(&me->channel[cid].work, + VERIFY(err, + wait_for_completion_timeout(&me->channel[cid].workport, RPC_TIMEOUT)); if (err) { - me->channel[cid].chan = 0; + me->channel[cid].chan = NULL; goto bail; } kref_init(&me->channel[cid].kref); pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); - if (me->channel[cid].ssrcount != + err = glink_queue_rx_intent(me->channel[cid].chan, NULL, + FASTRPC_GLINK_INTENT_LEN); + err |= glink_queue_rx_intent(me->channel[cid].chan, NULL, + FASTRPC_GLINK_INTENT_LEN); + if (err) + pr_warn("adsprpc: initial intent fail for %d err %d\n", + cid, err); + if (cid == 0 && me->channel[cid].ssrcount != me->channel[cid].prevssrcount) { + if (fastrpc_mmap_remove_ssr(fl)) + pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n"); me->channel[cid].prevssrcount = me->channel[cid].ssrcount; } @@ -2144,10 +2849,10 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) { int err = 0; struct dentry *debugfs_file; - struct fastrpc_file *fl = 0; + struct fastrpc_file *fl = NULL; struct fastrpc_apps *me = &gfa; - VERIFY(err, fl = kzalloc(sizeof(*fl), GFP_KERNEL)); + VERIFY(err, NULL != (fl = kzalloc(sizeof(*fl), GFP_KERNEL))); if (err) return err; debugfs_file = debugfs_create_file(current->comm, 0644, debugfs_root, @@ -2155,8 +2860,10 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) context_list_ctor(&fl->clst); spin_lock_init(&fl->hlock); INIT_HLIST_HEAD(&fl->maps); + INIT_HLIST_HEAD(&fl->perf); INIT_HLIST_HEAD(&fl->bufs); INIT_HLIST_NODE(&fl->hn); + fl->sessionid = 0; fl->tgid = current->tgid; fl->apps = me; fl->mode = FASTRPC_MODE_SERIAL; @@ -2164,10 +2871,14 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) if (debugfs_file != NULL) fl->debugfs_file = debugfs_file; memset(&fl->perf, 0, sizeof(fl->perf)); + fl->qos_request = 0; filp->private_data = fl; + mutex_init(&fl->map_mutex); + mutex_init(&fl->fl_map_mutex); spin_lock(&me->hlock); hlist_add_head(&fl->hn, &me->drivers); spin_unlock(&me->hlock); + mutex_init(&fl->perf_mutex); return 0; } @@ -2176,7 +2887,7 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info) int err = 0; uint32_t cid; - VERIFY(err, fl != 0); + VERIFY(err, fl != NULL); if (err) goto bail; if (fl->cid == -1) { @@ -2191,32 +2902,82 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info) if (err) goto bail; } + VERIFY(err, fl->sctx != NULL); + if (err) + goto bail; *info = (fl->sctx->smmu.enabled ? 1 : 0); bail: return err; } +static int fastrpc_internal_control(struct fastrpc_file *fl, + struct fastrpc_ioctl_control *cp) +{ + int err = 0; + int latency; + + VERIFY(err, !IS_ERR_OR_NULL(fl) && !IS_ERR_OR_NULL(fl->apps)); + if (err) + goto bail; + VERIFY(err, !IS_ERR_OR_NULL(cp)); + if (err) + goto bail; + + switch (cp->req) { + case FASTRPC_CONTROL_LATENCY: + latency = cp->lp.enable == FASTRPC_LATENCY_CTRL_ENB ? + fl->apps->latency : PM_QOS_DEFAULT_VALUE; + VERIFY(err, latency != 0); + if (err) + goto bail; + if (!fl->qos_request) { + pm_qos_add_request(&fl->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, latency); + fl->qos_request = 1; + } else + pm_qos_update_request(&fl->pm_qos_req, latency); + break; + default: + err = -ENOTTY; + break; + } +bail: + return err; +} + static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { union { - struct fastrpc_ioctl_invoke_attrs inv; + struct fastrpc_ioctl_invoke_crc inv; struct fastrpc_ioctl_mmap mmap; struct fastrpc_ioctl_munmap munmap; + struct fastrpc_ioctl_munmap_fd munmap_fd; struct fastrpc_ioctl_init_attrs init; struct fastrpc_ioctl_perf perf; + struct fastrpc_ioctl_control cp; } p; void *param = (char *)ioctl_param; struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; int size = 0, err = 0; uint32_t info; - p.inv.fds = 0; - p.inv.attrs = 0; + p.inv.fds = NULL; + p.inv.attrs = NULL; + p.inv.crc = NULL; + spin_lock(&fl->hlock); + if (fl->file_close == 1) { + err = EBADF; + pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP"); + spin_unlock(&fl->hlock); + goto bail; + } + spin_unlock(&fl->hlock); switch (ioctl_num) { case FASTRPC_IOCTL_INVOKE: size = sizeof(struct fastrpc_ioctl_invoke); + /* fall through */ case FASTRPC_IOCTL_INVOKE_FD: if (!size) size = sizeof(struct fastrpc_ioctl_invoke_fd); @@ -2224,7 +2985,11 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, case FASTRPC_IOCTL_INVOKE_ATTRS: if (!size) size = sizeof(struct fastrpc_ioctl_invoke_attrs); - VERIFY(err, 0 == copy_from_user(&p.inv, param, size)); + /* fall through */ + case FASTRPC_IOCTL_INVOKE_CRC: + if (!size) + size = sizeof(struct fastrpc_ioctl_invoke_crc); + K_COPY_FROM_USER(err, 0, &p.inv, param, size); if (err) goto bail; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, fl->mode, @@ -2233,20 +2998,20 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, goto bail; break; case FASTRPC_IOCTL_MMAP: - VERIFY(err, 0 == copy_from_user(&p.mmap, param, - sizeof(p.mmap))); + K_COPY_FROM_USER(err, 0, &p.mmap, param, + sizeof(p.mmap)); if (err) goto bail; VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &p.mmap))); if (err) goto bail; - VERIFY(err, 0 == copy_to_user(param, &p.mmap, sizeof(p.mmap))); + K_COPY_TO_USER(err, 0, param, &p.mmap, sizeof(p.mmap)); if (err) goto bail; break; case FASTRPC_IOCTL_MUNMAP: - VERIFY(err, 0 == copy_from_user(&p.munmap, param, - sizeof(p.munmap))); + K_COPY_FROM_USER(err, 0, &p.munmap, param, + sizeof(p.munmap)); if (err) goto bail; VERIFY(err, 0 == (err = fastrpc_internal_munmap(fl, @@ -2254,6 +3019,16 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, if (err) goto bail; break; + case FASTRPC_IOCTL_MUNMAP_FD: + K_COPY_FROM_USER(err, 0, &p.munmap_fd, param, + sizeof(p.munmap_fd)); + if (err) + goto bail; + VERIFY(err, 0 == (err = fastrpc_internal_munmap_fd(fl, + &p.munmap_fd))); + if (err) + goto bail; + break; case FASTRPC_IOCTL_SETMODE: switch ((uint32_t)ioctl_param) { case FASTRPC_MODE_PARALLEL: @@ -2263,41 +3038,69 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, case FASTRPC_MODE_PROFILE: fl->profile = (uint32_t)ioctl_param; break; + case FASTRPC_MODE_SESSION: + fl->sessionid = 1; + fl->tgid |= (1 << SESSION_ID_INDEX); + break; default: err = -ENOTTY; break; } break; case FASTRPC_IOCTL_GETPERF: - VERIFY(err, 0 == copy_from_user(&p.perf, - param, sizeof(p.perf))); + K_COPY_FROM_USER(err, 0, &p.perf, + param, sizeof(p.perf)); if (err) goto bail; p.perf.numkeys = sizeof(struct fastrpc_perf)/sizeof(int64_t); if (p.perf.keys) { char *keys = PERF_KEYS; - VERIFY(err, 0 == copy_to_user((char *)p.perf.keys, - keys, strlen(keys)+1)); + K_COPY_TO_USER(err, 0, (void *)p.perf.keys, + keys, strlen(keys)+1); if (err) goto bail; } if (p.perf.data) { - VERIFY(err, 0 == copy_to_user((int64_t *)p.perf.data, - &fl->perf, sizeof(fl->perf))); + struct fastrpc_perf *perf = NULL, *fperf = NULL; + struct hlist_node *n = NULL; + + mutex_lock(&fl->perf_mutex); + hlist_for_each_entry_safe(perf, n, &fl->perf, hn) { + if (perf->tid == current->pid) { + fperf = perf; + break; + } + } + + mutex_unlock(&fl->perf_mutex); + + if (fperf) { + K_COPY_TO_USER(err, 0, (void *)p.perf.data, + fperf, sizeof(*fperf)); + } } - VERIFY(err, 0 == copy_to_user(param, &p.perf, sizeof(p.perf))); + K_COPY_TO_USER(err, 0, param, &p.perf, sizeof(p.perf)); + if (err) + goto bail; + break; + case FASTRPC_IOCTL_CONTROL: + K_COPY_FROM_USER(err, 0, &p.cp, param, + sizeof(p.cp)); + if (err) + goto bail; + VERIFY(err, 0 == (err = fastrpc_internal_control(fl, &p.cp))); if (err) goto bail; break; case FASTRPC_IOCTL_GETINFO: - VERIFY(err, 0 == copy_from_user(&info, param, sizeof(info))); + K_COPY_FROM_USER(err, 0, &info, param, sizeof(info)); if (err) goto bail; VERIFY(err, 0 == (err = fastrpc_get_info(fl, &info))); if (err) goto bail; - VERIFY(err, 0 == copy_to_user(param, &info, sizeof(info))); + K_COPY_TO_USER(err, 0, param, &info, sizeof(info)); if (err) goto bail; break; @@ -2309,10 +3112,18 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, case FASTRPC_IOCTL_INIT_ATTRS: if (!size) size = sizeof(struct fastrpc_ioctl_init_attrs); - VERIFY(err, 0 == copy_from_user(&p.init, param, size)); + K_COPY_FROM_USER(err, 0, &p.init, param, size); + if (err) + goto bail; + VERIFY(err, p.init.init.filelen >= 0 && + p.init.init.filelen < INIT_FILELEN_MAX); + if (err) + goto bail; + VERIFY(err, p.init.init.memlen >= 0 && + p.init.init.memlen < INIT_MEMLEN_MAX); if (err) goto bail; - VERIFY(err, 0 == fastrpc_init_process(fl, &p.init)); + VERIFY(err, 0 == (err = fastrpc_init_process(fl, &p.init))); if (err) goto bail; break; @@ -2332,6 +3143,7 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, { struct fastrpc_apps *me = &gfa; struct fastrpc_channel_ctx *ctx; + struct notif_data *notifdata = data; int cid; ctx = container_of(nb, struct fastrpc_channel_ctx, nb); @@ -2339,16 +3151,84 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, if (code == SUBSYS_BEFORE_SHUTDOWN) { mutex_lock(&me->smd_mutex); ctx->ssrcount++; + ctx->issubsystemup = 0; if (ctx->chan) { fastrpc_glink_close(ctx->chan, cid); - ctx->chan = 0; + ctx->chan = NULL; pr_info("'restart notifier: closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); } mutex_unlock(&me->smd_mutex); + if (cid == 0) + me->staticpd_flags = 0; fastrpc_notify_drivers(me, cid); + } else if (code == SUBSYS_RAMDUMP_NOTIFICATION) { + if (me->channel[0].remoteheap_ramdump_dev && + notifdata->enable_ramdump) { + me->channel[0].ramdumpenabled = 1; + } + } else if (code == SUBSYS_AFTER_POWERUP) { + ctx->issubsystemup = 1; + } + + return NOTIFY_DONE; +} + +static int fastrpc_audio_pdr_notifier_cb(struct notifier_block *pdrnb, + unsigned long code, + void *data) +{ + struct fastrpc_apps *me = &gfa; + struct fastrpc_static_pd *spd; + struct notif_data *notifdata = data; + + spd = container_of(pdrnb, struct fastrpc_static_pd, pdrnb); + if (code == SERVREG_NOTIF_SERVICE_STATE_DOWN_V01) { + mutex_lock(&me->smd_mutex); + spd->pdrcount++; + spd->ispdup = 0; + pr_info("ADSPRPC: Audio PDR notifier %d %s\n", + MAJOR(me->dev_no), spd->spdname); + mutex_unlock(&me->smd_mutex); + if (!strcmp(spd->spdname, + AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME)) + me->staticpd_flags = 0; + fastrpc_notify_pdr_drivers(me, spd->spdname); + } else if (code == SUBSYS_RAMDUMP_NOTIFICATION) { + if (me->channel[0].remoteheap_ramdump_dev && + notifdata->enable_ramdump) { + me->channel[0].ramdumpenabled = 1; + } + } else if (code == SERVREG_NOTIF_SERVICE_STATE_UP_V01) { + spd->ispdup = 1; + } + + return NOTIFY_DONE; +} + +static int fastrpc_get_service_location_notify(struct notifier_block *nb, + unsigned long opcode, void *data) +{ + struct fastrpc_static_pd *spd; + struct pd_qmi_client_data *pdr = data; + int curr_state = 0; + + spd = container_of(nb, struct fastrpc_static_pd, get_service_nb); + if (opcode == LOCATOR_DOWN) { + pr_err("ADSPRPC: Audio PD restart notifier locator down\n"); + return NOTIFY_DONE; } + if (pdr->total_domains == 1) { + spd->pdrhandle = service_notif_register_notifier( + pdr->domain_list[0].name, + pdr->domain_list[0].instance_id, + &spd->pdrnb, &curr_state); + if (IS_ERR(spd->pdrhandle)) + pr_err("ADSPRPC: Unable to register notifier\n"); + } else + pr_err("ADSPRPC: Service returned invalid domains\n"); + return NOTIFY_DONE; } @@ -2377,7 +3257,8 @@ static int fastrpc_cb_probe(struct device *dev) int err = 0, i; int secure_vmid = VMID_CP_PIXEL; - VERIFY(err, 0 != (name = of_get_property(dev->of_node, "label", NULL))); + VERIFY(err, NULL != (name = of_get_property(dev->of_node, + "label", NULL))); if (err) goto bail; for (i = 0; i < NUM_CHANNELS; i++) { @@ -2409,7 +3290,7 @@ static int fastrpc_cb_probe(struct device *dev) start = 0x60000000; VERIFY(err, !IS_ERR_OR_NULL(sess->smmu.mapping = arm_iommu_create_mapping(&platform_bus_type, - start, 0x7fffffff))); + start, 0x78000000))); if (err) goto bail; @@ -2421,7 +3302,7 @@ static int fastrpc_cb_probe(struct device *dev) VERIFY(err, !arm_iommu_attach_device(dev, sess->smmu.mapping)); if (err) goto bail; - sess->dev = dev; + sess->smmu.dev = dev; sess->smmu.enabled = 1; chan->sesscount++; debugfs_global_file = debugfs_create_file("global", 0644, debugfs_root, @@ -2430,6 +3311,46 @@ static int fastrpc_cb_probe(struct device *dev) return err; } +static void init_secure_vmid_list(struct device *dev, char *prop_name, + struct secure_vm *destvm) +{ + int err = 0; + u32 len = 0, i = 0; + u32 *rhvmlist = NULL; + u32 *rhvmpermlist = NULL; + + if (!of_find_property(dev->of_node, prop_name, &len)) + goto bail; + if (len == 0) + goto bail; + len /= sizeof(u32); + VERIFY(err, NULL != (rhvmlist = kcalloc(len, sizeof(u32), GFP_KERNEL))); + if (err) + goto bail; + VERIFY(err, NULL != (rhvmpermlist = kcalloc(len, sizeof(u32), + GFP_KERNEL))); + if (err) + goto bail; + for (i = 0; i < len; i++) { + err = of_property_read_u32_index(dev->of_node, prop_name, i, + &rhvmlist[i]); + rhvmpermlist[i] = PERM_READ | PERM_WRITE | PERM_EXEC; + pr_info("ADSPRPC: Secure VMID = %d", rhvmlist[i]); + if (err) { + pr_err("ADSPRPC: Failed to read VMID\n"); + goto bail; + } + } + destvm->vmid = rhvmlist; + destvm->vmperm = rhvmpermlist; + destvm->vmcount = len; +bail: + if (err) { + kfree(rhvmlist); + kfree(rhvmpermlist); + } +} + static int fastrpc_probe(struct platform_device *pdev) { int err = 0; @@ -2440,7 +3361,18 @@ static int fastrpc_probe(struct platform_device *pdev) struct platform_device *ion_pdev; struct cma *cma; uint32_t val; + int ret = 0; + + if (of_device_is_compatible(dev->of_node, + "qcom,msm-fastrpc-compute")) { + init_secure_vmid_list(dev, "qcom,adsp-remoteheap-vmid", + &gcinfo[0].rhvm); + + + of_property_read_u32(dev->of_node, "qcom,rpc-latency-us", + &me->latency); + } if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute-cb")) return fastrpc_cb_probe(dev); @@ -2471,7 +3403,7 @@ static int fastrpc_probe(struct platform_device *pdev) int srcVM[1] = {VMID_HLOS}; int destVM[4] = {VMID_HLOS, VMID_MSS_MSA, VMID_SSC_Q6, VMID_ADSP_Q6}; - int destVMperm[4] = {PERM_READ | PERM_WRITE, + int destVMperm[4] = {PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC, PERM_READ | PERM_WRITE | PERM_EXEC, @@ -2484,7 +3416,26 @@ static int fastrpc_probe(struct platform_device *pdev) } return 0; } + if (of_property_read_bool(dev->of_node, + "qcom,fastrpc-adsp-audio-pdr")) { + int session; + VERIFY(err, !fastrpc_get_adsp_session( + AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME, &session)); + if (err) + goto spdbail; + me->channel[0].spd[session].get_service_nb.notifier_call = + fastrpc_get_service_location_notify; + ret = get_service_location( + AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME, + AUDIO_PDR_ADSP_SERVICE_NAME, + &me->channel[0].spd[session].get_service_nb); + if (ret) + pr_err("ADSPRPC: Get service location failed: %d\n", + ret); + } +spdbail: + err = 0; VERIFY(err, !of_platform_populate(pdev->dev.of_node, fastrpc_match_table, NULL, &pdev->dev)); @@ -2504,20 +3455,21 @@ static void fastrpc_deinit(void) if (chan->chan) { kref_put_mutex(&chan->kref, fastrpc_channel_close, &me->smd_mutex); - chan->chan = 0; + chan->chan = NULL; } for (j = 0; j < NUM_SESSIONS; j++) { struct fastrpc_session_ctx *sess = &chan->session[j]; - - if (sess->smmu.enabled) { - arm_iommu_detach_device(sess->dev); - sess->dev = 0; + if (sess->smmu.dev) { + arm_iommu_detach_device(sess->smmu.dev); + sess->smmu.dev = NULL; } if (sess->smmu.mapping) { arm_iommu_release_mapping(sess->smmu.mapping); - sess->smmu.mapping = 0; + sess->smmu.mapping = NULL; } } + kfree(chan->rhvm.vmid); + kfree(chan->rhvm.vmperm); } } @@ -2533,7 +3485,7 @@ static struct platform_driver fastrpc_driver = { static int __init fastrpc_device_init(void) { struct fastrpc_apps *me = &gfa; - struct device *dev = 0; + struct device *dev = NULL; int err = 0, i; memset(me, 0, sizeof(*me)); @@ -2568,6 +3520,9 @@ static int __init fastrpc_device_init(void) me->channel[i].dev = dev; me->channel[i].ssrcount = 0; me->channel[i].prevssrcount = 0; + me->channel[i].issubsystemup = 1; + me->channel[i].ramdumpenabled = 0; + me->channel[i].remoteheap_ramdump_dev = NULL; me->channel[i].nb.notifier_call = fastrpc_restart_notifier_cb; me->channel[i].handle = subsys_notif_register_notifier( gcinfo[i].subsys, diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c index 8e72b4ddfd931929974010dc7c0ed4209164a0c9..0f07483eaf1deceb2b3a3f9cd0339f68098c8312 100644 --- a/drivers/char/adsprpc_compat.c +++ b/drivers/char/adsprpc_compat.c @@ -11,7 +11,6 @@ * GNU General Public License for more details. * */ - #include #include #include @@ -36,10 +35,14 @@ _IOWR('R', 9, struct compat_fastrpc_ioctl_perf) #define COMPAT_FASTRPC_IOCTL_INIT_ATTRS \ _IOWR('R', 10, struct compat_fastrpc_ioctl_init_attrs) +#define COMPAT_FASTRPC_IOCTL_INVOKE_CRC \ + _IOWR('R', 11, struct compat_fastrpc_ioctl_invoke_crc) +#define COMPAT_FASTRPC_IOCTL_CONTROL \ + _IOWR('R', 12, struct compat_fastrpc_ioctl_control) struct compat_remote_buf { compat_uptr_t pv; /* buffer pointer */ - compat_ssize_t len; /* length of buffer */ + compat_size_t len; /* length of buffer */ }; union compat_remote_arg { @@ -64,17 +67,24 @@ struct compat_fastrpc_ioctl_invoke_attrs { compat_uptr_t attrs; /* attribute list */ }; +struct compat_fastrpc_ioctl_invoke_crc { + struct compat_fastrpc_ioctl_invoke inv; + compat_uptr_t fds; /* fd list */ + compat_uptr_t attrs; /* attribute list */ + compat_uptr_t crc; /* crc list */ +}; + struct compat_fastrpc_ioctl_mmap { compat_int_t fd; /* ion fd */ compat_uint_t flags; /* flags for dsp to map with */ compat_uptr_t vaddrin; /* optional virtual address */ - compat_ssize_t size; /* size */ + compat_size_t size; /* size */ compat_uptr_t vaddrout; /* dsps virtual address */ }; struct compat_fastrpc_ioctl_munmap { compat_uptr_t vaddrout; /* address to unmap */ - compat_ssize_t size; /* size */ + compat_size_t size; /* size */ }; struct compat_fastrpc_ioctl_init { @@ -99,15 +109,28 @@ struct compat_fastrpc_ioctl_perf { /* kernel performance data */ compat_uptr_t keys; }; +#define FASTRPC_CONTROL_LATENCY (1) +struct compat_fastrpc_ctrl_latency { + compat_uint_t enable; /* latency control enable */ + compat_uint_t level; /* level of control */ +}; + +struct compat_fastrpc_ioctl_control { + compat_uint_t req; + union { + struct compat_fastrpc_ctrl_latency lp; + }; +}; + static int compat_get_fastrpc_ioctl_invoke( - struct compat_fastrpc_ioctl_invoke_attrs __user *inv32, - struct fastrpc_ioctl_invoke_attrs __user **inva, + struct compat_fastrpc_ioctl_invoke_crc __user *inv32, + struct fastrpc_ioctl_invoke_crc __user **inva, unsigned int cmd) { compat_uint_t u, sc; - compat_ssize_t s; + compat_size_t s; compat_uptr_t p; - struct fastrpc_ioctl_invoke_attrs *inv; + struct fastrpc_ioctl_invoke_crc *inv; union compat_remote_arg *pra32; union remote_arg *pra; int err, len, j; @@ -146,10 +169,16 @@ static int compat_get_fastrpc_ioctl_invoke( err |= put_user(p, (compat_uptr_t *)&inv->fds); } err |= put_user(NULL, &inv->attrs); - if (cmd == COMPAT_FASTRPC_IOCTL_INVOKE_ATTRS) { + if ((cmd == COMPAT_FASTRPC_IOCTL_INVOKE_ATTRS) || + (cmd == COMPAT_FASTRPC_IOCTL_INVOKE_CRC)) { err |= get_user(p, &inv32->attrs); err |= put_user(p, (compat_uptr_t *)&inv->attrs); } + err |= put_user(NULL, (compat_uptr_t __user **)&inv->crc); + if (cmd == COMPAT_FASTRPC_IOCTL_INVOKE_CRC) { + err |= get_user(p, &inv32->crc); + err |= put_user(p, (compat_uptr_t __user *)&inv->crc); + } *inva = inv; return err; @@ -161,7 +190,7 @@ static int compat_get_fastrpc_ioctl_mmap( { compat_uint_t u; compat_int_t i; - compat_ssize_t s; + compat_size_t s; compat_uptr_t p; int err; @@ -195,7 +224,7 @@ static int compat_get_fastrpc_ioctl_munmap( struct fastrpc_ioctl_munmap __user *unmap) { compat_uptr_t p; - compat_ssize_t s; + compat_size_t s; int err; err = get_user(p, &unmap32->vaddrout); @@ -221,6 +250,25 @@ static int compat_get_fastrpc_ioctl_perf( return err; } +static int compat_get_fastrpc_ioctl_control( + struct compat_fastrpc_ioctl_control __user *ctrl32, + struct fastrpc_ioctl_control __user *ctrl) +{ + compat_uptr_t p; + int err; + + err = get_user(p, &ctrl32->req); + err |= put_user(p, &ctrl->req); + if (p == FASTRPC_CONTROL_LATENCY) { + err |= get_user(p, &ctrl32->lp.enable); + err |= put_user(p, &ctrl->lp.enable); + err |= get_user(p, &ctrl32->lp.level); + err |= put_user(p, &ctrl->lp.level); + } + + return err; +} + static int compat_get_fastrpc_ioctl_init( struct compat_fastrpc_ioctl_init_attrs __user *init32, struct fastrpc_ioctl_init_attrs __user *init, @@ -273,9 +321,10 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, case COMPAT_FASTRPC_IOCTL_INVOKE: case COMPAT_FASTRPC_IOCTL_INVOKE_FD: case COMPAT_FASTRPC_IOCTL_INVOKE_ATTRS: + case COMPAT_FASTRPC_IOCTL_INVOKE_CRC: { - struct compat_fastrpc_ioctl_invoke_attrs __user *inv32; - struct fastrpc_ioctl_invoke_attrs __user *inv; + struct compat_fastrpc_ioctl_invoke_crc __user *inv32; + struct fastrpc_ioctl_invoke_crc __user *inv; inv32 = compat_ptr(arg); VERIFY(err, 0 == compat_get_fastrpc_ioctl_invoke(inv32, @@ -283,7 +332,7 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, if (err) return err; return filp->f_op->unlocked_ioctl(filp, - FASTRPC_IOCTL_INVOKE_ATTRS, (unsigned long)inv); + FASTRPC_IOCTL_INVOKE_CRC, (unsigned long)inv); } case COMPAT_FASTRPC_IOCTL_MMAP: { @@ -369,6 +418,24 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, case FASTRPC_IOCTL_SETMODE: return filp->f_op->unlocked_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); + case COMPAT_FASTRPC_IOCTL_CONTROL: + { + struct compat_fastrpc_ioctl_control __user *ctrl32; + struct fastrpc_ioctl_control __user *ctrl; + + ctrl32 = compat_ptr(arg); + VERIFY(err, NULL != (ctrl = compat_alloc_user_space( + sizeof(*ctrl)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_control(ctrl32, + ctrl)); + if (err) + return err; + err = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_CONTROL, + (unsigned long)ctrl); + return err; + } case COMPAT_FASTRPC_IOCTL_GETPERF: { struct compat_fastrpc_ioctl_perf __user *perf32; diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 7175b9eea2540437fe1a714e7b8d0e2eba1537ff..535160aaa08eeba106015b2d83f9019e738af066 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -27,6 +27,9 @@ #define FASTRPC_IOCTL_GETINFO _IOWR('R', 8, uint32_t) #define FASTRPC_IOCTL_GETPERF _IOWR('R', 9, struct fastrpc_ioctl_perf) #define FASTRPC_IOCTL_INIT_ATTRS _IOWR('R', 10, struct fastrpc_ioctl_init_attrs) +#define FASTRPC_IOCTL_INVOKE_CRC _IOWR('R', 11, struct fastrpc_ioctl_invoke_crc) +#define FASTRPC_IOCTL_CONTROL _IOWR('R', 12, struct fastrpc_ioctl_control) +#define FASTRPC_IOCTL_MUNMAP_FD _IOWR('R', 13, struct fastrpc_ioctl_munmap_fd) #define FASTRPC_GLINK_GUID "fastrpcglink-apps-dsp" #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp" @@ -35,6 +38,15 @@ /* Set for buffers that have no virtual mapping in userspace */ #define FASTRPC_ATTR_NOVA 0x1 +/* Set for buffers that are NOT dma coherent */ +#define FASTRPC_ATTR_NON_COHERENT 0x2 + +/* Set for buffers that are dma coherent */ +#define FASTRPC_ATTR_COHERENT 0x4 + +/* Fastrpc attribute for keeping the map persistent */ +#define FASTRPC_ATTR_KEEP_MAP 0x8 + /* Driver should operate in parallel with the co-processor */ #define FASTRPC_MODE_PARALLEL 0 @@ -44,9 +56,13 @@ /* Driver should operate in profile mode with the co-processor */ #define FASTRPC_MODE_PROFILE 2 +/* Set FastRPC session ID to 1 */ +#define FASTRPC_MODE_SESSION 4 + /* INIT a new process or attach to guestos */ #define FASTRPC_INIT_ATTACH 0 #define FASTRPC_INIT_CREATE 1 +#define FASTRPC_INIT_CREATE_STATIC 2 /* Retrives number of input buffers from the scalars parameter */ #define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff) @@ -93,7 +109,7 @@ #define VERIFY(err, val) \ do {\ VERIFY_IPRINTF(__FILE_LINE__"info: calling: " #val "\n");\ - if (0 == (val)) {\ + if ((val) == 0) {\ (err) = (err) == 0 ? -1 : (err);\ VERIFY_EPRINTF(__FILE_LINE__"error: %d: " #val "\n", (err));\ } else {\ @@ -106,7 +122,7 @@ do {\ struct remote_buf64 { uint64_t pv; - int64_t len; + uint64_t len; }; struct remote_dma_handle64 { @@ -125,7 +141,7 @@ union remote_arg64 { struct remote_buf { void *pv; /* buffer pointer */ - ssize_t len; /* length of buffer */ + size_t len; /* length of buffer */ }; struct remote_dma_handle { @@ -156,39 +172,66 @@ struct fastrpc_ioctl_invoke_attrs { unsigned int *attrs; /* attribute list */ }; +struct fastrpc_ioctl_invoke_crc { + struct fastrpc_ioctl_invoke inv; + int *fds; /* fd list */ + unsigned int *attrs; /* attribute list */ + unsigned int *crc; +}; + struct fastrpc_ioctl_init { uint32_t flags; /* one of FASTRPC_INIT_* macros */ - uintptr_t __user file; /* pointer to elf file */ - int32_t filelen; /* elf file length */ + uintptr_t file; /* pointer to elf file */ + uint32_t filelen; /* elf file length */ int32_t filefd; /* ION fd for the file */ - uintptr_t __user mem; /* mem for the PD */ - int32_t memlen; /* mem length */ + uintptr_t mem; /* mem for the PD */ + uint32_t memlen; /* mem length */ int32_t memfd; /* ION fd for the mem */ }; struct fastrpc_ioctl_init_attrs { struct fastrpc_ioctl_init init; int attrs; - int siglen; + unsigned int siglen; }; struct fastrpc_ioctl_munmap { uintptr_t vaddrout; /* address to unmap */ - ssize_t size; /* size */ + size_t size; /* size */ }; struct fastrpc_ioctl_mmap { int fd; /* ion fd */ uint32_t flags; /* flags for dsp to map with */ - uintptr_t __user *vaddrin; /* optional virtual address */ - ssize_t size; /* size */ + uintptr_t vaddrin; /* optional virtual address */ + size_t size; /* size */ uintptr_t vaddrout; /* dsps virtual address */ }; +struct fastrpc_ioctl_munmap_fd { + int fd; /* fd */ + uint32_t flags; /* control flags */ + uintptr_t va; /* va */ + ssize_t len; /* length */ +}; + struct fastrpc_ioctl_perf { /* kernel performance data */ - uintptr_t __user data; + uintptr_t data; uint32_t numkeys; - uintptr_t __user keys; + uintptr_t keys; +}; + +#define FASTRPC_CONTROL_LATENCY (1) +struct fastrpc_ctrl_latency { + uint32_t enable; //!latency control enable + uint32_t level; //!level of control +}; + +struct fastrpc_ioctl_control { + uint32_t req; + union { + struct fastrpc_ctrl_latency lp; + }; }; struct smq_null_invoke { @@ -226,7 +269,7 @@ struct smq_invoke_rsp { static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg64_t *pra, uint32_t sc) { - int len = REMOTE_SCALARS_LENGTH(sc); + unsigned int len = REMOTE_SCALARS_LENGTH(sc); return (struct smq_invoke_buf *)(&pra[len]); } @@ -234,7 +277,7 @@ static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg64_t *pra, static inline struct smq_phy_page *smq_phy_page_start(uint32_t sc, struct smq_invoke_buf *buf) { - int nTotal = REMOTE_SCALARS_LENGTH(sc); + unsigned int nTotal = REMOTE_SCALARS_LENGTH(sc); return (struct smq_phy_page *)(&buf[nTotal]); } diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index e907d0d6c0b6e755af8409de5716bf01a75b2096..0aad08aa80ca14dd9570c85cfec492ee0e90a081 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -134,6 +134,35 @@ void diag_dci_record_traffic(int read_bytes, uint8_t ch_type, void diag_dci_record_traffic(int read_bytes, uint8_t ch_type, uint8_t peripheral, uint8_t proc) { } #endif + +static int check_peripheral_dci_support(int peripheral_id, int dci_proc_id) +{ + int dci_peripheral_list = 0; + + if (dci_proc_id < 0 || dci_proc_id >= NUM_DCI_PROC) { + pr_err("diag:In %s,not a supported DCI proc id\n", __func__); + return 0; + } + if (peripheral_id < 0 || peripheral_id >= NUM_PERIPHERALS) { + pr_err("diag:In %s,not a valid peripheral id\n", __func__); + return 0; + } + dci_peripheral_list = dci_ops_tbl[dci_proc_id].peripheral_status; + + if (dci_peripheral_list <= 0 || dci_peripheral_list > DIAG_CON_ALL) { + pr_err("diag:In %s,not a valid dci peripheral mask\n", + __func__); + return 0; + } + /* Remove APSS bit mask information */ + dci_peripheral_list = dci_peripheral_list >> 1; + + if ((1 << peripheral_id) & (dci_peripheral_list)) + return 1; + else + return 0; +} + static void create_dci_log_mask_tbl(unsigned char *mask, uint8_t dirty) { unsigned char *temp = mask; @@ -1440,6 +1469,8 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc) struct siginfo info; struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; + struct pid *pid_struct = NULL; + struct task_struct *dci_task = NULL; memset(&info, 0, sizeof(struct siginfo)); info.si_code = SI_QUEUE; @@ -1457,20 +1488,32 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc) continue; if (entry->client_info.notification_list & peripheral_mask) { info.si_signo = entry->client_info.signal_type; - if (entry->client && - entry->tgid == entry->client->tgid) { - DIAG_LOG(DIAG_DEBUG_DCI, - "entry tgid = %d, dci client tgid = %d\n", - entry->tgid, entry->client->tgid); - stat = send_sig_info( - entry->client_info.signal_type, - &info, entry->client); - if (stat) - pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n", + pid_struct = find_get_pid(entry->tgid); + if (pid_struct) { + dci_task = get_pid_task(pid_struct, + PIDTYPE_PID); + if (!dci_task) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: dci client with pid = %d Exited..\n", + entry->tgid); + mutex_unlock(&driver->dci_mutex); + return; + } + if (entry->client && + entry->tgid == dci_task->tgid) { + DIAG_LOG(DIAG_DEBUG_DCI, + "entry tgid = %d, dci client tgid = %d\n", + entry->tgid, dci_task->tgid); + stat = send_sig_info( + entry->client_info.signal_type, + &info, dci_task); + if (stat) + pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n", info.si_int, stat); - } else - pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n", + } else + pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n", info.si_int, stat); + } } } mutex_unlock(&driver->dci_mutex); @@ -2208,11 +2251,28 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid) { struct list_head *start, *temp; struct diag_dci_client_tbl *entry = NULL; + struct pid *pid_struct = NULL; + struct task_struct *task_s = NULL; list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); - if (entry->client->tgid == tgid) - return entry; + pid_struct = find_get_pid(entry->tgid); + if (!pid_struct) { + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: valid pid doesn't exist for pid = %d\n", + entry->tgid); + continue; + } + task_s = get_pid_task(pid_struct, PIDTYPE_PID); + if (!task_s) { + DIAG_LOG(DIAG_DEBUG_DCI, + "diag: valid task doesn't exist for pid = %d\n", + entry->tgid); + continue; + } + if (task_s == entry->client) + if (entry->client->tgid == tgid) + return entry; } return NULL; } @@ -2379,10 +2439,12 @@ int diag_send_dci_event_mask(int token) * is down. It may also mean that the peripheral doesn't * support DCI. */ - err = diag_dci_write_proc(i, DIAG_CNTL_TYPE, buf, - header_size + DCI_EVENT_MASK_SIZE); - if (err != DIAG_DCI_NO_ERROR) - ret = DIAG_DCI_SEND_DATA_FAIL; + if (check_peripheral_dci_support(i, DCI_LOCAL_PROC)) { + err = diag_dci_write_proc(i, DIAG_CNTL_TYPE, buf, + header_size + DCI_EVENT_MASK_SIZE); + if (err != DIAG_DCI_NO_ERROR) + ret = DIAG_DCI_SEND_DATA_FAIL; + } } mutex_unlock(&event_mask.lock); @@ -2564,11 +2626,13 @@ int diag_send_dci_log_mask(int token) } write_len = dci_fill_log_mask(buf, log_mask_ptr); for (j = 0; j < NUM_PERIPHERALS && write_len; j++) { - err = diag_dci_write_proc(j, DIAG_CNTL_TYPE, buf, - write_len); - if (err != DIAG_DCI_NO_ERROR) { - updated = 0; - ret = DIAG_DCI_SEND_DATA_FAIL; + if (check_peripheral_dci_support(j, DCI_LOCAL_PROC)) { + err = diag_dci_write_proc(j, DIAG_CNTL_TYPE, + buf, write_len); + if (err != DIAG_DCI_NO_ERROR) { + updated = 0; + ret = DIAG_DCI_SEND_DATA_FAIL; + } } } if (updated) @@ -2849,6 +2913,8 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) new_entry->num_buffers = 1; break; } + + new_entry->buffers = NULL; new_entry->real_time = MODE_REALTIME; new_entry->in_service = 0; INIT_LIST_HEAD(&new_entry->list_write_buf); @@ -2919,7 +2985,8 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) fail_alloc: if (new_entry) { - for (i = 0; i < new_entry->num_buffers; i++) { + for (i = 0; ((i < new_entry->num_buffers) && + new_entry->buffers); i++) { proc_buf = &new_entry->buffers[i]; if (proc_buf) { mutex_destroy(&proc_buf->health_mutex); diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index 89fba641f146f78560b3fb3b02dfacdcfe87c7ad..0a3fabab0da07aec81d0a6f632a8c3acece06505 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 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 @@ -50,7 +50,7 @@ static int diag_dbgfs_bridgeinfo_index; static int diag_dbgfs_finished; static int diag_dbgfs_dci_data_index; static int diag_dbgfs_dci_finished; - +static struct mutex diag_dci_dbgfs_mutex; static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { @@ -69,6 +69,7 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, "Uses Device Tree: %d\n" "Apps Supports Separate CMDRSP: %d\n" "Apps Supports HDLC Encoding: %d\n" + "Apps Supports Header Untagging: %d\n" "Apps Supports Sockets: %d\n" "Logging Mode: %d\n" "RSP Buffer is Busy: %d\n" @@ -76,13 +77,15 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, "Time Sync Enabled: %d\n" "MD session mode: %d\n" "MD session mask: %d\n" - "Uses Time API: %d\n", + "Uses Time API: %d\n" + "Supports PD buffering: %d\n", chk_config_get_id(), chk_polling_response(), driver->polling_reg_flag, driver->use_device_tree, driver->supports_separate_cmdrsp, driver->supports_apps_hdlc_encoding, + driver->supports_apps_header_untagging, driver->supports_sockets, driver->logging_mode, driver->rsp_buf_busy, @@ -90,11 +93,12 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, driver->time_sync_enabled, driver->md_session_mode, driver->md_session_mask, - driver->uses_time_api); + driver->uses_time_api, + driver->supports_pd_buffering); for (i = 0; i < NUM_PERIPHERALS; i++) { ret += scnprintf(buf+ret, buf_size-ret, - "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c|\n", + "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c%c|\n", PERIPHERAL_STRING(i), driver->feature[i].feature_mask[0], driver->feature[i].feature_mask[1], @@ -103,9 +107,11 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf, driver->feature[i].encode_hdlc ? 'H':'h', driver->feature[i].peripheral_buffering ? 'B':'b', driver->feature[i].mask_centralization ? 'M':'m', + driver->feature[i].pd_buffering ? 'P':'p', driver->feature[i].stm_support ? 'Q':'q', driver->feature[i].sockets_enabled ? 'S':'s', - driver->feature[i].sent_feature_mask ? 'T':'t'); + driver->feature[i].sent_feature_mask ? 'T':'t', + driver->feature[i].untag_header ? 'U':'u'); } #ifdef CONFIG_DIAG_OVER_USB @@ -149,6 +155,7 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, buf_size = ksize(buf); bytes_remaining = buf_size; + mutex_lock(&diag_dci_dbgfs_mutex); if (diag_dbgfs_dci_data_index == 0) { bytes_written = scnprintf(buf, buf_size, @@ -204,8 +211,8 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, } temp_data++; } - diag_dbgfs_dci_data_index = (i >= DIAG_DCI_DEBUG_CNT) ? 0 : i + 1; + mutex_unlock(&diag_dci_dbgfs_mutex); bytes_written = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buf); kfree(buf); @@ -264,8 +271,10 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, struct list_head *temp; struct diag_cmd_reg_t *item = NULL; + mutex_lock(&driver->cmd_reg_mutex); if (diag_dbgfs_table_index == driver->cmd_reg_count) { diag_dbgfs_table_index = 0; + mutex_unlock(&driver->cmd_reg_mutex); return 0; } @@ -274,6 +283,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, buf = kcalloc(buf_size, sizeof(char), GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) { pr_err("diag: %s, Error allocating memory\n", __func__); + mutex_unlock(&driver->cmd_reg_mutex); return -ENOMEM; } buf_size = ksize(buf); @@ -318,6 +328,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf, break; } diag_dbgfs_table_index = i; + mutex_unlock(&driver->cmd_reg_mutex); *ppos = 0; ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer); @@ -1054,6 +1065,7 @@ int diag_debugfs_init(void) pr_warn("diag: could not allocate memory for dci debug info\n"); mutex_init(&dci_stat_mutex); + mutex_init(&diag_dci_dbgfs_mutex); return 0; err: kfree(dci_traffic); @@ -1067,6 +1079,7 @@ void diag_debugfs_cleanup(void) diag_dbgfs_dent = NULL; kfree(dci_traffic); mutex_destroy(&dci_stat_mutex); + mutex_destroy(&diag_dci_dbgfs_mutex); } #else int diag_debugfs_init(void) { return 0; } diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index c4d378edf8de2cf48f2e5e442afdcbbf4377d7db..f510c14b986dbeffdf79a09baf9e423a55068251 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -60,7 +60,8 @@ static const struct diag_ssid_range_t msg_mask_tbl[] = { { .ssid_first = MSG_SSID_21, .ssid_last = MSG_SSID_21_LAST }, { .ssid_first = MSG_SSID_22, .ssid_last = MSG_SSID_22_LAST }, { .ssid_first = MSG_SSID_23, .ssid_last = MSG_SSID_23_LAST }, - { .ssid_first = MSG_SSID_24, .ssid_last = MSG_SSID_24_LAST } + { .ssid_first = MSG_SSID_24, .ssid_last = MSG_SSID_24_LAST }, + { .ssid_first = MSG_SSID_25, .ssid_last = MSG_SSID_25_LAST } }; static int diag_apps_responds(void) @@ -85,16 +86,15 @@ static int diag_apps_responds(void) static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) { - int i; - int err = 0; - int send_once = 0; + int err = 0, send_once = 0, i; int header_len = sizeof(struct diag_ctrl_log_mask); - uint8_t *buf = NULL; - uint8_t *temp = NULL; - uint32_t mask_size = 0; + uint8_t *buf = NULL, *temp = NULL; + uint8_t upd = 0; + uint32_t mask_size = 0, pd_mask = 0; struct diag_ctrl_log_mask ctrl_pkt; struct diag_mask_info *mask_info = NULL; struct diag_log_mask_t *mask = NULL; + struct diagfwd_info *fwd_info = NULL; if (peripheral >= NUM_PERIPHERALS) return; @@ -106,16 +106,33 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) return; } - if (driver->md_session_mask != 0 && - driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) - mask_info = driver->md_session_map[peripheral]->log_mask; - else + MD_PERIPHERAL_PD_MASK(TYPE_CNTL, peripheral, pd_mask); + + if (driver->md_session_mask != 0) { + if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) { + if (driver->md_session_map[peripheral]) + mask_info = + driver->md_session_map[peripheral]->log_mask; + } else if (driver->md_session_mask & pd_mask) { + upd = diag_mask_to_pd_value(driver->md_session_mask); + if (upd && driver->md_session_map[upd]) + mask_info = + driver->md_session_map[upd]->log_mask; + } else { + DIAG_LOG(DIAG_DEBUG_MASKS, + "asking for mask update with unknown session mask\n"); + return; + } + } else { mask_info = &log_mask; + } - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; mask = (struct diag_log_mask_t *)mask_info->ptr; + if (!mask->ptr) + return; buf = mask_info->update_buf; switch (mask_info->status) { @@ -193,14 +210,14 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) static void diag_send_event_mask_update(uint8_t peripheral) { - uint8_t *buf = NULL; - uint8_t *temp = NULL; + uint8_t *buf = NULL, *temp = NULL; + uint8_t upd = 0; + uint32_t pd_mask = 0; + int num_bytes = EVENT_COUNT_TO_BYTES(driver->last_event_id); + int write_len = 0, err = 0, i = 0, temp_len = 0; struct diag_ctrl_event_mask header; struct diag_mask_info *mask_info = NULL; - int num_bytes = EVENT_COUNT_TO_BYTES(driver->last_event_id); - int write_len = 0; - int err = 0; - int temp_len = 0; + struct diagfwd_info *fwd_info = NULL; if (num_bytes <= 0 || num_bytes > driver->event_mask_size) { pr_debug("diag: In %s, invalid event mask length %d\n", @@ -218,13 +235,28 @@ static void diag_send_event_mask_update(uint8_t peripheral) return; } - if (driver->md_session_mask != 0 && - (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))) - mask_info = driver->md_session_map[peripheral]->event_mask; - else + MD_PERIPHERAL_PD_MASK(TYPE_CNTL, peripheral, pd_mask); + + if (driver->md_session_mask != 0) { + if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) { + if (driver->md_session_map[peripheral]) + mask_info = + driver->md_session_map[peripheral]->event_mask; + } else if (driver->md_session_mask & pd_mask) { + upd = diag_mask_to_pd_value(driver->md_session_mask); + if (upd && driver->md_session_map[upd]) + mask_info = + driver->md_session_map[upd]->event_mask; + } else { + DIAG_LOG(DIAG_DEBUG_MASKS, + "asking for mask update with unknown session mask\n"); + return; + } + } else { mask_info = &event_mask; + } - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; buf = mask_info->update_buf; @@ -278,16 +310,16 @@ static void diag_send_event_mask_update(uint8_t peripheral) static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) { - int i; - int err = 0; + int i, err = 0, temp_len = 0; int header_len = sizeof(struct diag_ctrl_msg_mask); - int temp_len = 0; - uint8_t *buf = NULL; - uint8_t *temp = NULL; - uint32_t mask_size = 0; + uint8_t *buf = NULL, *temp = NULL; + uint8_t upd = 0; + uint8_t msg_mask_tbl_count_local; + uint32_t mask_size = 0, pd_mask = 0; struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; + struct diagfwd_info *fwd_info = NULL; if (peripheral >= NUM_PERIPHERALS) return; @@ -299,17 +331,38 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } - if (driver->md_session_mask != 0 && - (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))) - mask_info = driver->md_session_map[peripheral]->msg_mask; - else + MD_PERIPHERAL_PD_MASK(TYPE_CNTL, peripheral, pd_mask); + + if (driver->md_session_mask != 0) { + if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) { + if (driver->md_session_map[peripheral]) + mask_info = + driver->md_session_map[peripheral]->msg_mask; + } else if (driver->md_session_mask & pd_mask) { + upd = diag_mask_to_pd_value(driver->md_session_mask); + if (upd && driver->md_session_map[upd]) + mask_info = + driver->md_session_map[upd]->msg_mask; + } else { + DIAG_LOG(DIAG_DEBUG_MASKS, + "asking for mask update with unknown session mask\n"); + return; + } + } else { mask_info = &msg_mask; + } - if (!mask_info) + if (!mask_info || !mask_info->ptr || !mask_info->update_buf) return; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + mutex_unlock(&driver->msg_mask_lock); + return; + } buf = mask_info->update_buf; + msg_mask_tbl_count_local = driver->msg_mask_tbl_count; + mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { case DIAG_CTRL_MASK_ALL_DISABLED: @@ -326,9 +379,11 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) goto err; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { - if (((first < mask->ssid_first) || - (last > mask->ssid_last_tools)) && first != ALL_SSID) { + for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { + mutex_lock(&driver->msg_mask_lock); + if (((mask->ssid_first > first) || + (mask->ssid_last_tools < last)) && first != ALL_SSID) { + mutex_unlock(&driver->msg_mask_lock); continue; } @@ -369,12 +424,13 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) if (mask_size > 0) memcpy(buf + header_len, mask->ptr, mask_size); mutex_unlock(&mask->lock); + mutex_unlock(&driver->msg_mask_lock); err = diagfwd_write(peripheral, TYPE_CNTL, buf, header_len + mask_size); if (err && err != -ENODEV) - pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d\n", - peripheral); + pr_err_ratelimited("diag: Unable to send msg masks to peripheral %d, error = %d\n", + peripheral, err); if (first != ALL_SSID) break; @@ -453,6 +509,13 @@ static void diag_send_feature_mask_update(uint8_t peripheral) DIAG_SET_FEATURE_MASK(F_DIAG_REQ_RSP_SUPPORT); if (driver->supports_apps_hdlc_encoding) DIAG_SET_FEATURE_MASK(F_DIAG_APPS_HDLC_ENCODE); + if (driver->supports_apps_header_untagging) { + if (driver->feature[peripheral].untag_header) { + DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG); + driver->peripheral_untag[peripheral] = + ENABLE_PKT_HEADER_UNTAGGING; + } + } DIAG_SET_FEATURE_MASK(F_DIAG_MASK_CENTRALIZATION); if (driver->supports_sockets) DIAG_SET_FEATURE_MASK(F_DIAG_SOCKETS_ENABLED); @@ -491,10 +554,15 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } if (!diag_apps_responds()) return 0; - + mutex_lock(&driver->msg_mask_lock); rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE; rsp.status = MSG_STATUS_SUCCESS; @@ -502,7 +570,6 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, rsp.count = driver->msg_mask_tbl_count; memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); - mask_ptr = (struct diag_msg_mask_t *)mask_info->ptr; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask_ptr++) { if (write_len + sizeof(ssid_range) > dest_len) { @@ -515,7 +582,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, memcpy(dest_buf + write_len, &ssid_range, sizeof(ssid_range)); write_len += sizeof(ssid_range); } - + mutex_unlock(&driver->msg_mask_lock); return write_len; } @@ -539,7 +606,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, if (!diag_apps_responds()) return 0; - + mutex_lock(&driver->msg_mask_lock); req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_BUILD_MASK; @@ -547,9 +614,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, rsp.ssid_last = req->ssid_last; rsp.status = MSG_STATUS_FAIL; rsp.padding = 0; - build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { if (build_mask->ssid_first != req->ssid_first) continue; num_entries = req->ssid_last - req->ssid_first + 1; @@ -570,7 +636,7 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, } memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); - + mutex_unlock(&driver->msg_mask_lock); return write_len; } @@ -594,10 +660,15 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } - + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } if (!diag_apps_responds()) return 0; + mutex_lock(&driver->msg_mask_lock); req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_MSG_MASK; @@ -605,8 +676,13 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, rsp.ssid_last = req->ssid_last; rsp.status = MSG_STATUS_FAIL; rsp.padding = 0; - mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if ((req->ssid_first < mask->ssid_first) || (req->ssid_first > mask->ssid_last_tools)) { @@ -623,7 +699,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, } memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); - + mutex_unlock(&driver->msg_mask_lock); return write_len; } @@ -631,18 +707,15 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, struct diag_md_session_t *info) { - int i; - int write_len = 0; + uint32_t mask_size = 0, offset = 0; + uint32_t *temp = NULL; + int write_len = 0, i = 0, found = 0, peripheral; int header_len = sizeof(struct diag_msg_build_mask_t); - int found = 0; - uint32_t mask_size = 0; - uint32_t offset = 0; struct diag_msg_mask_t *mask = NULL; struct diag_msg_build_mask_t *req = NULL; struct diag_msg_build_mask_t rsp; struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask_next = NULL; - uint32_t *temp = NULL; mask_info = (!info) ? &msg_mask : info->msg_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -652,11 +725,23 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_msg_build_mask_t *)src_buf; - mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { if (i < (driver->msg_mask_tbl_count - 1)) { mask_next = mask; @@ -695,6 +780,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, pr_err_ratelimited("diag: In %s, unable to allocate memory for msg mask ptr, mask_size: %d\n", __func__, mask_size); mutex_unlock(&mask->lock); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); return -ENOMEM; } mask->ptr = temp; @@ -713,8 +800,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_info->status = DIAG_CTRL_MASK_VALID; break; } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); - if (diag_check_update(APPS_DATA)) diag_update_userspace_clients(MSG_MASKS_TYPE); @@ -736,10 +823,19 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mask_size = dest_len - write_len; memcpy(dest_buf + write_len, src_buf + header_len, mask_size); write_len += mask_size; - for (i = 0; i < NUM_PERIPHERALS; i++) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (i == APPS_DATA) + continue; if (!diag_check_update(i)) continue; - diag_send_msg_mask_update(i, req->ssid_first, req->ssid_last); + if (i > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + else + peripheral = i; + mutex_lock(&driver->md_session_lock); + diag_send_msg_mask_update(peripheral, req->ssid_first, + req->ssid_last); + mutex_unlock(&driver->md_session_lock); } end: return write_len; @@ -749,8 +845,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, struct diag_md_session_t *info) { - int i; - int write_len = 0; + int i, write_len = 0, peripheral; int header_len = sizeof(struct diag_msg_config_rsp_t); struct diag_msg_config_rsp_t rsp; struct diag_msg_config_rsp_t *req = NULL; @@ -765,11 +860,25 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_msg_config_rsp_t *)src_buf; - mask = (struct diag_msg_mask_t *)mask_info->ptr; mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); + + mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { @@ -778,6 +887,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mask->range * sizeof(uint32_t)); mutex_unlock(&mask->lock); } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); if (diag_check_update(APPS_DATA)) @@ -795,10 +905,18 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, memcpy(dest_buf, &rsp, header_len); write_len += header_len; - for (i = 0; i < NUM_PERIPHERALS; i++) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (i == APPS_DATA) + continue; if (!diag_check_update(i)) continue; - diag_send_msg_mask_update(i, ALL_SSID, ALL_SSID); + if (i > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + else + peripheral = i; + mutex_lock(&driver->md_session_lock); + diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID); + mutex_unlock(&driver->md_session_lock); } return write_len; @@ -844,9 +962,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, struct diag_md_session_t *info) { - int i; - int write_len = 0; - int mask_len = 0; + int i, write_len = 0, mask_len = 0, peripheral; int header_len = sizeof(struct diag_event_mask_config_t); struct diag_event_mask_config_t rsp; struct diag_event_mask_config_t *req; @@ -860,7 +976,11 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } - + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_event_mask_config_t *)src_buf; mask_len = EVENT_COUNT_TO_BYTES(req->num_bits); if (mask_len <= 0 || mask_len > event_mask.mask_len) { @@ -889,10 +1009,18 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, memcpy(dest_buf + write_len, mask_info->ptr, mask_len); write_len += mask_len; - for (i = 0; i < NUM_PERIPHERALS; i++) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (i == APPS_DATA) + continue; if (!diag_check_update(i)) continue; - diag_send_event_mask_update(i); + if (i > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + else + peripheral = i; + mutex_lock(&driver->md_session_lock); + diag_send_event_mask_update(peripheral); + mutex_unlock(&driver->md_session_lock); } return write_len; @@ -902,8 +1030,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, struct diag_md_session_t *info) { - int i; - int write_len = 0; + int write_len = 0, i, peripheral; uint8_t toggle = 0; struct diag_event_report_t header; struct diag_mask_info *mask_info = NULL; @@ -916,6 +1043,11 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } toggle = *(src_buf + 1); mutex_lock(&mask_info->lock); @@ -936,10 +1068,18 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, */ header.cmd_code = DIAG_CMD_EVENT_TOGGLE; header.padding = 0; - for (i = 0; i < NUM_PERIPHERALS; i++) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (i == APPS_DATA) + continue; if (!diag_check_update(i)) continue; - diag_send_event_mask_update(i); + if (i > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + else + peripheral = i; + mutex_lock(&driver->md_session_lock); + diag_send_event_mask_update(peripheral); + mutex_unlock(&driver->md_session_lock); } memcpy(dest_buf, &header, sizeof(header)); write_len += sizeof(header); @@ -971,6 +1111,11 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } if (!diag_apps_responds()) return 0; @@ -990,6 +1135,11 @@ static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len, write_len += rsp_header_len; log_item = (struct diag_log_mask_t *)mask_info->ptr; + if (!log_item->ptr) { + pr_err("diag: Invalid input in %s, mask: %pK\n", + __func__, log_item); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) { if (log_item->equip_id != req->equip_id) continue; @@ -1075,19 +1225,17 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, struct diag_md_session_t *info) { - int i; - int write_len = 0; + int i, peripheral, write_len = 0; int status = LOG_STATUS_SUCCESS; - int read_len = 0; - int payload_len = 0; + int read_len = 0, payload_len = 0; int req_header_len = sizeof(struct diag_log_config_req_t); int rsp_header_len = sizeof(struct diag_log_config_set_rsp_t); uint32_t mask_size = 0; struct diag_log_config_req_t *req; struct diag_log_config_set_rsp_t rsp; struct diag_log_mask_t *mask = NULL; - unsigned char *temp_buf = NULL; struct diag_mask_info *mask_info = NULL; + unsigned char *temp_buf = NULL; mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -1097,11 +1245,20 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } req = (struct diag_log_config_req_t *)src_buf; read_len += req_header_len; mask = (struct diag_log_mask_t *)mask_info->ptr; - + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + return -EINVAL; + } if (req->equip_id >= MAX_EQUIP_ID) { pr_err("diag: In %s, Invalid logging mask request, equip_id: %d\n", __func__, req->equip_id); @@ -1190,10 +1347,18 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, memcpy(dest_buf + write_len, src_buf + read_len, payload_len); write_len += payload_len; - for (i = 0; i < NUM_PERIPHERALS; i++) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (i == APPS_DATA) + continue; if (!diag_check_update(i)) continue; - diag_send_log_mask_update(i, req->equip_id); + if (i > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + else + peripheral = i; + mutex_lock(&driver->md_session_lock); + diag_send_log_mask_update(peripheral, req->equip_id); + mutex_unlock(&driver->md_session_lock); } end: return write_len; @@ -1206,8 +1371,7 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, struct diag_mask_info *mask_info = NULL; struct diag_log_mask_t *mask = NULL; struct diag_log_config_rsp_t header; - int write_len = 0; - int i; + int write_len = 0, i, peripheral; mask_info = (!info) ? &log_mask : info->log_mask; if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 || @@ -1217,9 +1381,17 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, mask_info); return -EINVAL; } - + if (!mask_info->ptr) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n", + __func__, mask_info->ptr); + return -EINVAL; + } mask = (struct diag_log_mask_t *)mask_info->ptr; - + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { mutex_lock(&mask->lock); memset(mask->ptr, 0, mask->range); @@ -1241,10 +1413,18 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, header.status = LOG_STATUS_SUCCESS; memcpy(dest_buf, &header, sizeof(struct diag_log_config_rsp_t)); write_len += sizeof(struct diag_log_config_rsp_t); - for (i = 0; i < NUM_PERIPHERALS; i++) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (i == APPS_DATA) + continue; if (!diag_check_update(i)) continue; - diag_send_log_mask_update(i, ALL_EQUIP_ID); + if (i > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + else + peripheral = i; + mutex_lock(&driver->md_session_lock); + diag_send_log_mask_update(peripheral, ALL_EQUIP_ID); + mutex_unlock(&driver->md_session_lock); } return write_len; @@ -1277,12 +1457,12 @@ int diag_create_msg_mask_table_entry(struct diag_msg_mask_t *msg_mask, static int diag_create_msg_mask_table(void) { - int i; - int err = 0; + int i, err = 0; struct diag_msg_mask_t *mask = (struct diag_msg_mask_t *)msg_mask.ptr; struct diag_ssid_range_t range; mutex_lock(&msg_mask.lock); + mutex_lock(&driver->msg_mask_lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; @@ -1291,22 +1471,24 @@ static int diag_create_msg_mask_table(void) if (err) break; } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&msg_mask.lock); return err; } static int diag_create_build_time_mask(void) { - int i; - int err = 0; + int i, err = 0; const uint32_t *tbl = NULL; uint32_t tbl_size = 0; struct diag_msg_mask_t *build_mask = NULL; struct diag_ssid_range_t range; mutex_lock(&msg_bt_mask.lock); + mutex_lock(&driver->msg_mask_lock); + driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(build_mask, &range); @@ -1416,8 +1598,8 @@ static int diag_create_build_time_mask(void) } memcpy(build_mask->ptr, tbl, tbl_size); } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&msg_bt_mask.lock); - return err; } @@ -1479,7 +1661,7 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, static void __diag_mask_exit(struct diag_mask_info *mask_info) { - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); @@ -1492,8 +1674,7 @@ static void __diag_mask_exit(struct diag_mask_info *mask_info) int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) { - int i; - int err = 0; + int i, err = 0; struct diag_log_mask_t *src_mask = NULL; struct diag_log_mask_t *dest_mask = NULL; @@ -1536,11 +1717,17 @@ void diag_log_mask_free(struct diag_mask_info *mask_info) int i; struct diag_log_mask_t *mask = NULL; - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; mutex_lock(&mask_info->lock); mask = (struct diag_log_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&mask_info->lock); + return; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; @@ -1553,8 +1740,7 @@ void diag_log_mask_free(struct diag_mask_info *mask_info) static int diag_msg_mask_init(void) { - int err = 0; - int i; + int err = 0, i; err = __diag_mask_init(&msg_mask, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) @@ -1564,18 +1750,18 @@ static int diag_msg_mask_init(void) pr_err("diag: Unable to create msg masks, err: %d\n", err); return err; } + mutex_lock(&driver->msg_mask_lock); driver->msg_mask = &msg_mask; - for (i = 0; i < NUM_PERIPHERALS; i++) driver->max_ssid_count[i] = 0; + mutex_unlock(&driver->msg_mask_lock); return 0; } int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) { - int i; - int err = 0; + int i, err = 0, mask_size = 0; struct diag_msg_mask_t *src_mask = NULL; struct diag_msg_mask_t *dest_mask = NULL; struct diag_ssid_range_t range; @@ -1586,8 +1772,8 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; - mutex_lock(&dest->lock); + mutex_lock(&driver->msg_mask_lock); src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; @@ -1599,13 +1785,16 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) err = diag_create_msg_mask_table_entry(dest_mask, &range); if (err) break; - memcpy(dest_mask->ptr, src_mask->ptr, - dest_mask->range * sizeof(uint32_t)); + if (src_mask->range_tools < dest_mask->range) + mask_size = src_mask->range_tools * sizeof(uint32_t); + else + mask_size = dest_mask->range * sizeof(uint32_t); + memcpy(dest_mask->ptr, src_mask->ptr, mask_size); src_mask++; dest_mask++; } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&dest->lock); - return err; } @@ -1614,17 +1803,24 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) int i; struct diag_msg_mask_t *mask = NULL; - if (!mask_info) + if (!mask_info || !mask_info->ptr) return; - mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)mask_info->ptr; + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); - __diag_mask_exit(mask_info); } @@ -1632,15 +1828,17 @@ static void diag_msg_mask_exit(void) { int i; struct diag_msg_mask_t *mask = NULL; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)(msg_mask.ptr); if (mask) { for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) kfree(mask->ptr); kfree(msg_mask.ptr); + msg_mask.ptr = NULL; } - kfree(msg_mask.update_buf); + msg_mask.update_buf = NULL; + mutex_unlock(&driver->msg_mask_lock); } static int diag_build_time_mask_init(void) @@ -1665,19 +1863,20 @@ static void diag_build_time_mask_exit(void) { int i; struct diag_msg_mask_t *mask = NULL; - + mutex_lock(&driver->msg_mask_lock); mask = (struct diag_msg_mask_t *)(msg_bt_mask.ptr); if (mask) { - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, mask++) kfree(mask->ptr); - kfree(msg_mask.ptr); + kfree(msg_bt_mask.ptr); + msg_bt_mask.ptr = NULL; } + mutex_unlock(&driver->msg_mask_lock); } static int diag_log_mask_init(void) { - int err = 0; - int i; + int err = 0, i; err = __diag_mask_init(&log_mask, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) @@ -1710,8 +1909,7 @@ static void diag_log_mask_exit(void) static int diag_event_mask_init(void) { - int err = 0; - int i; + int err = 0, i; err = __diag_mask_init(&event_mask, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) @@ -1764,11 +1962,8 @@ static void diag_event_mask_exit(void) int diag_copy_to_user_msg_mask(char __user *buf, size_t count, struct diag_md_session_t *info) { - int i; - int err = 0; - int len = 0; - int copy_len = 0; - int total_len = 0; + int i, err = 0, len = 0; + int copy_len = 0, total_len = 0; struct diag_msg_mask_userspace_t header; struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; @@ -1781,6 +1976,11 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + if (!mask_info->ptr || !mask_info->update_buf) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK, mask_info->update_buf: %pK\n", + __func__, mask_info->ptr, mask_info->update_buf); + return -EINVAL; + } mutex_lock(&driver->diag_maskclear_mutex); if (driver->mask_clear) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -1789,9 +1989,17 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EIO; } mutex_unlock(&driver->diag_maskclear_mutex); - mutex_lock(&mask_info->lock); + mutex_lock(&driver->msg_mask_lock); + mask = (struct diag_msg_mask_t *)(mask_info->ptr); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { ptr = mask_info->update_buf; len = 0; @@ -1827,19 +2035,16 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, } total_len += len; } + mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); - return err ? err : total_len; } int diag_copy_to_user_log_mask(char __user *buf, size_t count, struct diag_md_session_t *info) { - int i; - int err = 0; - int len = 0; - int copy_len = 0; - int total_len = 0; + int i, err = 0, len = 0; + int copy_len = 0, total_len = 0; struct diag_log_mask_userspace_t header; struct diag_log_mask_t *mask = NULL; struct diag_mask_info *mask_info = NULL; @@ -1852,8 +2057,20 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + if (!mask_info->ptr || !mask_info->update_buf) { + pr_err("diag: In %s, invalid input mask_info->ptr: %pK, mask_info->update_buf: %pK\n", + __func__, mask_info->ptr, mask_info->update_buf); + return -EINVAL; + } + mutex_lock(&mask_info->lock); mask = (struct diag_log_mask_t *)(mask_info->ptr); + if (!mask->ptr) { + pr_err("diag: Invalid input in %s, mask->ptr: %pK\n", + __func__, mask->ptr); + mutex_unlock(&mask_info->lock); + return -EINVAL; + } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { ptr = mask_info->update_buf; len = 0; @@ -1894,23 +2111,43 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, void diag_send_updates_peripheral(uint8_t peripheral) { - diag_send_feature_mask_update(peripheral); - if (driver->time_sync_enabled) - diag_send_time_sync_update(peripheral); - diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID); - diag_send_log_mask_update(peripheral, ALL_EQUIP_ID); - diag_send_event_mask_update(peripheral); - diag_send_real_time_update(peripheral, + if (!driver->feature[peripheral].sent_feature_mask) + diag_send_feature_mask_update(peripheral); + /* + * Masks (F3, logs and events) will be sent to + * peripheral immediately following feature mask update only + * if diag_id support is not present or + * diag_id support is present and diag_id has been sent to + * peripheral. + */ + if (!driver->feature[peripheral].diag_id_support || + driver->diag_id_sent[peripheral]) { + if (driver->time_sync_enabled) + diag_send_time_sync_update(peripheral); + mutex_lock(&driver->md_session_lock); + diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID); + diag_send_log_mask_update(peripheral, ALL_EQUIP_ID); + diag_send_event_mask_update(peripheral); + mutex_unlock(&driver->md_session_lock); + diag_send_real_time_update(peripheral, driver->real_time_mode[DIAG_LOCAL_PROC]); - diag_send_peripheral_buffering_mode( - &driver->buffering_mode[peripheral]); + diag_send_peripheral_buffering_mode( + &driver->buffering_mode[peripheral]); + + /* + * Clear mask_update variable afer updating + * logging masks to peripheral. + */ + mutex_lock(&driver->cntl_lock); + driver->mask_update ^= PERIPHERAL_MASK(peripheral); + mutex_unlock(&driver->cntl_lock); + } } int diag_process_apps_masks(unsigned char *buf, int len, struct diag_md_session_t *info) { - int size = 0; - int sub_cmd = 0; + int size = 0, sub_cmd = 0; int (*hdlr)(unsigned char *src_buf, int src_len, unsigned char *dest_buf, int dest_len, struct diag_md_session_t *info) = NULL; diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index 13ad4025643b2983d6d6350c6174f5c1fc4b20a6..9cecb030c74fc583ca0997595636de717a0afd9e 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,6 +29,7 @@ #include "diagmem.h" #include "diagfwd.h" #include "diagfwd_peripheral.h" +#include "diag_ipc_logging.h" struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { { @@ -132,7 +133,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) uint8_t found = 0; unsigned long flags; struct diag_md_info *ch = NULL; - uint8_t peripheral; + int peripheral; struct diag_md_session_t *session_info = NULL; if (id < 0 || id >= NUM_DIAG_MD_DEV || id >= DIAG_NUM_PROC) @@ -141,24 +142,30 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) if (!buf || len < 0) return -EINVAL; - peripheral = GET_BUF_PERIPHERAL(ctx); - if (peripheral > NUM_PERIPHERALS) + peripheral = diag_md_get_peripheral(ctx); + if (peripheral < 0) return -EINVAL; - session_info = diag_md_session_get_peripheral(peripheral); + session_info = + diag_md_session_get_peripheral(peripheral); if (!session_info) return -EIO; ch = &diag_md[id]; + if (!ch) + return -EINVAL; spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { if (ch->tbl[i].buf != buf) continue; found = 1; - pr_err_ratelimited("diag: trying to write the same buffer buf: %pK, ctxt: %d len: %d at i: %d back to the table, proc: %d, mode: %d\n", - buf, ctx, ch->tbl[i].len, - i, id, driver->logging_mode); + pr_err_ratelimited("diag: trying to write the same buffer buf: %pK, len: %d, back to the table for p: %d, t: %d, buf_num: %d, proc: %d, i: %d\n", + buf, ch->tbl[i].len, GET_BUF_PERIPHERAL(ctx), + GET_BUF_TYPE(ctx), GET_BUF_NUM(ctx), id, i); + ch->tbl[i].buf = NULL; + ch->tbl[i].len = 0; + ch->tbl[i].ctx = 0; } spin_unlock_irqrestore(&ch->lock, flags); @@ -191,7 +198,10 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) continue; found = 1; - driver->data_ready[i] |= USER_SPACE_DATA_TYPE; + if (!(driver->data_ready[i] & USER_SPACE_DATA_TYPE)) { + driver->data_ready[i] |= USER_SPACE_DATA_TYPE; + atomic_inc(&driver->data_ready_notif[i]); + } pr_debug("diag: wake up logging process\n"); wake_up_interruptible(&driver->wait_q); } @@ -214,27 +224,39 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, struct diag_md_info *ch = NULL; struct diag_buf_tbl_t *entry = NULL; uint8_t drain_again = 0; - uint8_t peripheral = 0; + int peripheral = 0; struct diag_md_session_t *session_info = NULL; + struct pid *pid_struct = NULL; for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) { ch = &diag_md[i]; for (j = 0; j < ch->num_tbl_entries && !err; j++) { entry = &ch->tbl[j]; - if (entry->len <= 0) + if (entry->len <= 0 || entry->buf == NULL) continue; - peripheral = GET_BUF_PERIPHERAL(entry->ctx); - /* Account for Apps data as well */ - if (peripheral > NUM_PERIPHERALS) + + peripheral = diag_md_get_peripheral(entry->ctx); + if (peripheral < 0) goto drop_data; session_info = diag_md_session_get_peripheral(peripheral); + if (!session_info) + goto drop_data; + if (session_info && info && (session_info->pid != info->pid)) continue; if ((info && (info->peripheral_mask & MD_PERIPHERAL_MASK(peripheral)) == 0)) goto drop_data; + pid_struct = find_get_pid(session_info->pid); + if (!pid_struct) { + err = -ESRCH; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: No such md_session_map[%d] with pid = %d err=%d exists..\n", + peripheral, session_info->pid, err); + goto drop_data; + } /* * If the data is from remote processor, copy the remote * token first @@ -254,27 +276,35 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, } if (i > 0) { remote_token = diag_get_remote(i); - err = copy_to_user(buf + ret, &remote_token, - sizeof(int)); + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + &remote_token, + sizeof(int)); + if (err) + goto drop_data; + ret += sizeof(int); + } + } + + /* Copy the length of data being passed */ + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + (void *)&(entry->len), + sizeof(int)); if (err) goto drop_data; ret += sizeof(int); } - /* Copy the length of data being passed */ - err = copy_to_user(buf + ret, (void *)&(entry->len), - sizeof(int)); - if (err) - goto drop_data; - ret += sizeof(int); - /* Copy the actual data being passed */ - err = copy_to_user(buf + ret, (void *)entry->buf, - entry->len); - if (err) - goto drop_data; - ret += entry->len; - + if (get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + ret, + (void *)entry->buf, + entry->len); + if (err) + goto drop_data; + ret += entry->len; + } /* * The data is now copied to the user space client, * Notify that the write is complete and delete its @@ -296,7 +326,11 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, } *pret = ret; - err = copy_to_user(buf + sizeof(int), (void *)&num_data, sizeof(int)); + if (pid_struct && get_pid_task(pid_struct, PIDTYPE_PID)) { + err = copy_to_user(buf + sizeof(int), + (void *)&num_data, + sizeof(int)); + } diag_ws_on_copy_complete(DIAG_WS_MUX); if (drain_again) chk_logging_wakeup(); @@ -320,8 +354,15 @@ int diag_md_close_peripheral(int id, uint8_t peripheral) spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { entry = &ch->tbl[i]; - if (GET_BUF_PERIPHERAL(entry->ctx) != peripheral) - continue; + + if (peripheral > NUM_PERIPHERALS) { + if (GET_PD_CTXT(entry->ctx) != peripheral) + continue; + } else { + if (GET_BUF_PERIPHERAL(entry->ctx) != + peripheral) + continue; + } found = 1; if (ch->ops && ch->ops->write_done) { ch->ops->write_done(entry->buf, entry->len, diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 8f5a00210e72bcebfd7f2ed874723fc45fd0f9cf..c31998cc97df80ecca1d10a686cfdc93ac28c6ab 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 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 @@ -27,7 +27,8 @@ #include "diag_mux.h" #include "diag_usb.h" #include "diag_memorydevice.h" - +#include "diagfwd_peripheral.h" +#include "diag_ipc_logging.h" struct diag_mux_state_t *diag_mux; static struct diag_logger_t usb_logger; @@ -141,9 +142,13 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx) if (!diag_mux) return -EIO; - peripheral = GET_BUF_PERIPHERAL(ctx); - if (peripheral > NUM_PERIPHERALS) + peripheral = diag_md_get_peripheral(ctx); + if (peripheral < 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag:%s:%d invalid peripheral = %d\n", + __func__, __LINE__, peripheral); return -EINVAL; + } if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask) logger = diag_mux->md_ptr; @@ -162,8 +167,13 @@ int diag_mux_close_peripheral(int proc, uint8_t peripheral) if (proc < 0 || proc >= NUM_MUX_PROC) return -EINVAL; /* Peripheral should account for Apps data as well */ - if (peripheral > NUM_PERIPHERALS) - return -EINVAL; + if (peripheral > NUM_PERIPHERALS) { + if (!driver->num_pd_session) + return -EINVAL; + if (peripheral > NUM_MD_SESSIONS) + return -EINVAL; + } + if (!diag_mux) return -EIO; @@ -184,7 +194,8 @@ int diag_mux_switch_logging(int *req_mode, int *peripheral_mask) if (!req_mode) return -EINVAL; - if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) { + if (*peripheral_mask <= 0 || + (*peripheral_mask > (DIAG_CON_ALL | DIAG_CON_UPD_ALL))) { pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__); return -EINVAL; } @@ -194,6 +205,8 @@ int diag_mux_switch_logging(int *req_mode, int *peripheral_mask) new_mask = ~(*peripheral_mask) & diag_mux->mux_mask; if (new_mask != DIAG_CON_NONE) *req_mode = DIAG_MULTI_MODE; + if (new_mask == DIAG_CON_ALL) + *req_mode = DIAG_MEMORY_DEVICE_MODE; break; case DIAG_MEMORY_DEVICE_MODE: new_mask = (*peripheral_mask) | diag_mux->mux_mask; diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index d3dde5048e2bbedd2bf4652d3aa1b45a5564fb76..9de40b02ee83473b3474a750e70ea6e8d9569c20 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -21,10 +21,12 @@ #include #include #include -#include +#include #include #include "diagfwd_bridge.h" +#define THRESHOLD_CLIENT_LIMIT 50 + /* Size of the USB buffers used for read and write*/ #define USB_MAX_OUT_BUF 4096 #define APPS_BUF_SIZE 4096 @@ -33,7 +35,7 @@ #define DIAG_MAX_REQ_SIZE (16 * 1024) #define DIAG_MAX_RSP_SIZE (16 * 1024) -#define APF_DIAG_PADDING 256 +#define APF_DIAG_PADDING 0 /* * In the worst case, the HDLC buffer can be atmost twice the size of the * original packet. Add 3 bytes for 16 bit CRC (2 bytes) and a delimiter @@ -58,19 +60,28 @@ #define DIAG_CTRL_MSG_F3_MASK 11 #define CONTROL_CHAR 0x7E +#define DIAG_ID_ROOT_STRING "root" + #define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */ #define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */ #define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */ #define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */ #define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */ -#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */ -#define DIAG_CON_CDSP (0x0040) +#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */ +#define DIAG_CON_CDSP (0x0040) /* Bit mask for CDSP */ + +#define DIAG_CON_UPD_WLAN (0x1000) /*Bit mask for WLAN PD*/ +#define DIAG_CON_UPD_AUDIO (0x2000) /*Bit mask for AUDIO PD*/ +#define DIAG_CON_UPD_SENSORS (0x4000) /*Bit mask for SENSORS PD*/ #define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/ #define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \ | DIAG_CON_LPASS | DIAG_CON_WCNSS \ | DIAG_CON_SENSORS | DIAG_CON_WDSP \ | DIAG_CON_CDSP) +#define DIAG_CON_UPD_ALL (DIAG_CON_UPD_WLAN \ + | DIAG_CON_UPD_AUDIO \ + | DIAG_CON_UPD_SENSORS) #define DIAG_STM_MODEM 0x01 #define DIAG_STM_LPASS 0x02 @@ -165,7 +176,7 @@ #define PKT_ALLOC 1 #define PKT_RESET 2 -#define FEATURE_MASK_LEN 2 +#define FEATURE_MASK_LEN 4 #define DIAG_MD_NONE 0 #define DIAG_MD_PERIPHERAL 1 @@ -209,11 +220,25 @@ #define NUM_PERIPHERALS 6 #define APPS_DATA (NUM_PERIPHERALS) +#define UPD_WLAN 7 +#define UPD_AUDIO 8 +#define UPD_SENSORS 9 +#define NUM_UPD 3 + +#define MAX_PERIPHERAL_UPD 2 /* Number of sessions possible in Memory Device Mode. +1 for Apps data */ -#define NUM_MD_SESSIONS (NUM_PERIPHERALS + 1) +#define NUM_MD_SESSIONS (NUM_PERIPHERALS \ + + NUM_UPD + 1) #define MD_PERIPHERAL_MASK(x) (1 << x) +#define MD_PERIPHERAL_PD_MASK(x, peripheral, pd_mask) \ +do { \ +fwd_info = &peripheral_info[x][peripheral]; \ +for (i = 0; i <= fwd_info->num_pd - 2; i++) \ + pd_mask |= (1 << fwd_info->upd_diag_id[i].pd);\ +} while (0) + /* * Number of stm processors includes all the peripherals and * apps.Added 1 below to indicate apps @@ -295,6 +320,8 @@ struct diag_cmd_diag_id_query_req_t { struct diag_id_tbl_t { struct list_head link; uint8_t diag_id; + uint8_t pd_val; + uint8_t peripheral; char *process_name; } __packed; struct diag_id_t { @@ -439,7 +466,12 @@ struct diag_partial_pkt_t { struct diag_logging_mode_param_t { uint32_t req_mode; uint32_t peripheral_mask; + uint32_t pd_mask; uint8_t mode_param; + uint8_t diag_id; + uint8_t pd_val; + uint8_t reserved; + int peripheral; } __packed; struct diag_md_session_t { @@ -485,11 +517,14 @@ struct diag_feature_t { uint8_t log_on_demand; uint8_t separate_cmd_rsp; uint8_t encode_hdlc; + uint8_t untag_header; uint8_t peripheral_buffering; + uint8_t pd_buffering; uint8_t mask_centralization; uint8_t stm_support; uint8_t sockets_enabled; uint8_t sent_feature_mask; + uint8_t diag_id_support; }; struct diagchar_dev { @@ -511,11 +546,15 @@ struct diagchar_dev { wait_queue_head_t wait_q; struct diag_client_map *client_map; int *data_ready; + atomic_t data_ready_notif[THRESHOLD_CLIENT_LIMIT]; int num_clients; int polling_reg_flag; int use_device_tree; int supports_separate_cmdrsp; int supports_apps_hdlc_encoding; + int supports_apps_header_untagging; + int supports_pd_buffering; + int peripheral_untag[NUM_PERIPHERALS]; int supports_sockets; /* The state requested in the STM command */ int stm_state_requested[NUM_STM_PROCESSORS]; @@ -568,8 +607,8 @@ struct diagchar_dev { struct diagfwd_info *diagfwd_cmd[NUM_PERIPHERALS]; struct diagfwd_info *diagfwd_dci_cmd[NUM_PERIPHERALS]; struct diag_feature_t feature[NUM_PERIPHERALS]; - struct diag_buffering_mode_t buffering_mode[NUM_PERIPHERALS]; - uint8_t buffering_flag[NUM_PERIPHERALS]; + struct diag_buffering_mode_t buffering_mode[NUM_MD_SESSIONS]; + uint8_t buffering_flag[NUM_MD_SESSIONS]; struct mutex mode_lock; unsigned char *user_space_data_buf; uint8_t user_space_data_busy; @@ -580,6 +619,7 @@ struct diagchar_dev { unsigned char *buf_feature_mask_update; uint8_t hdlc_disabled; struct mutex hdlc_disable_mutex; + struct mutex hdlc_recovery_mutex; struct timer_list hdlc_reset_timer; struct mutex diag_hdlc_mutex; unsigned char *hdlc_buf; @@ -611,6 +651,10 @@ struct diagchar_dev { int in_busy_dcipktdata; int logging_mode; int logging_mask; + int pd_logging_mode[NUM_UPD]; + int pd_session_clear[NUM_UPD]; + int num_pd_session; + int diag_id_sent[NUM_PERIPHERALS]; int mask_check; uint32_t md_session_mask; uint8_t md_session_mode; @@ -625,8 +669,10 @@ struct diagchar_dev { struct diag_mask_info *event_mask; struct diag_mask_info *build_time_mask; uint8_t msg_mask_tbl_count; + uint8_t bt_msg_mask_tbl_count; uint16_t event_mask_size; uint16_t last_event_id; + struct mutex msg_mask_lock; /* Variables for Mask Centralization */ uint16_t num_event_id[NUM_PERIPHERALS]; uint32_t num_equip_id[NUM_PERIPHERALS]; @@ -669,7 +715,11 @@ void diag_cmd_remove_reg_by_proc(int proc); int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry); int diag_mask_param(void); void diag_clear_masks(struct diag_md_session_t *info); - +uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask); +int diag_query_pd(char *process_name); +int diag_search_peripheral_by_pd(uint8_t pd_val); +uint8_t diag_search_diagid_by_pd(uint8_t pd_val, + uint8_t *diag_id, int *peripheral); void diag_record_stats(int type, int flag); struct diag_md_session_t *diag_md_session_get_pid(int pid); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 128d6ce61426115863a6491a225d73a01b1672b7..015854965abd7663f6512a6ba0bbb3b2a088e4d0 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -136,7 +136,6 @@ module_param(poolsize_qsc_usb, uint, 0000); /* This is the max number of user-space clients supported at initialization*/ static unsigned int max_clients = 15; -static unsigned int threshold_client_limit = 50; module_param(max_clients, uint, 0000); /* Timer variables */ @@ -324,7 +323,7 @@ static int diagchar_open(struct inode *inode, struct file *file) if (i < driver->num_clients) { diag_add_client(i, file); } else { - if (i < threshold_client_limit) { + if (i < THRESHOLD_CLIENT_LIMIT) { driver->num_clients++; temp = krealloc(driver->client_map , (driver->num_clients) * sizeof(struct @@ -354,11 +353,17 @@ static int diagchar_open(struct inode *inode, struct file *file) } } driver->data_ready[i] = 0x0; + atomic_set(&driver->data_ready_notif[i], 0); driver->data_ready[i] |= MSG_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= EVENT_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= LOG_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= DCI_LOG_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); driver->data_ready[i] |= DCI_EVENT_MASKS_TYPE; + atomic_inc(&driver->data_ready_notif[i]); if (driver->ref_count == 0) diag_mempool_init(); @@ -393,9 +398,26 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask) ret |= DIAG_CON_WDSP; if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_CDSP)) ret |= DIAG_CON_CDSP; - + if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_WLAN)) + ret |= DIAG_CON_UPD_WLAN; + if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_AUDIO)) + ret |= DIAG_CON_UPD_AUDIO; + if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_SENSORS)) + ret |= DIAG_CON_UPD_SENSORS; return ret; } + +uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask) +{ + uint8_t upd = 0; + + for (upd = UPD_WLAN; upd < NUM_MD_SESSIONS; upd++) { + if (peripheral_mask & (1 << upd)) + return upd; + } + return 0; +} + int diag_mask_param(void) { return diag_mask_clear_param; @@ -423,8 +445,9 @@ void diag_clear_masks(struct diag_md_session_t *info) static void diag_close_logging_process(const int pid) { - int i; - int session_peripheral_mask; + int i, j; + int session_mask; + uint32_t p_mask; struct diag_md_session_t *session_info = NULL; struct diag_logging_mode_param_t params; @@ -440,18 +463,33 @@ static void diag_close_logging_process(const int pid) mutex_unlock(&driver->diag_maskclear_mutex); mutex_lock(&driver->diagchar_mutex); - session_peripheral_mask = session_info->peripheral_mask; + session_mask = session_info->peripheral_mask; diag_md_session_close(session_info); - mutex_unlock(&driver->diagchar_mutex); + + p_mask = + diag_translate_kernel_to_user_mask(session_mask); + for (i = 0; i < NUM_MD_SESSIONS; i++) - if (MD_PERIPHERAL_MASK(i) & session_peripheral_mask) + if (MD_PERIPHERAL_MASK(i) & session_mask) diag_mux_close_peripheral(DIAG_LOCAL_PROC, i); params.req_mode = USB_MODE; params.mode_param = 0; - params.peripheral_mask = - diag_translate_kernel_to_user_mask(session_peripheral_mask); - mutex_lock(&driver->diagchar_mutex); + params.pd_mask = 0; + params.peripheral_mask = p_mask; + + if (driver->num_pd_session > 0) { + for (i = UPD_WLAN; (i < NUM_MD_SESSIONS); i++) { + if (session_mask & MD_PERIPHERAL_MASK(i)) { + j = i - UPD_WLAN; + driver->pd_session_clear[j] = 1; + driver->pd_logging_mode[j] = 0; + driver->num_pd_session -= 1; + params.pd_mask = p_mask; + } + } + } + diag_switch_logging(¶ms); mutex_unlock(&driver->diagchar_mutex); } @@ -654,6 +692,11 @@ static void diag_cmd_invalidate_polling(int change_flag) driver->polling_reg_flag = 0; list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + return; + } polling = diag_cmd_chk_polling(&item->entry); if (polling == DIAG_CMD_POLLING) { driver->polling_reg_flag = 1; @@ -793,6 +836,12 @@ void diag_cmd_remove_reg_by_pid(int pid) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + mutex_unlock(&driver->cmd_reg_mutex); + return; + } if (item->pid == pid) { list_del(&item->link); kfree(item); @@ -811,6 +860,12 @@ void diag_cmd_remove_reg_by_proc(int proc) mutex_lock(&driver->cmd_reg_mutex); list_for_each_safe(start, temp, &driver->cmd_reg_list) { item = list_entry(start, struct diag_cmd_reg_t, link); + if (&item->entry == NULL) { + pr_err("diag: In %s, unable to search command\n", + __func__); + mutex_unlock(&driver->cmd_reg_mutex); + return; + } if (item->proc == proc) { list_del(&item->link); kfree(item); @@ -975,14 +1030,34 @@ static int diag_send_raw_data_remote(int proc, void *buf, int len, else hdlc_disabled = driver->hdlc_disabled; if (hdlc_disabled) { + if (len < 4) { + pr_err("diag: In %s, invalid len: %d of non_hdlc pkt", + __func__, len); + return -EBADMSG; + } payload = *(uint16_t *)(buf + 2); + if (payload > DIAG_MAX_HDLC_BUF_SIZE) { + pr_err("diag: Dropping packet, payload size is %d\n", + payload); + return -EBADMSG; + } driver->hdlc_encode_buf_len = payload; /* - * Adding 4 bytes for start (1 byte), version (1 byte) and - * payload (2 bytes) + * Adding 5 bytes for start (1 byte), version (1 byte), + * payload (2 bytes) and end (1 byte) */ - memcpy(driver->hdlc_encode_buf, buf + 4, payload); - goto send_data; + if (len == (payload + 5)) { + /* + * Adding 4 bytes for start (1 byte), version (1 byte) + * and payload (2 bytes) + */ + memcpy(driver->hdlc_encode_buf, buf + 4, payload); + goto send_data; + } else { + pr_err("diag: In %s, invalid len: %d of non_hdlc pkt", + __func__, len); + return -EBADMSG; + } } if (hdlc_flag) { @@ -1232,11 +1307,9 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) mutex_unlock(&driver->md_session_lock); return -ENOMEM; } - new_session->peripheral_mask = 0; new_session->pid = current->tgid; new_session->task = current; - new_session->log_mask = kzalloc(sizeof(struct diag_mask_info), GFP_KERNEL); if (!new_session->log_mask) { @@ -1354,7 +1427,6 @@ static void diag_md_session_close(struct diag_md_session_t *session_info) struct diag_md_session_t *diag_md_session_get_pid(int pid) { int i; - for (i = 0; i < NUM_MD_SESSIONS; i++) { if (driver->md_session_map[i] && driver->md_session_map[i]->pid == pid) @@ -1470,7 +1542,10 @@ static int diag_md_session_check(int curr_mode, int req_mode, * If this session owns all the requested peripherals, then * call function to switch the modes/masks for the md_session */ + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); + if (!session_info) { *change_mode = 1; return 0; @@ -1499,7 +1574,9 @@ static int diag_md_session_check(int curr_mode, int req_mode, * owned by this md session */ change_mask = driver->md_session_mask & param->peripheral_mask; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); if (session_info) { if ((session_info->peripheral_mask & change_mask) @@ -1543,17 +1620,21 @@ static uint32_t diag_translate_mask(uint32_t peripheral_mask) ret |= (1 << PERIPHERAL_WDSP); if (peripheral_mask & DIAG_CON_CDSP) ret |= (1 << PERIPHERAL_CDSP); - + if (peripheral_mask & DIAG_CON_UPD_WLAN) + ret |= (1 << UPD_WLAN); + if (peripheral_mask & DIAG_CON_UPD_AUDIO) + ret |= (1 << UPD_AUDIO); + if (peripheral_mask & DIAG_CON_UPD_SENSORS) + ret |= (1 << UPD_SENSORS); return ret; } static int diag_switch_logging(struct diag_logging_mode_param_t *param) { - int new_mode; - int curr_mode; - int err = 0; - uint8_t do_switch = 1; - uint32_t peripheral_mask = 0; + int new_mode, i = 0; + int curr_mode, err = 0; + uint8_t do_switch = 1, peripheral = 0; + uint32_t peripheral_mask = 0, pd_mask = 0; if (!param) return -EINVAL; @@ -1564,8 +1645,55 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) return -EINVAL; } - peripheral_mask = diag_translate_mask(param->peripheral_mask); - param->peripheral_mask = peripheral_mask; + if (param->pd_mask) { + pd_mask = diag_translate_mask(param->pd_mask); + for (i = UPD_WLAN; i < NUM_MD_SESSIONS; i++) { + if (pd_mask & (1 << i)) { + if (diag_search_diagid_by_pd(i, ¶m->diag_id, + ¶m->peripheral)) { + param->pd_val = i; + break; + } + } + } + if (!param->diag_id || + (param->pd_val < UPD_WLAN) || + (param->pd_val > NUM_MD_SESSIONS)) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag_id support is not present for the pd mask = %d\n", + param->pd_mask); + return -EINVAL; + } + + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: pd_mask = %d, diag_id = %d, peripheral = %d, pd_val = %d\n", + param->pd_mask, param->diag_id, + param->peripheral, param->pd_val); + + peripheral = param->peripheral; + i = param->pd_val - UPD_WLAN; + if (driver->md_session_map[peripheral] && + (MD_PERIPHERAL_MASK(peripheral) & + diag_mux->mux_mask) && + !driver->pd_session_clear[i]) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag_fr: User PD is already logging onto active peripheral logging\n"); + driver->pd_session_clear[i] = 0; + return -EINVAL; + } + peripheral_mask = + diag_translate_mask(param->pd_mask); + param->peripheral_mask = peripheral_mask; + if (!driver->pd_session_clear[i]) { + driver->pd_logging_mode[i] = 1; + driver->num_pd_session += 1; + } + driver->pd_session_clear[i] = 0; + } else { + peripheral_mask = + diag_translate_mask(param->peripheral_mask); + param->peripheral_mask = peripheral_mask; + } switch (param->req_mode) { case CALLBACK_MODE: @@ -1585,7 +1713,7 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) curr_mode = driver->logging_mode; DIAG_LOG(DIAG_DEBUG_USERSPACE, - "request to switch logging from %d mask:%0x to %d mask:%0x\n", + "request to switch logging from %d mask:%0x to new_mode %d mask:%0x\n", curr_mode, driver->md_session_mask, new_mode, peripheral_mask); err = diag_md_session_check(curr_mode, new_mode, param, &do_switch); @@ -1713,14 +1841,20 @@ static int diag_ioctl_lsm_deinit(void) { int i; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) break; - if (i == driver->num_clients) + if (i == driver->num_clients) { + mutex_unlock(&driver->diagchar_mutex); return -EINVAL; - - driver->data_ready[i] |= DEINIT_TYPE; + } + if (!(driver->data_ready[i] & DEINIT_TYPE)) { + driver->data_ready[i] |= DEINIT_TYPE; + atomic_inc(&driver->data_ready_notif[i]); + } + mutex_unlock(&driver->diagchar_mutex); wake_up_interruptible(&driver->wait_q); return 1; @@ -1829,12 +1963,33 @@ static int diag_ioctl_get_real_time(unsigned long ioarg) static int diag_ioctl_set_buffering_mode(unsigned long ioarg) { struct diag_buffering_mode_t params; + int peripheral = 0; + uint8_t diag_id = 0; if (copy_from_user(¶ms, (void __user *)ioarg, sizeof(params))) return -EFAULT; - if (params.peripheral >= NUM_PERIPHERALS) - return -EINVAL; + diag_map_pd_to_diagid(params.peripheral, &diag_id, &peripheral); + + if ((peripheral < 0) || + peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral = %d\n", __func__, + peripheral); + return -EIO; + } + + if (params.peripheral > NUM_PERIPHERALS && + !driver->feature[peripheral].pd_buffering) { + pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n", + __func__, peripheral); + return -EIO; + } + + if (!driver->feature[peripheral].peripheral_buffering) { + pr_err("diag: In %s, peripheral %d doesn't support buffering\n", + __func__, peripheral); + return -EIO; + } mutex_lock(&driver->mode_lock); driver->buffering_flag[params.peripheral] = 1; @@ -1845,24 +2000,29 @@ static int diag_ioctl_set_buffering_mode(unsigned long ioarg) static int diag_ioctl_peripheral_drain_immediate(unsigned long ioarg) { - uint8_t peripheral; + uint8_t pd, diag_id = 0; + int peripheral = 0; - if (copy_from_user(&peripheral, (void __user *)ioarg, sizeof(uint8_t))) + if (copy_from_user(&pd, (void __user *)ioarg, sizeof(uint8_t))) return -EFAULT; - if (peripheral >= NUM_PERIPHERALS) { + diag_map_pd_to_diagid(pd, &diag_id, &peripheral); + + if ((peripheral < 0) || + peripheral >= NUM_PERIPHERALS) { pr_err("diag: In %s, invalid peripheral %d\n", __func__, peripheral); return -EINVAL; } - if (!driver->feature[peripheral].peripheral_buffering) { - pr_err("diag: In %s, peripheral %d doesn't support buffering\n", - __func__, peripheral); + if (pd > NUM_PERIPHERALS && + !driver->feature[peripheral].pd_buffering) { + pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n", + __func__, peripheral); return -EIO; } - return diag_send_peripheral_drain_immediate(peripheral); + return diag_send_peripheral_drain_immediate(pd, diag_id, peripheral); } static int diag_ioctl_dci_support(unsigned long ioarg) @@ -1887,8 +2047,9 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg) { uint8_t hdlc_support; struct diag_md_session_t *session_info = NULL; - + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); if (copy_from_user(&hdlc_support, (void __user *)ioarg, sizeof(uint8_t))) return -EFAULT; @@ -1905,6 +2066,171 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg) return 0; } +/* + * diag_search_peripheral_by_pd(uint8_t pd_val) + * + * Function will return peripheral by searching pd in the + * diag_id table. + * + */ + +int diag_search_peripheral_by_pd(uint8_t pd_val) +{ + struct list_head *start; + struct list_head *temp; + struct diag_id_tbl_t *item = NULL; + + mutex_lock(&driver->diag_id_mutex); + list_for_each_safe(start, temp, &driver->diag_id_list) { + item = list_entry(start, struct diag_id_tbl_t, link); + if (pd_val == item->pd_val) { + mutex_unlock(&driver->diag_id_mutex); + return item->peripheral; + } + } + mutex_unlock(&driver->diag_id_mutex); + return -EINVAL; +} + +/* + * diag_search_diagid_by_pd(uint8_t pd_val, + * uint8_t *diag_id, int *peripheral) + * + * Function will update the peripheral and diag_id + * from the pd passed as an argument. + * + */ + +uint8_t diag_search_diagid_by_pd(uint8_t pd_val, + uint8_t *diag_id, int *peripheral) +{ + struct list_head *start; + struct list_head *temp; + struct diag_id_tbl_t *item = NULL; + + mutex_lock(&driver->diag_id_mutex); + list_for_each_safe(start, temp, &driver->diag_id_list) { + item = list_entry(start, struct diag_id_tbl_t, link); + if (pd_val == item->pd_val) { + *peripheral = item->peripheral; + *diag_id = item->diag_id; + mutex_unlock(&driver->diag_id_mutex); + return 1; + } + } + mutex_unlock(&driver->diag_id_mutex); + return 0; +} + +/* + * diag_query_pd_name(char *process_name, char *search_str) + * + * The function searches the pd string in the control packet string + * from the peripheral + * + */ + +static int diag_query_pd_name(char *process_name, char *search_str) +{ + if (!process_name) + return -EINVAL; + + if (strnstr(process_name, search_str, strlen(process_name))) + return 1; + + return 0; +} + +/* + * diag_query_pd_name(char *process_name, char *search_str) + * + * The function returns the PD information based on the presence of + * the pd specific string in the control packet's string from peripheral. + * + */ + +int diag_query_pd(char *process_name) +{ + if (!process_name) + return -EINVAL; + + if (diag_query_pd_name(process_name, "modem/root_pd")) + return PERIPHERAL_MODEM; + if (diag_query_pd_name(process_name, "adsp/root_pd")) + return PERIPHERAL_LPASS; + if (diag_query_pd_name(process_name, "slpi/root_pd")) + return PERIPHERAL_SENSORS; + if (diag_query_pd_name(process_name, "cdsp/root_pd")) + return PERIPHERAL_CDSP; + if (diag_query_pd_name(process_name, "wlan_pd")) + return UPD_WLAN; + if (diag_query_pd_name(process_name, "audio_pd")) + return UPD_AUDIO; + if (diag_query_pd_name(process_name, "sensor_pd")) + return UPD_SENSORS; + + return -EINVAL; +} + +/* + * diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param) + * + * IOCTL handler based on the parameter received will check on which peripheral + * the PD is present and validate if the peripheral supports the diag_id and + * tagging feature. + * + */ + +static int diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param) +{ + int ret = -EINVAL, i = 0; + int peripheral = -EINVAL; + uint32_t pd_mask = 0; + + if (!param) + return -EINVAL; + + if (!param->pd_mask) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "query with no pd mask set, returning error\n"); + return -EINVAL; + } + + if (param->pd_mask) { + pd_mask = diag_translate_mask(param->pd_mask); + for (i = UPD_WLAN; i < NUM_MD_SESSIONS; i++) { + if (pd_mask & (1 << i)) { + peripheral = diag_search_peripheral_by_pd(i); + break; + } + } + if (peripheral < 0) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag_id support is not present for the pd mask = %d\n", + param->pd_mask); + return -EINVAL; + } + } + mutex_lock(&driver->diag_cntl_mutex); + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: %s: Untagging support on APPS is %s\n", __func__, + ((driver->supports_apps_header_untagging) ? + "present" : "absent")); + + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: %s: Tagging support on peripheral = %d is %s\n", + __func__, peripheral, + (driver->feature[peripheral].untag_header ? + "present" : "absent")); + + if (driver->supports_apps_header_untagging && + driver->feature[peripheral].untag_header) + ret = 0; + + mutex_unlock(&driver->diag_cntl_mutex); + return ret; +} + static int diag_ioctl_register_callback(unsigned long ioarg) { int err = 0; @@ -2142,6 +2468,12 @@ long diagchar_compat_ioctl(struct file *filp, case DIAG_IOCTL_HDLC_TOGGLE: result = diag_ioctl_hdlc_toggle(ioarg); break; + case DIAG_IOCTL_QUERY_PD_LOGGING: + if (copy_from_user((void *)&mode_param, (void __user *)ioarg, + sizeof(mode_param))) + return -EFAULT; + result = diag_ioctl_query_pd_logging(&mode_param); + break; } return result; } @@ -2204,7 +2536,9 @@ long diagchar_ioctl(struct file *filp, mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_EVENT_STATUS: + mutex_lock(&driver->dci_mutex); result = diag_ioctl_dci_event_status(ioarg); + mutex_unlock(&driver->dci_mutex); break; case DIAG_IOCTL_DCI_CLEAR_LOGS: mutex_lock(&driver->dci_mutex); @@ -2265,6 +2599,12 @@ long diagchar_ioctl(struct file *filp, case DIAG_IOCTL_HDLC_TOGGLE: result = diag_ioctl_hdlc_toggle(ioarg); break; + case DIAG_IOCTL_QUERY_PD_LOGGING: + if (copy_from_user((void *)&mode_param, (void __user *)ioarg, + sizeof(mode_param))) + return -EFAULT; + result = diag_ioctl_query_pd_logging(&mode_param); + break; } return result; } @@ -2596,10 +2936,13 @@ static int diag_user_process_raw_data(const char __user *buf, int len) } else { wait_event_interruptible(driver->wait_q, (driver->in_busy_pktdata == 0)); + mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); ret = diag_process_apps_pkt(user_space_data, len, info); if (ret == 1) - diag_send_error_rsp((void *)(user_space_data), len); + diag_send_error_rsp((void *)(user_space_data), len, + info); } fail: diagmem_free(driver, user_space_data, mempool); @@ -2663,7 +3006,9 @@ static int diag_user_process_userspace_data(const char __user *buf, int len) /* send masks to local processor now */ if (!remote_proc) { + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); if (!session_info) { pr_err("diag:In %s request came from invalid md session pid:%d", __func__, current->tgid); @@ -2798,9 +3143,11 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, int write_len = 0; struct diag_md_session_t *session_info = NULL; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == current->tgid) index = i; + mutex_unlock(&driver->diagchar_mutex); if (index == -1) { pr_err("diag: Client PID not found in table"); @@ -2810,7 +3157,8 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, pr_err("diag: bad address from user side\n"); return -EFAULT; } - wait_event_interruptible(driver->wait_q, driver->data_ready[index]); + wait_event_interruptible(driver->wait_q, + atomic_read(&driver->data_ready_notif[index]) > 0); mutex_lock(&driver->diagchar_mutex); @@ -2821,12 +3169,15 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, /*Copy the type of data being passed*/ data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE; driver->data_ready[index] ^= USER_SPACE_DATA_TYPE; + atomic_dec(&driver->data_ready_notif[index]); COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int)); if (ret == -EFAULT) goto exit; /* place holder for number of data field */ ret += sizeof(int); + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); exit_stat = diag_md_copy_to_user(buf, &ret, count, session_info); goto exit; @@ -2835,16 +3186,20 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, * memory device any more, the condition needs to be cleared. */ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE; + atomic_dec(&driver->data_ready_notif[index]); } if (driver->data_ready[index] & HDLC_SUPPORT_TYPE) { data_type = driver->data_ready[index] & HDLC_SUPPORT_TYPE; driver->data_ready[index] ^= HDLC_SUPPORT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int)); if (ret == -EFAULT) goto exit; + mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); + mutex_unlock(&driver->md_session_lock); if (session_info) { COPY_USER_SPACE_OR_ERR(buf+4, session_info->hdlc_disabled, @@ -2862,6 +3217,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (ret == -EFAULT) goto exit; driver->data_ready[index] ^= DEINIT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); mutex_unlock(&driver->diagchar_mutex); diag_remove_client_entry(file); return ret; @@ -2879,6 +3235,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (write_len > 0) ret += write_len; driver->data_ready[index] ^= MSG_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -2905,6 +3262,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, goto exit; } driver->data_ready[index] ^= EVENT_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -2921,6 +3279,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (write_len > 0) ret += write_len; driver->data_ready[index] ^= LOG_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -2937,6 +3296,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (ret == -EFAULT) goto exit; driver->data_ready[index] ^= PKT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); driver->in_busy_pktdata = 0; goto exit; } @@ -2954,6 +3314,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, goto exit; driver->data_ready[index] ^= DCI_PKT_TYPE; + atomic_dec(&driver->data_ready_notif[index]); driver->in_busy_dcipktdata = 0; goto exit; } @@ -2975,6 +3336,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, goto exit; driver->data_ready[index] ^= DCI_EVENT_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } @@ -2994,15 +3356,16 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, if (ret == -EFAULT) goto exit; driver->data_ready[index] ^= DCI_LOG_MASKS_TYPE; + atomic_dec(&driver->data_ready_notif[index]); goto exit; } exit: - mutex_unlock(&driver->diagchar_mutex); if (driver->data_ready[index] & DCI_DATA_TYPE) { - mutex_lock(&driver->dci_mutex); - /* Copy the type of data being passed */ data_type = driver->data_ready[index] & DCI_DATA_TYPE; + mutex_unlock(&driver->diagchar_mutex); + /* Copy the type of data being passed */ + mutex_lock(&driver->dci_mutex); list_for_each_safe(start, temp, &driver->dci_client_list) { entry = list_entry(start, struct diag_dci_client_tbl, track); @@ -3025,6 +3388,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, exit_stat = diag_copy_dci(buf, count, entry, &ret); mutex_lock(&driver->diagchar_mutex); driver->data_ready[index] ^= DCI_DATA_TYPE; + atomic_dec(&driver->data_ready_notif[index]); mutex_unlock(&driver->diagchar_mutex); if (exit_stat == 1) { mutex_unlock(&driver->dci_mutex); @@ -3034,6 +3398,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, mutex_unlock(&driver->dci_mutex); goto end; } + mutex_unlock(&driver->diagchar_mutex); end: /* * Flush any read that is currently pending on DCI data and @@ -3318,7 +3683,7 @@ static void diag_debug_init(void) * to be logged to IPC */ diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI | - DIAG_DEBUG_BRIDGE; + DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE; } #else static void diag_debug_init(void) @@ -3448,6 +3813,11 @@ static int __init diagchar_init(void) poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6)); driver->num_clients = max_clients; driver->logging_mode = DIAG_USB_MODE; + for (i = 0; i < NUM_UPD; i++) { + driver->pd_logging_mode[i] = 0; + driver->pd_session_clear[i] = 0; + } + driver->num_pd_session = 0; driver->mask_check = 0; driver->in_busy_pktdata = 0; driver->in_busy_dcipktdata = 0; @@ -3463,8 +3833,12 @@ static int __init diagchar_init(void) mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); mutex_init(&apps_data_mutex); - for (i = 0; i < NUM_PERIPHERALS; i++) + mutex_init(&driver->msg_mask_lock); + mutex_init(&driver->hdlc_recovery_mutex); + for (i = 0; i < NUM_PERIPHERALS; i++) { mutex_init(&driver->diagfwd_channel_mutex[i]); + driver->diag_id_sent[i] = 0; + } init_waitqueue_head(&driver->wait_q); INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn); INIT_WORK(&(driver->update_user_clients), @@ -3536,7 +3910,7 @@ static int __init diagchar_init(void) goto fail; mutex_init(&driver->diag_id_mutex); INIT_LIST_HEAD(&driver->diag_id_list); - diag_add_diag_id_to_list(DIAG_ID_APPS, "APPS"); + diag_add_diag_id_to_list(DIAG_ID_APPS, "APPS", APPS_DATA, APPS_DATA); pr_debug("diagchar initialized now"); ret = diagfwd_bridge_init(); if (ret) diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index cd49f00cd83883799dae41d8300c51644b52ccec..11550879ba106a86b8a2accde3616ea4a1420573 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -38,6 +38,7 @@ #include "diag_masks.h" #include "diag_usb.h" #include "diag_mux.h" +#include "diag_ipc_logging.h" #define STM_CMD_VERSION_OFFSET 4 #define STM_CMD_MASK_OFFSET 5 @@ -225,6 +226,7 @@ void chk_logging_wakeup(void) * situation. */ driver->data_ready[i] |= USER_SPACE_DATA_TYPE; + atomic_inc(&driver->data_ready_notif[i]); pr_debug("diag: Force wakeup of logging process\n"); wake_up_interruptible(&driver->wait_q); break; @@ -239,10 +241,11 @@ void chk_logging_wakeup(void) } } -static void pack_rsp_and_send(unsigned char *buf, int len) +static void pack_rsp_and_send(unsigned char *buf, int len, + struct diag_md_session_t *info) { int err; - int retry_count = 0; + int retry_count = 0, i, rsp_ctxt; uint32_t write_len = 0; unsigned long flags; unsigned char *rsp_ptr = driver->encoded_rsp_buf; @@ -257,6 +260,26 @@ static void pack_rsp_and_send(unsigned char *buf, int len) return; } + /* + * Explicitly check for the Peripheral Modem here + * is necessary till a way to identify a peripheral + * if its supporting qshrink4 feature. + */ + if (info && info->peripheral_mask) { + if (info->peripheral_mask == DIAG_CON_ALL || + (info->peripheral_mask & (1 << APPS_DATA)) || + (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) { + rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1); + } else { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (info->peripheral_mask & (1 << i)) + break; + } + rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); + } + } else + rsp_ctxt = driver->rsp_buf_ctxt; + /* * Keep trying till we get the buffer back. It should probably * take one or two iterations. When this loops till UINT_MAX, it @@ -298,8 +321,7 @@ static void pack_rsp_and_send(unsigned char *buf, int len) *(uint8_t *)(rsp_ptr + write_len) = CONTROL_CHAR; write_len += sizeof(uint8_t); - err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, write_len, - driver->rsp_buf_ctxt); + err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, write_len, rsp_ctxt); if (err) { pr_err("diag: In %s, unable to write to mux, err: %d\n", __func__, err); @@ -309,12 +331,13 @@ static void pack_rsp_and_send(unsigned char *buf, int len) } } -static void encode_rsp_and_send(unsigned char *buf, int len) +static void encode_rsp_and_send(unsigned char *buf, int len, + struct diag_md_session_t *info) { struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 }; struct diag_hdlc_dest_type enc = { NULL, NULL, 0 }; unsigned char *rsp_ptr = driver->encoded_rsp_buf; - int err, retry_count = 0; + int err, i, rsp_ctxt, retry_count = 0; unsigned long flags; if (!rsp_ptr || !buf) @@ -326,6 +349,26 @@ static void encode_rsp_and_send(unsigned char *buf, int len) return; } + /* + * Explicitly check for the Peripheral Modem here + * is necessary till a way to identify a peripheral + * if its supporting qshrink4 feature. + */ + if (info && info->peripheral_mask) { + if (info->peripheral_mask == DIAG_CON_ALL || + (info->peripheral_mask & (1 << APPS_DATA)) || + (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) { + rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1); + } else { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (info->peripheral_mask & (1 << i)) + break; + } + rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1); + } + } else + rsp_ctxt = driver->rsp_buf_ctxt; + /* * Keep trying till we get the buffer back. It should probably * take one or two iterations. When this loops till UINT_MAX, it @@ -369,7 +412,7 @@ static void encode_rsp_and_send(unsigned char *buf, int len) diag_hdlc_encode(&send, &enc); driver->encoded_rsp_len = (int)(enc.dest - (void *)rsp_ptr); err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, driver->encoded_rsp_len, - driver->rsp_buf_ctxt); + rsp_ctxt); if (err) { pr_err("diag: In %s, Unable to write to device, err: %d\n", __func__, err); @@ -380,21 +423,23 @@ static void encode_rsp_and_send(unsigned char *buf, int len) memset(buf, '\0', DIAG_MAX_RSP_SIZE); } -void diag_send_rsp(unsigned char *buf, int len) +static void diag_send_rsp(unsigned char *buf, int len, + struct diag_md_session_t *info) { struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled; - session_info = diag_md_session_get_peripheral(APPS_DATA); + session_info = (info) ? info : + diag_md_session_get_peripheral(APPS_DATA); if (session_info) hdlc_disabled = session_info->hdlc_disabled; else hdlc_disabled = driver->hdlc_disabled; if (hdlc_disabled) - pack_rsp_and_send(buf, len); + pack_rsp_and_send(buf, len, session_info); else - encode_rsp_and_send(buf, len); + encode_rsp_and_send(buf, len, session_info); } void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type) @@ -447,8 +492,11 @@ void diag_update_userspace_clients(unsigned int type) mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) - if (driver->client_map[i].pid != 0) + if (driver->client_map[i].pid != 0 && + !(driver->data_ready[i] & type)) { driver->data_ready[i] |= type; + atomic_inc(&driver->data_ready_notif[i]); + } wake_up_interruptible(&driver->wait_q); mutex_unlock(&driver->diagchar_mutex); } @@ -464,7 +512,11 @@ void diag_update_md_clients(unsigned int type) if (driver->client_map[j].pid != 0 && driver->client_map[j].pid == driver->md_session_map[i]->pid) { - driver->data_ready[j] |= type; + if (!(driver->data_ready[i] & type)) { + driver->data_ready[j] |= type; + atomic_inc( + &driver->data_ready_notif[j]); + } break; } } @@ -479,7 +531,10 @@ void diag_update_sleeping_process(int process_id, int data_type) mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients; i++) if (driver->client_map[i].pid == process_id) { - driver->data_ready[i] |= data_type; + if (!(driver->data_ready[i] & data_type)) { + driver->data_ready[i] |= data_type; + atomic_inc(&driver->data_ready_notif[i]); + } break; } wake_up_interruptible(&driver->wait_q); @@ -539,14 +594,15 @@ int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf) * Check if command is valid. If the command is asking for * status, then the processor mask field is to be ignored. */ - if ((version != 2) || (cmd > STATUS_STM) || - ((cmd != STATUS_STM) && ((mask == 0) || (0 != (mask >> 4))))) { + if ((version != 2) || (cmd > STM_AUTO_QUERY) || + ((cmd != STATUS_STM && cmd != STM_AUTO_QUERY) && + ((mask == 0) || (0 != (mask >> 4))))) { /* Command is invalid. Send bad param message response */ dest_buf[0] = BAD_PARAM_RESPONSE_MESSAGE; for (i = 0; i < STM_CMD_NUM_BYTES; i++) dest_buf[i+1] = *(buf + i); return STM_CMD_NUM_BYTES+1; - } else if (cmd != STATUS_STM) { + } else if (cmd != STATUS_STM && cmd != STM_AUTO_QUERY) { if (mask & DIAG_STM_MODEM) diag_process_stm_mask(cmd, DIAG_STM_MODEM, PERIPHERAL_MODEM); @@ -925,7 +981,8 @@ static int diag_cmd_disable_hdlc(unsigned char *src_buf, int src_len, return write_len; } -void diag_send_error_rsp(unsigned char *buf, int len) +void diag_send_error_rsp(unsigned char *buf, int len, + struct diag_md_session_t *info) { /* -1 to accommodate the first byte 0x13 */ if (len > (DIAG_MAX_RSP_SIZE - 1)) { @@ -935,7 +992,7 @@ void diag_send_error_rsp(unsigned char *buf, int len) *(uint8_t *)driver->apps_rsp_buf = DIAG_CMD_ERROR; memcpy((driver->apps_rsp_buf + sizeof(uint8_t)), buf, len); - diag_send_rsp(driver->apps_rsp_buf, len + 1); + diag_send_rsp(driver->apps_rsp_buf, len + 1, info); } int diag_process_apps_pkt(unsigned char *buf, int len, @@ -948,6 +1005,8 @@ int diag_process_apps_pkt(unsigned char *buf, int len, struct diag_cmd_reg_entry_t entry; struct diag_cmd_reg_entry_t *temp_entry = NULL; struct diag_cmd_reg_t *reg_item = NULL; + struct diagfwd_info *fwd_info = NULL; + uint32_t pd_mask = 0; if (!buf) return -EIO; @@ -955,7 +1014,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, /* Check if the command is a supported mask command */ mask_ret = diag_process_apps_masks(buf, len, info); if (mask_ret > 0) { - diag_send_rsp(driver->apps_rsp_buf, mask_ret); + diag_send_rsp(driver->apps_rsp_buf, mask_ret, info); return 0; } @@ -977,7 +1036,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } @@ -985,15 +1044,21 @@ int diag_process_apps_pkt(unsigned char *buf, int len, temp_entry = diag_cmd_search(&entry, ALL_PROC); if (temp_entry) { reg_item = container_of(temp_entry, struct diag_cmd_reg_t, - entry); + entry); if (info) { - if (MD_PERIPHERAL_MASK(reg_item->proc) & - info->peripheral_mask) + MD_PERIPHERAL_PD_MASK(TYPE_CMD, reg_item->proc, + pd_mask); + if ((MD_PERIPHERAL_MASK(reg_item->proc) & + info->peripheral_mask) || + (pd_mask & info->peripheral_mask)) write_len = diag_send_data(reg_item, buf, len); } else { if (MD_PERIPHERAL_MASK(reg_item->proc) & - driver->logging_mask) - diag_send_error_rsp(buf, len); + driver->logging_mask) { + mutex_unlock(&driver->cmd_reg_mutex); + diag_send_error_rsp(buf, len, info); + return write_len; + } else write_len = diag_send_data(reg_item, buf, len); } @@ -1009,13 +1074,13 @@ int diag_process_apps_pkt(unsigned char *buf, int len, for (i = 0; i < 4; i++) *(driver->apps_rsp_buf+i) = *(buf+i); *(uint32_t *)(driver->apps_rsp_buf+4) = DIAG_MAX_REQ_SIZE; - diag_send_rsp(driver->apps_rsp_buf, 8); + diag_send_rsp(driver->apps_rsp_buf, 8, info); return 0; } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) && (*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) { len = diag_process_stm_cmd(buf, driver->apps_rsp_buf); if (len > 0) { - diag_send_rsp(driver->apps_rsp_buf, len); + diag_send_rsp(driver->apps_rsp_buf, len, info); return 0; } return len; @@ -1028,7 +1093,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } /* Check for time sync switch command */ @@ -1039,7 +1104,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } /* Check for diag id command */ @@ -1050,14 +1115,14 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } /* Check for download command */ else if ((chk_apps_master()) && (*buf == 0x3A)) { /* send response back */ driver->apps_rsp_buf[0] = *buf; - diag_send_rsp(driver->apps_rsp_buf, 1); + diag_send_rsp(driver->apps_rsp_buf, 1, info); msleep(5000); /* call download API */ msm_set_restart_mode(RESTART_DLOAD); @@ -1077,7 +1142,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, for (i = 0; i < 13; i++) driver->apps_rsp_buf[i+3] = 0; - diag_send_rsp(driver->apps_rsp_buf, 16); + diag_send_rsp(driver->apps_rsp_buf, 16, info); return 0; } } @@ -1086,7 +1151,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) { memcpy(driver->apps_rsp_buf, buf, 4); driver->apps_rsp_buf[4] = wrap_enabled; - diag_send_rsp(driver->apps_rsp_buf, 5); + diag_send_rsp(driver->apps_rsp_buf, 5, info); return 0; } /* Wrap the Delayed Rsp ID */ @@ -1095,7 +1160,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, wrap_enabled = true; memcpy(driver->apps_rsp_buf, buf, 4); driver->apps_rsp_buf[4] = wrap_count; - diag_send_rsp(driver->apps_rsp_buf, 6); + diag_send_rsp(driver->apps_rsp_buf, 6, info); return 0; } /* Mobile ID Rsp */ @@ -1106,7 +1171,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) { - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } } @@ -1126,7 +1191,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, for (i = 0; i < 55; i++) driver->apps_rsp_buf[i] = 0; - diag_send_rsp(driver->apps_rsp_buf, 55); + diag_send_rsp(driver->apps_rsp_buf, 55, info); return 0; } /* respond to 0x7c command */ @@ -1139,14 +1204,14 @@ int diag_process_apps_pkt(unsigned char *buf, int len, chk_config_get_id(); *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0'; *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0'; - diag_send_rsp(driver->apps_rsp_buf, 14); + diag_send_rsp(driver->apps_rsp_buf, 14, info); return 0; } } write_len = diag_cmd_chk_stats(buf, len, driver->apps_rsp_buf, DIAG_MAX_RSP_SIZE); if (write_len > 0) { - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); return 0; } write_len = diag_cmd_disable_hdlc(buf, len, driver->apps_rsp_buf, @@ -1158,7 +1223,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, * before disabling HDLC encoding on Apps processor. */ mutex_lock(&driver->hdlc_disable_mutex); - diag_send_rsp(driver->apps_rsp_buf, write_len); + diag_send_rsp(driver->apps_rsp_buf, write_len, info); /* * Set the value of hdlc_disabled after sending the response to * the tools. This is required since the tools is expecting a @@ -1178,7 +1243,7 @@ int diag_process_apps_pkt(unsigned char *buf, int len, /* We have now come to the end of the function. */ if (chk_apps_only()) - diag_send_error_rsp(buf, len); + diag_send_error_rsp(buf, len, info); return 0; } @@ -1261,7 +1326,7 @@ void diag_process_hdlc_pkt(void *data, unsigned int len, * recovery algorithm. Send an error response if the * packet is not in expected format. */ - diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len); + diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, info); driver->hdlc_buf_len = 0; end: mutex_unlock(&driver->diag_hdlc_mutex); @@ -1443,7 +1508,9 @@ static void diag_hdlc_start_recovery(unsigned char *buf, int len, if (start_ptr) { /* Discard any partial packet reads */ + mutex_lock(&driver->hdlc_recovery_mutex); driver->incoming_pkt.processing = 0; + mutex_unlock(&driver->hdlc_recovery_mutex); diag_process_non_hdlc_pkt(start_ptr, len - i, info); } } @@ -1457,18 +1524,24 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, const uint32_t header_len = sizeof(struct diag_pkt_frame_t); struct diag_pkt_frame_t *actual_pkt = NULL; unsigned char *data_ptr = NULL; - struct diag_partial_pkt_t *partial_pkt = &driver->incoming_pkt; + struct diag_partial_pkt_t *partial_pkt = NULL; - if (!buf || len <= 0) + mutex_lock(&driver->hdlc_recovery_mutex); + if (!buf || len <= 0) { + mutex_unlock(&driver->hdlc_recovery_mutex); return; - - if (!partial_pkt->processing) + } + partial_pkt = &driver->incoming_pkt; + if (!partial_pkt->processing) { + mutex_unlock(&driver->hdlc_recovery_mutex); goto start; + } if (partial_pkt->remaining > len) { if ((partial_pkt->read_len + len) > partial_pkt->capacity) { pr_err("diag: Invalid length %d, %d received in %s\n", partial_pkt->read_len, len, __func__); + mutex_unlock(&driver->hdlc_recovery_mutex); goto end; } memcpy(partial_pkt->data + partial_pkt->read_len, buf, len); @@ -1482,6 +1555,7 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, pr_err("diag: Invalid length during partial read %d, %d received in %s\n", partial_pkt->read_len, partial_pkt->remaining, __func__); + mutex_unlock(&driver->hdlc_recovery_mutex); goto end; } memcpy(partial_pkt->data + partial_pkt->read_len, buf, @@ -1495,20 +1569,27 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, if (partial_pkt->remaining == 0) { actual_pkt = (struct diag_pkt_frame_t *)(partial_pkt->data); data_ptr = partial_pkt->data + header_len; - if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR) + if (*(uint8_t *)(data_ptr + actual_pkt->length) != + CONTROL_CHAR) { + mutex_unlock(&driver->hdlc_recovery_mutex); diag_hdlc_start_recovery(buf, len, info); + mutex_lock(&driver->hdlc_recovery_mutex); + } err = diag_process_apps_pkt(data_ptr, actual_pkt->length, info); if (err) { pr_err("diag: In %s, unable to process incoming data packet, err: %d\n", __func__, err); + mutex_unlock(&driver->hdlc_recovery_mutex); goto end; } partial_pkt->read_len = 0; partial_pkt->total_len = 0; partial_pkt->processing = 0; + mutex_unlock(&driver->hdlc_recovery_mutex); goto start; } + mutex_unlock(&driver->hdlc_recovery_mutex); goto end; start: @@ -1518,17 +1599,17 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, if (actual_pkt->start != CONTROL_CHAR) { diag_hdlc_start_recovery(buf, len, info); - diag_send_error_rsp(buf, len); + diag_send_error_rsp(buf, len, info); goto end; } - + mutex_lock(&driver->hdlc_recovery_mutex); if (pkt_len + header_len > partial_pkt->capacity) { pr_err("diag: In %s, incoming data is too large for the request buffer %d\n", __func__, pkt_len); + mutex_unlock(&driver->hdlc_recovery_mutex); diag_hdlc_start_recovery(buf, len, info); break; } - if ((pkt_len + header_len) > (len - read_bytes)) { partial_pkt->read_len = len - read_bytes; partial_pkt->total_len = pkt_len + header_len; @@ -1536,19 +1617,27 @@ void diag_process_non_hdlc_pkt(unsigned char *buf, int len, partial_pkt->read_len; partial_pkt->processing = 1; memcpy(partial_pkt->data, buf, partial_pkt->read_len); + mutex_unlock(&driver->hdlc_recovery_mutex); break; } data_ptr = buf + header_len; - if (*(uint8_t *)(data_ptr + actual_pkt->length) != CONTROL_CHAR) + if (*(uint8_t *)(data_ptr + actual_pkt->length) != + CONTROL_CHAR) { + mutex_unlock(&driver->hdlc_recovery_mutex); diag_hdlc_start_recovery(buf, len, info); + mutex_lock(&driver->hdlc_recovery_mutex); + } else hdlc_reset = 0; err = diag_process_apps_pkt(data_ptr, actual_pkt->length, info); - if (err) + if (err) { + mutex_unlock(&driver->hdlc_recovery_mutex); break; + } read_bytes += header_len + pkt_len + 1; buf += header_len + pkt_len + 1; /* advance to next pkt */ + mutex_unlock(&driver->hdlc_recovery_mutex); } end: return; @@ -1586,6 +1675,9 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, switch (type) { case TYPE_DATA: if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n", + peripheral, type, num); diagfwd_write_done(peripheral, type, num); diag_ws_on_copy(DIAG_WS_MUX); } else if (peripheral == APPS_DATA) { @@ -1599,16 +1691,18 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, break; case TYPE_CMD: if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n", + peripheral, type, num); diagfwd_write_done(peripheral, type, num); - } else if (peripheral == APPS_DATA) { + } + if (peripheral == APPS_DATA || + ctxt == DIAG_MEMORY_DEVICE_MODE) { spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags); driver->rsp_buf_busy = 0; driver->encoded_rsp_len = 0; spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags); - } else { - pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n", - peripheral, __func__, type); } break; default: @@ -1639,6 +1733,10 @@ int diagfwd_init(void) driver->real_time_mode[i] = 1; driver->supports_separate_cmdrsp = 1; driver->supports_apps_hdlc_encoding = 1; + driver->supports_apps_header_untagging = 1; + driver->supports_pd_buffering = 1; + for (i = 0; i < NUM_PERIPHERALS; i++) + driver->peripheral_untag[i] = 0; mutex_init(&driver->diag_hdlc_mutex); mutex_init(&driver->diag_cntl_mutex); mutex_init(&driver->mode_lock); @@ -1667,10 +1765,17 @@ int diagfwd_init(void) driver->feature[i].stm_support = DISABLE_STM; driver->feature[i].rcvd_feature_mask = 0; driver->feature[i].peripheral_buffering = 0; + driver->feature[i].pd_buffering = 0; driver->feature[i].encode_hdlc = 0; + driver->feature[i].untag_header = + DISABLE_PKT_HEADER_UNTAGGING; driver->feature[i].mask_centralization = 0; driver->feature[i].log_on_demand = 0; driver->feature[i].sent_feature_mask = 0; + driver->feature[i].diag_id_support = 0; + } + + for (i = 0; i < NUM_MD_SESSIONS; i++) { driver->buffering_mode[i].peripheral = i; driver->buffering_mode[i].mode = DIAG_BUFFERING_MODE_STREAMING; driver->buffering_mode[i].high_wm_val = DEFAULT_HIGH_WM_VAL; @@ -1711,6 +1816,9 @@ int diagfwd_init(void) } kmemleak_not_leak(driver->data_ready); + for (i = 0; i < THRESHOLD_CLIENT_LIMIT; i++) + atomic_set(&driver->data_ready_notif[i], 0); + if (driver->apps_req_buf == NULL) { driver->apps_req_buf = kzalloc(DIAG_MAX_REQ_SIZE, GFP_KERNEL); if (!driver->apps_req_buf) diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h index 47c85551cf27dae29334d817492684b44591c2eb..0e0bf2d95ed4fd4e45b668da6fa42e6484f72ae1 100644 --- a/drivers/char/diag/diagfwd.h +++ b/drivers/char/diag/diagfwd.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, 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 @@ -19,9 +19,11 @@ */ #define SET_BUF_CTXT(p, d, n) \ (((p & 0xFF) << 16) | ((d & 0xFF) << 8) | (n & 0xFF)) +#define SET_PD_CTXT(u) ((u & 0xFF) << 24) #define GET_BUF_PERIPHERAL(p) ((p & 0xFF0000) >> 16) #define GET_BUF_TYPE(d) ((d & 0x00FF00) >> 8) #define GET_BUF_NUM(n) ((n & 0x0000FF)) +#define GET_PD_CTXT(u) ((u & 0xFF000000) >> 24) #define CHK_OVERFLOW(bufStart, start, end, length) \ ((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0) @@ -45,7 +47,8 @@ void diag_update_userspace_clients(unsigned int type); void diag_update_sleeping_process(int process_id, int data_type); int diag_process_apps_pkt(unsigned char *buf, int len, struct diag_md_session_t *info); -void diag_send_error_rsp(unsigned char *buf, int len); +void diag_send_error_rsp(unsigned char *buf, int len, + struct diag_md_session_t *info); void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type); int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf); void diag_md_hdlc_reset_timer_func(unsigned long pid); diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 3684b8d5e095cd5b7d56729ec97a86a736c6fec6..5de7897b31a23c96d802c362ca0e92879e6d8406 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,6 +90,18 @@ static int diagfwd_bridge_mux_disconnect(int id, int mode) { if (id < 0 || id >= NUM_REMOTE_DEV) return -EINVAL; + + if ((mode == DIAG_USB_MODE && + driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) || + (mode == DIAG_MEMORY_DEVICE_MODE && + driver->logging_mode == DIAG_USB_MODE)) { + /* + * Don't close the MHI channels when usb is disconnected + * and a process is running in memory device mode. + */ + return 0; + } + if (bridge_info[id].dev_ops && bridge_info[id].dev_ops->close) bridge_info[id].dev_ops->close(bridge_info[id].ctxt); return 0; diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index e13871e7eef363c1cffcff370c9a544c019fd895..162d53f3edb4f7c0b9eb2c5aec48f75b40288811 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -39,9 +39,6 @@ static void diag_mask_update_work_fn(struct work_struct *work) for (peripheral = 0; peripheral <= NUM_PERIPHERALS; peripheral++) { if (!(driver->mask_update & PERIPHERAL_MASK(peripheral))) continue; - mutex_lock(&driver->cntl_lock); - driver->mask_update ^= PERIPHERAL_MASK(peripheral); - mutex_unlock(&driver->cntl_lock); diag_send_updates_peripheral(peripheral); } } @@ -68,9 +65,9 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info) driver->feature[peripheral].sent_feature_mask = 0; driver->feature[peripheral].rcvd_feature_mask = 0; - flush_workqueue(driver->cntl_wq); reg_dirty |= PERIPHERAL_MASK(peripheral); diag_cmd_remove_reg_by_proc(peripheral); + driver->diag_id_sent[peripheral] = 0; driver->feature[peripheral].stm_support = DISABLE_STM; driver->feature[peripheral].log_on_demand = 0; driver->stm_state[peripheral] = DISABLE_STM; @@ -111,6 +108,8 @@ void diag_notify_md_client(uint8_t peripheral, int data) { int stat = 0; struct siginfo info; + struct pid *pid_struct; + struct task_struct *result; if (peripheral > NUM_PERIPHERALS) return; @@ -123,18 +122,38 @@ void diag_notify_md_client(uint8_t peripheral, int data) info.si_code = SI_QUEUE; info.si_int = (PERIPHERAL_MASK(peripheral) | data); info.si_signo = SIGCONT; - if (driver->md_session_map[peripheral] && - driver->md_session_map[peripheral]->task) { - if (driver->md_session_map[peripheral]->pid == - driver->md_session_map[peripheral]->task->tgid) { + + if (!driver->md_session_map[peripheral] || + driver->md_session_map[peripheral]->pid <= 0) { + pr_err("diag: md_session_map[%d] is invalid\n", peripheral); + mutex_unlock(&driver->md_session_lock); + return; + } + + pid_struct = find_get_pid( + driver->md_session_map[peripheral]->pid); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "md_session_map[%d] pid = %d task = %pK\n", + peripheral, + driver->md_session_map[peripheral]->pid, + driver->md_session_map[peripheral]->task); + + if (pid_struct) { + result = get_pid_task(pid_struct, PIDTYPE_PID); + + if (!result) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "md_session %d pid = %d, md_session %d task tgid = %d\n", + "diag: md_session_map[%d] with pid = %d Exited..\n", peripheral, - driver->md_session_map[peripheral]->pid, - peripheral, - driver->md_session_map[peripheral]->task->tgid); - stat = send_sig_info(info.si_signo, &info, - driver->md_session_map[peripheral]->task); + driver->md_session_map[peripheral]->pid); + mutex_unlock(&driver->md_session_lock); + return; + } + + if (driver->md_session_map[peripheral] && + driver->md_session_map[peripheral]->task == result) { + stat = send_sig_info(info.si_signo, + &info, result); if (stat) pr_err("diag: Err sending signal to memory device client, signal data: 0x%x, stat: %d\n", info.si_int, stat); @@ -199,6 +218,20 @@ static void process_hdlc_encoding_feature(uint8_t peripheral) } } +static void process_upd_header_untagging_feature(uint8_t peripheral) +{ + if (peripheral >= NUM_PERIPHERALS) + return; + + if (driver->supports_apps_header_untagging) { + driver->feature[peripheral].untag_header = + ENABLE_PKT_HEADER_UNTAGGING; + } else { + driver->feature[peripheral].untag_header = + DISABLE_PKT_HEADER_UNTAGGING; + } +} + static void process_command_deregistration(uint8_t *buf, uint32_t len, uint8_t peripheral) { @@ -375,6 +408,8 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len, driver->feature[peripheral].separate_cmd_rsp = 1; if (FEATURE_SUPPORTED(F_DIAG_APPS_HDLC_ENCODE)) process_hdlc_encoding_feature(peripheral); + if (FEATURE_SUPPORTED(F_DIAG_PKT_HEADER_UNTAG)) + process_upd_header_untagging_feature(peripheral); if (FEATURE_SUPPORTED(F_DIAG_STM)) enable_stm_feature(peripheral); if (FEATURE_SUPPORTED(F_DIAG_MASK_CENTRALIZATION)) @@ -383,6 +418,10 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len, driver->feature[peripheral].peripheral_buffering = 1; if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED)) enable_socket_feature(peripheral); + if (FEATURE_SUPPORTED(F_DIAG_DIAGID_SUPPORT)) + driver->feature[peripheral].diag_id_support = 1; + if (FEATURE_SUPPORTED(F_DIAG_PD_BUFFERING)) + driver->feature[peripheral].pd_buffering = 1; } process_socket_feature(peripheral); @@ -511,6 +550,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, /* Don't account for pkt_id and length */ read_len += header_len - (2 * sizeof(uint32_t)); + mutex_lock(&driver->msg_mask_lock); driver->max_ssid_count[peripheral] = header->count; for (i = 0; i < header->count && read_len < len; i++) { ssid_range = (struct diag_ssid_range_t *)ptr; @@ -554,6 +594,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, } driver->msg_mask_tbl_count += 1; } + mutex_unlock(&driver->msg_mask_lock); } static void diag_build_time_mask_update(uint8_t *buf, @@ -578,11 +619,11 @@ static void diag_build_time_mask_update(uint8_t *buf, __func__, range->ssid_first, range->ssid_last); return; } - + mutex_lock(&driver->msg_mask_lock); build_mask = (struct diag_msg_mask_t *)(driver->build_time_mask->ptr); num_items = range->ssid_last - range->ssid_first + 1; - for (i = 0; i < driver->msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { if (build_mask->ssid_first != range->ssid_first) continue; found = 1; @@ -601,7 +642,7 @@ static void diag_build_time_mask_update(uint8_t *buf, if (found) goto end; - new_size = (driver->msg_mask_tbl_count + 1) * + new_size = (driver->bt_msg_mask_tbl_count + 1) * sizeof(struct diag_msg_mask_t); temp = krealloc(driver->build_time_mask->ptr, new_size, GFP_KERNEL); if (!temp) { @@ -616,8 +657,9 @@ static void diag_build_time_mask_update(uint8_t *buf, __func__, err); goto end; } - driver->msg_mask_tbl_count += 1; + driver->bt_msg_mask_tbl_count += 1; end: + mutex_unlock(&driver->msg_mask_lock); return; } @@ -651,7 +693,8 @@ static void process_build_mask_report(uint8_t *buf, uint32_t len, } } -int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name) +int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name, + uint8_t pd_val, uint8_t peripheral) { struct diag_id_tbl_t *new_item = NULL; @@ -670,6 +713,8 @@ int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name) } kmemleak_not_leak(new_item->process_name); new_item->diag_id = diag_id; + new_item->pd_val = pd_val; + new_item->peripheral = peripheral; strlcpy(new_item->process_name, process_name, strlen(process_name) + 1); INIT_LIST_HEAD(&new_item->link); mutex_lock(&driver->diag_id_mutex); @@ -704,21 +749,65 @@ static void process_diagid(uint8_t *buf, uint32_t len, { struct diag_ctrl_diagid *header = NULL; struct diag_ctrl_diagid ctrl_pkt; + struct diagfwd_info *fwd_info = NULL; char *process_name = NULL; int err = 0; + int pd_val; + char *root_str = NULL; uint8_t local_diag_id = 0; + uint8_t new_request = 0, i = 0, ch_type = 0; if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS) return; + header = (struct diag_ctrl_diagid *)buf; process_name = (char *)&header->process_name; if (diag_query_diag_id(process_name, &local_diag_id)) ctrl_pkt.diag_id = local_diag_id; else { diag_id++; - diag_add_diag_id_to_list(diag_id, process_name); + new_request = 1; + pd_val = diag_query_pd(process_name); + if (pd_val < 0) + return; + diag_add_diag_id_to_list(diag_id, process_name, + pd_val, peripheral); ctrl_pkt.diag_id = diag_id; } + root_str = strnstr(process_name, DIAG_ID_ROOT_STRING, + strlen(process_name)); + + if (new_request) { + for (ch_type = 0; ch_type < NUM_TYPES; ch_type++) { + if (ch_type == TYPE_DCI || + ch_type == TYPE_DCI_CMD) + continue; + fwd_info = &peripheral_info[ch_type][peripheral]; + fwd_info->num_pd++; + + if (root_str) { + fwd_info->root_diag_id.diagid_val = + ctrl_pkt.diag_id; + fwd_info->root_diag_id.reg_str = + process_name; + fwd_info->root_diag_id.pd = pd_val; + } else { + i = fwd_info->num_pd - 2; + if (i >= 0 && i < MAX_PERIPHERAL_UPD) { + fwd_info->upd_diag_id[i].diagid_val = + ctrl_pkt.diag_id; + fwd_info->upd_diag_id[i].reg_str = + process_name; + fwd_info->upd_diag_id[i].pd = pd_val; + } + } + } + } + + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: peripheral = %d: diag_id string = %s,diag_id = %d\n", + peripheral, process_name, ctrl_pkt.diag_id); + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_DIAGID; ctrl_pkt.version = 1; strlcpy((char *)&ctrl_pkt.process_name, process_name, @@ -728,8 +817,28 @@ static void process_diagid(uint8_t *buf, uint32_t len, err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, ctrl_pkt.len + sizeof(ctrl_pkt.pkt_id) + sizeof(ctrl_pkt.len)); if (err && err != -ENODEV) { - pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n", + pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n", peripheral, err); + } else { + /* + * Masks (F3, logs and events) will be sent to + * peripheral immediately following feature mask update only + * if diag_id support is not present or + * diag_id support is present and diag_id has been sent to + * peripheral. + * With diag_id being sent now, mask will be updated + * to peripherals. + */ + if (root_str) { + driver->diag_id_sent[peripheral] = 1; + queue_work(driver->cntl_wq, &driver->mask_update_work); + } + fwd_info = &peripheral_info[TYPE_DATA][peripheral]; + diagfwd_buffers_init(fwd_info); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n", + driver->diag_id_sent[peripheral], peripheral, + ctrl_pkt.diag_id, process_name); } } @@ -837,32 +946,54 @@ static int diag_compute_real_time(int idx) } static void diag_create_diag_mode_ctrl_pkt(unsigned char *dest_buf, - int real_time) + uint8_t diag_id, int real_time) { struct diag_ctrl_msg_diagmode diagmode; + struct diag_ctrl_msg_diagmode_v2 diagmode_v2; int msg_size = sizeof(struct diag_ctrl_msg_diagmode); + int msg_size_2 = sizeof(struct diag_ctrl_msg_diagmode_v2); if (!dest_buf) return; - diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; - diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN; - diagmode.version = 1; - diagmode.sleep_vote = real_time ? 1 : 0; - /* - * 0 - Disables real-time logging (to prevent - * frequent APPS wake-ups, etc.). - * 1 - Enable real-time logging - */ - diagmode.real_time = real_time; - diagmode.use_nrt_values = 0; - diagmode.commit_threshold = 0; - diagmode.sleep_threshold = 0; - diagmode.sleep_time = 0; - diagmode.drain_timer_val = 0; - diagmode.event_stale_timer_val = 0; - - memcpy(dest_buf, &diagmode, msg_size); + if (diag_id) { + diagmode_v2.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; + diagmode_v2.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN_V2; + diagmode_v2.version = 2; + diagmode_v2.sleep_vote = real_time ? 1 : 0; + /* + * 0 - Disables real-time logging (to prevent + * frequent APPS wake-ups, etc.). + * 1 - Enable real-time logging + */ + diagmode_v2.real_time = real_time; + diagmode_v2.use_nrt_values = 0; + diagmode_v2.commit_threshold = 0; + diagmode_v2.sleep_threshold = 0; + diagmode_v2.sleep_time = 0; + diagmode_v2.drain_timer_val = 0; + diagmode_v2.event_stale_timer_val = 0; + diagmode_v2.diag_id = diag_id; + memcpy(dest_buf, &diagmode_v2, msg_size_2); + } else { + diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE; + diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN; + diagmode.version = 1; + diagmode.sleep_vote = real_time ? 1 : 0; + /* + * 0 - Disables real-time logging (to prevent + * frequent APPS wake-ups, etc.). + * 1 - Enable real-time logging + */ + diagmode.real_time = real_time; + diagmode.use_nrt_values = 0; + diagmode.commit_threshold = 0; + diagmode.sleep_threshold = 0; + diagmode.sleep_time = 0; + diagmode.drain_timer_val = 0; + diagmode.event_stale_timer_val = 0; + memcpy(dest_buf, &diagmode, msg_size); + } } void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index) @@ -947,7 +1078,7 @@ static void diag_send_diag_mode_update_remote(int token, int real_time) memcpy(buf + write_len, &dci_header, dci_header_size); write_len += dci_header_size; - diag_create_diag_mode_ctrl_pkt(buf + write_len, real_time); + diag_create_diag_mode_ctrl_pkt(buf + write_len, 0, real_time); write_len += msg_size; *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ write_len += sizeof(uint8_t); @@ -1053,14 +1184,18 @@ void diag_real_time_work_fn(struct work_struct *work) } #endif -static int __diag_send_real_time_update(uint8_t peripheral, int real_time) +static int __diag_send_real_time_update(uint8_t peripheral, int real_time, + uint8_t diag_id) { - char buf[sizeof(struct diag_ctrl_msg_diagmode)]; - int msg_size = sizeof(struct diag_ctrl_msg_diagmode); + char buf[sizeof(struct diag_ctrl_msg_diagmode_v2)]; + int msg_size = 0; int err = 0; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); return -EINVAL; + } if (!driver->diagfwd_cntl[peripheral] || !driver->diagfwd_cntl[peripheral]->ch_open) { @@ -1075,12 +1210,17 @@ static int __diag_send_real_time_update(uint8_t peripheral, int real_time) return -EINVAL; } - diag_create_diag_mode_ctrl_pkt(buf, real_time); + msg_size = (diag_id ? sizeof(struct diag_ctrl_msg_diagmode_v2) : + sizeof(struct diag_ctrl_msg_diagmode)); + + diag_create_diag_mode_ctrl_pkt(buf, diag_id, real_time); mutex_lock(&driver->diag_cntl_mutex); + err = diagfwd_write(peripheral, TYPE_CNTL, buf, msg_size); + if (err && err != -ENODEV) { - pr_err("diag: In %s, unable to write to socket, peripheral: %d, type: %d, len: %d, err: %d\n", + pr_err("diag: In %s, unable to write, peripheral: %d, type: %d, len: %d, err: %d\n", __func__, peripheral, TYPE_CNTL, msg_size, err); } else { @@ -1106,27 +1246,56 @@ int diag_send_real_time_update(uint8_t peripheral, int real_time) return -EINVAL; } - return __diag_send_real_time_update(peripheral, real_time); + return __diag_send_real_time_update(peripheral, real_time, 0); +} + +void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral) +{ + if (!diag_search_diagid_by_pd(pd, (void *)diag_id, + (void *)peripheral)) { + *diag_id = 0; + if ((pd >= 0) && pd < NUM_PERIPHERALS) + *peripheral = pd; + else + *peripheral = -EINVAL; + } + + if (*peripheral >= 0) + if (!driver->feature[*peripheral].pd_buffering) + *diag_id = 0; } int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) { int err = 0; int mode = MODE_REALTIME; - uint8_t peripheral = 0; + int peripheral = 0; + uint8_t diag_id = 0; if (!params) return -EIO; - peripheral = params->peripheral; - if (peripheral >= NUM_PERIPHERALS) { + diag_map_pd_to_diagid(params->peripheral, + &diag_id, &peripheral); + + if ((peripheral < 0) || + peripheral >= NUM_PERIPHERALS) { pr_err("diag: In %s, invalid peripheral %d\n", __func__, peripheral); return -EINVAL; } - if (!driver->buffering_flag[peripheral]) + if (!driver->buffering_flag[params->peripheral]) { + pr_err("diag: In %s, buffering flag not set for %d\n", __func__, + params->peripheral); return -EINVAL; + } + + if (!driver->feature[peripheral].peripheral_buffering) { + pr_err("diag: In %s, peripheral %d doesn't support buffering\n", + __func__, peripheral); + return -EIO; + } switch (params->mode) { case DIAG_BUFFERING_MODE_STREAMING: @@ -1145,7 +1314,7 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", __func__, peripheral); - driver->buffering_flag[peripheral] = 0; + driver->buffering_flag[params->peripheral] = 0; return -EIO; } @@ -1160,35 +1329,39 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params) (params->low_wm_val != DIAG_MIN_WM_VAL))) { pr_err("diag: In %s, invalid watermark values, high: %d, low: %d, peripheral: %d\n", __func__, params->high_wm_val, params->low_wm_val, - peripheral); + params->peripheral); return -EINVAL; } mutex_lock(&driver->mode_lock); - err = diag_send_buffering_tx_mode_pkt(peripheral, params); + err = diag_send_buffering_tx_mode_pkt(peripheral, diag_id, params); if (err) { pr_err("diag: In %s, unable to send buffering mode packet to peripheral %d, err: %d\n", __func__, peripheral, err); goto fail; } - err = diag_send_buffering_wm_values(peripheral, params); + err = diag_send_buffering_wm_values(peripheral, diag_id, params); if (err) { pr_err("diag: In %s, unable to send buffering wm value packet to peripheral %d, err: %d\n", __func__, peripheral, err); goto fail; } - err = __diag_send_real_time_update(peripheral, mode); + err = __diag_send_real_time_update(peripheral, mode, diag_id); if (err) { pr_err("diag: In %s, unable to send mode update to peripheral %d, mode: %d, err: %d\n", __func__, peripheral, mode, err); goto fail; } - driver->buffering_mode[peripheral].peripheral = peripheral; - driver->buffering_mode[peripheral].mode = params->mode; - driver->buffering_mode[peripheral].low_wm_val = params->low_wm_val; - driver->buffering_mode[peripheral].high_wm_val = params->high_wm_val; + driver->buffering_mode[params->peripheral].peripheral = + params->peripheral; + driver->buffering_mode[params->peripheral].mode = + params->mode; + driver->buffering_mode[params->peripheral].low_wm_val = + params->low_wm_val; + driver->buffering_mode[params->peripheral].high_wm_val = + params->high_wm_val; if (params->mode == DIAG_BUFFERING_MODE_STREAMING) - driver->buffering_flag[peripheral] = 0; + driver->buffering_flag[params->peripheral] = 0; fail: mutex_unlock(&driver->mode_lock); return err; @@ -1227,10 +1400,12 @@ int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data) return err; } -int diag_send_peripheral_drain_immediate(uint8_t peripheral) +int diag_send_peripheral_drain_immediate(uint8_t pd, + uint8_t diag_id, int peripheral) { int err = 0; struct diag_ctrl_drain_immediate ctrl_pkt; + struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2; if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", @@ -1245,32 +1420,57 @@ int diag_send_peripheral_drain_immediate(uint8_t peripheral) return -ENODEV; } - ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM; - /* The length of the ctrl pkt is size of version and stream id */ - ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t); - ctrl_pkt.version = 1; - ctrl_pkt.stream_id = 1; - - err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, sizeof(ctrl_pkt)); - if (err && err != -ENODEV) { - pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n", - peripheral, err); + if (diag_id && driver->feature[peripheral].pd_buffering) { + ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM; + /* + * The length of the ctrl pkt is size of version, + * diag_id and stream id + */ + ctrl_pkt_v2.len = sizeof(uint32_t) + (2 * sizeof(uint8_t)); + ctrl_pkt_v2.version = 2; + ctrl_pkt_v2.diag_id = diag_id; + ctrl_pkt_v2.stream_id = 1; + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2, + sizeof(ctrl_pkt_v2)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + } + } else { + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM; + /* + * The length of the ctrl pkt is + * size of version and stream id + */ + ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t); + ctrl_pkt.version = 1; + ctrl_pkt.stream_id = 1; + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, + sizeof(ctrl_pkt)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + } } return err; } int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, - struct diag_buffering_mode_t *params) + uint8_t diag_id, struct diag_buffering_mode_t *params) { int err = 0; struct diag_ctrl_peripheral_tx_mode ctrl_pkt; + struct diag_ctrl_peripheral_tx_mode_v2 ctrl_pkt_v2; if (!params) return -EIO; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); return -EINVAL; + } if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", @@ -1278,9 +1478,6 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, return -EINVAL; } - if (params->peripheral != peripheral) - return -EINVAL; - switch (params->mode) { case DIAG_BUFFERING_MODE_STREAMING: case DIAG_BUFFERING_MODE_THRESHOLD: @@ -1292,36 +1489,67 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, return -EINVAL; } - ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE; - /* Control packet length is size of version, stream_id and tx_mode */ - ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t)); - ctrl_pkt.version = 1; - ctrl_pkt.stream_id = 1; - ctrl_pkt.tx_mode = params->mode; + if (diag_id && + driver->feature[peripheral].pd_buffering) { - err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, sizeof(ctrl_pkt)); - if (err && err != -ENODEV) { - pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n", - peripheral, err); - goto fail; + ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE; + /* + * Control packet length is size of version, diag_id, + * stream_id and tx_mode + */ + ctrl_pkt_v2.len = sizeof(uint32_t) + (3 * sizeof(uint8_t)); + ctrl_pkt_v2.version = 2; + ctrl_pkt_v2.diag_id = diag_id; + ctrl_pkt_v2.stream_id = 1; + ctrl_pkt_v2.tx_mode = params->mode; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2, + sizeof(ctrl_pkt_v2)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + goto fail; + } + } else { + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE; + /* + * Control packet length is size of version, + * stream_id and tx_mode + */ + ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t)); + ctrl_pkt.version = 1; + ctrl_pkt.stream_id = 1; + ctrl_pkt.tx_mode = params->mode; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, + sizeof(ctrl_pkt)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n", + peripheral, err); + goto fail; + } } - driver->buffering_mode[peripheral].mode = params->mode; + driver->buffering_mode[params->peripheral].mode = params->mode; fail: return err; } int diag_send_buffering_wm_values(uint8_t peripheral, - struct diag_buffering_mode_t *params) + uint8_t diag_id, struct diag_buffering_mode_t *params) { int err = 0; struct diag_ctrl_set_wq_val ctrl_pkt; + struct diag_ctrl_set_wq_val_v2 ctrl_pkt_v2; if (!params) return -EIO; - if (peripheral >= NUM_PERIPHERALS) + if (peripheral >= NUM_PERIPHERALS) { + pr_err("diag: In %s, invalid peripheral %d\n", __func__, + peripheral); return -EINVAL; + } if (!driver->feature[peripheral].peripheral_buffering) { pr_debug("diag: In %s, peripheral %d doesn't support buffering\n", @@ -1336,9 +1564,6 @@ int diag_send_buffering_wm_values(uint8_t peripheral, return -ENODEV; } - if (params->peripheral != peripheral) - return -EINVAL; - switch (params->mode) { case DIAG_BUFFERING_MODE_STREAMING: case DIAG_BUFFERING_MODE_THRESHOLD: @@ -1350,21 +1575,45 @@ int diag_send_buffering_wm_values(uint8_t peripheral, return -EINVAL; } - ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL; - /* Control packet length is size of version, stream_id and wmq values */ - ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t)); - ctrl_pkt.version = 1; - ctrl_pkt.stream_id = 1; - ctrl_pkt.high_wm_val = params->high_wm_val; - ctrl_pkt.low_wm_val = params->low_wm_val; - - err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, - sizeof(ctrl_pkt)); - if (err && err != -ENODEV) { - pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n", - peripheral, err); + if (diag_id && + driver->feature[peripheral].pd_buffering) { + ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL; + /* + * Control packet length is size of version, diag_id, + * stream_id and wmq values + */ + ctrl_pkt_v2.len = sizeof(uint32_t) + (4 * sizeof(uint8_t)); + ctrl_pkt_v2.version = 2; + ctrl_pkt_v2.diag_id = diag_id; + ctrl_pkt_v2.stream_id = 1; + ctrl_pkt_v2.high_wm_val = params->high_wm_val; + ctrl_pkt_v2.low_wm_val = params->low_wm_val; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2, + sizeof(ctrl_pkt_v2)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n", + peripheral, err); + } + } else { + ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL; + /* + * Control packet length is size of version, + * stream_id and wmq values + */ + ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t)); + ctrl_pkt.version = 1; + ctrl_pkt.stream_id = 1; + ctrl_pkt.high_wm_val = params->high_wm_val; + ctrl_pkt.low_wm_val = params->low_wm_val; + + err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, + sizeof(ctrl_pkt)); + if (err && err != -ENODEV) { + pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n", + peripheral, err); + } } - return err; } diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h index 7823040f31190070882078fea7f780d076a8a8ce..4a0ee11be13af29c0408be77f0295d01c65a1214 100644 --- a/drivers/char/diag/diagfwd_cntl.h +++ b/drivers/char/diag/diagfwd_cntl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, 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 @@ -68,6 +68,8 @@ #define F_DIAG_SOCKETS_ENABLED 13 #define F_DIAG_DCI_EXTENDED_HEADER_SUPPORT 14 #define F_DIAG_DIAGID_SUPPORT 15 +#define F_DIAG_PKT_HEADER_UNTAG 16 +#define F_DIAG_PD_BUFFERING 17 #define ENABLE_SEPARATE_CMDRSP 1 #define DISABLE_SEPARATE_CMDRSP 0 @@ -75,14 +77,18 @@ #define DISABLE_STM 0 #define ENABLE_STM 1 #define STATUS_STM 2 - +#define STM_AUTO_QUERY 3 #define UPDATE_PERIPHERAL_STM_STATE 1 #define CLEAR_PERIPHERAL_STM_STATE 2 #define ENABLE_APPS_HDLC_ENCODING 1 #define DISABLE_APPS_HDLC_ENCODING 0 -#define DIAG_MODE_PKT_LEN 36 +#define ENABLE_PKT_HEADER_UNTAGGING 1 +#define DISABLE_PKT_HEADER_UNTAGGING 0 + +#define DIAG_MODE_PKT_LEN 36 +#define DIAG_MODE_PKT_LEN_V2 37 struct diag_ctrl_pkt_header_t { uint32_t pkt_id; @@ -168,6 +174,21 @@ struct diag_ctrl_msg_diagmode { uint32_t event_stale_timer_val; } __packed; +struct diag_ctrl_msg_diagmode_v2 { + uint32_t ctrl_pkt_id; + uint32_t ctrl_pkt_data_len; + uint32_t version; + uint32_t sleep_vote; + uint32_t real_time; + uint32_t use_nrt_values; + uint32_t commit_threshold; + uint32_t sleep_threshold; + uint32_t sleep_time; + uint32_t drain_timer_val; + uint32_t event_stale_timer_val; + uint8_t diag_id; +} __packed; + struct diag_ctrl_msg_stm { uint32_t ctrl_pkt_id; uint32_t ctrl_pkt_data_len; @@ -246,6 +267,15 @@ struct diag_ctrl_peripheral_tx_mode { uint8_t tx_mode; } __packed; +struct diag_ctrl_peripheral_tx_mode_v2 { + uint32_t pkt_id; + uint32_t len; + uint32_t version; + uint8_t diag_id; + uint8_t stream_id; + uint8_t tx_mode; +} __packed; + struct diag_ctrl_drain_immediate { uint32_t pkt_id; uint32_t len; @@ -253,6 +283,14 @@ struct diag_ctrl_drain_immediate { uint8_t stream_id; } __packed; +struct diag_ctrl_drain_immediate_v2 { + uint32_t pkt_id; + uint32_t len; + uint32_t version; + uint8_t diag_id; + uint8_t stream_id; +} __packed; + struct diag_ctrl_set_wq_val { uint32_t pkt_id; uint32_t len; @@ -262,6 +300,16 @@ struct diag_ctrl_set_wq_val { uint8_t low_wm_val; } __packed; +struct diag_ctrl_set_wq_val_v2 { + uint32_t pkt_id; + uint32_t len; + uint32_t version; + uint8_t diag_id; + uint8_t stream_id; + uint8_t high_wm_val; + uint8_t low_wm_val; +} __packed; + struct diag_ctrl_diagid { uint32_t pkt_id; uint32_t len; @@ -271,7 +319,8 @@ struct diag_ctrl_diagid { } __packed; int diagfwd_cntl_init(void); -int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name); +int diag_add_diag_id_to_list(uint8_t diag_id, + char *process_name, uint8_t pd_val, uint8_t peripheral); void diagfwd_cntl_channel_init(void); void diagfwd_cntl_exit(void); void diag_cntl_channel_open(struct diagfwd_info *p_info); @@ -279,14 +328,16 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info); void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf, int len); int diag_send_real_time_update(uint8_t peripheral, int real_time); +void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral); int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params); void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index); void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index); void diag_real_time_work_fn(struct work_struct *work); int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data); -int diag_send_peripheral_drain_immediate(uint8_t peripheral); +int diag_send_peripheral_drain_immediate(uint8_t pd, + uint8_t diag_id, int peripheral); int diag_send_buffering_tx_mode_pkt(uint8_t peripheral, - struct diag_buffering_mode_t *params); + uint8_t diag_id, struct diag_buffering_mode_t *params); int diag_send_buffering_wm_values(uint8_t peripheral, - struct diag_buffering_mode_t *params); + uint8_t diag_id, struct diag_buffering_mode_t *params); #endif diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index ebc37f61c31bd4c0d40142bdadb25b95a1ca921f..e9683e092cff6bcec7ab4ede7a286a9bcac9062a 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, 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 @@ -361,13 +361,44 @@ static void diag_glink_read_work_fn(struct work_struct *work) diagfwd_channel_read(glink_info->fwd_ctxt); } +struct diag_glink_read_work { + struct diag_glink_info *glink_info; + const void *ptr_read_done; + const void *ptr_rx_done; + size_t ptr_read_size; + struct work_struct work; +}; + +static void diag_glink_notify_rx_work_fn(struct work_struct *work) +{ + struct diag_glink_read_work *read_work = container_of(work, + struct diag_glink_read_work, work); + struct diag_glink_info *glink_info = read_work->glink_info; + + if (!glink_info || !glink_info->hdl) { + kfree(read_work); + return; + } + + diagfwd_channel_read_done(glink_info->fwd_ctxt, + (unsigned char *)(read_work->ptr_read_done), + read_work->ptr_read_size); + + glink_rx_done(glink_info->hdl, read_work->ptr_rx_done, false); + + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Rx done for packet %pK of len: %d periph: %d ch: %d\n", + read_work->ptr_rx_done, (int)read_work->ptr_read_size, + glink_info->peripheral, glink_info->type); + kfree(read_work); +} static void diag_glink_notify_rx(void *hdl, const void *priv, const void *pkt_priv, const void *ptr, size_t size) { struct diag_glink_info *glink_info = (struct diag_glink_info *)priv; - int err = 0; + struct diag_glink_read_work *read_work; if (!glink_info || !glink_info->hdl || !ptr || !pkt_priv || !hdl) return; @@ -379,12 +410,25 @@ static void diag_glink_notify_rx(void *hdl, const void *priv, "diag: received a packet %pK of len:%d from periph:%d ch:%d\n", ptr, (int)size, glink_info->peripheral, glink_info->type); + read_work = kmalloc(sizeof(*read_work), GFP_ATOMIC); + if (!read_work) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Could not allocate read_work\n"); + glink_rx_done(glink_info->hdl, ptr, true); + return; + } + memcpy((void *)pkt_priv, ptr, size); - err = diagfwd_channel_read_done(glink_info->fwd_ctxt, - (unsigned char *)pkt_priv, size); - glink_rx_done(glink_info->hdl, ptr, false); + + read_work->glink_info = glink_info; + read_work->ptr_read_done = pkt_priv; + read_work->ptr_rx_done = ptr; + read_work->ptr_read_size = size; + INIT_WORK(&read_work->work, diag_glink_notify_rx_work_fn); + queue_work(glink_info->wq, &read_work->work); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: Rx done for packet %pK of len:%d periph:%d ch:%d\n", + "diag: Rx queued for packet %pK of len: %d periph: %d ch: %d\n", ptr, (int)size, glink_info->peripheral, glink_info->type); } @@ -462,6 +506,45 @@ static int diag_glink_write(void *ctxt, unsigned char *buf, int len) return err; } + +static void diag_glink_connect_work_fn(struct work_struct *work) +{ + struct diag_glink_info *glink_info = container_of(work, + struct diag_glink_info, + connect_work); + if (!glink_info || !glink_info->hdl) + return; + atomic_set(&glink_info->opened, 1); + diagfwd_channel_open(glink_info->fwd_ctxt); + diagfwd_late_open(glink_info->fwd_ctxt); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink channel open: p: %d t: %d\n", + glink_info->peripheral, glink_info->type); +} + +static void diag_glink_remote_disconnect_work_fn(struct work_struct *work) +{ + struct diag_glink_info *glink_info = container_of(work, + struct diag_glink_info, + remote_disconnect_work); + if (!glink_info || !glink_info->hdl) + return; + atomic_set(&glink_info->opened, 0); + diagfwd_channel_close(glink_info->fwd_ctxt); + atomic_set(&glink_info->tx_intent_ready, 0); +} + +static void diag_glink_late_init_work_fn(struct work_struct *work) +{ + struct diag_glink_info *glink_info = container_of(work, + struct diag_glink_info, + late_init_work); + if (!glink_info || !glink_info->hdl) + return; + diagfwd_channel_open(glink_info->fwd_ctxt); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "glink late init p: %d t: %d\n", + glink_info->peripheral, glink_info->type); +} + static void diag_glink_transport_notify_state(void *handle, const void *priv, unsigned int event) { @@ -475,9 +558,7 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv, DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s received channel connect for periph:%d\n", glink_info->name, glink_info->peripheral); - atomic_set(&glink_info->opened, 1); - diagfwd_channel_open(glink_info->fwd_ctxt); - diagfwd_late_open(glink_info->fwd_ctxt); + queue_work(glink_info->wq, &glink_info->connect_work); break; case GLINK_LOCAL_DISCONNECTED: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -489,9 +570,7 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv, DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s received channel remote disconnect for periph:%d\n", glink_info->name, glink_info->peripheral); - atomic_set(&glink_info->opened, 0); - diagfwd_channel_close(glink_info->fwd_ctxt); - atomic_set(&glink_info->tx_intent_ready, 0); + queue_work(glink_info->wq, &glink_info->remote_disconnect_work); break; default: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -596,7 +675,7 @@ static void glink_late_init(struct diag_glink_info *glink_info) glink_info->inited = 1; if (atomic_read(&glink_info->opened)) - diagfwd_channel_open(glink_info->fwd_ctxt); + queue_work(glink_info->wq, &(glink_info->late_init_work)); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", glink_info->name); @@ -641,6 +720,10 @@ static void __diag_glink_init(struct diag_glink_info *glink_info) INIT_WORK(&(glink_info->open_work), diag_glink_open_work_fn); INIT_WORK(&(glink_info->close_work), diag_glink_close_work_fn); INIT_WORK(&(glink_info->read_work), diag_glink_read_work_fn); + INIT_WORK(&(glink_info->connect_work), diag_glink_connect_work_fn); + INIT_WORK(&(glink_info->remote_disconnect_work), + diag_glink_remote_disconnect_work_fn); + INIT_WORK(&(glink_info->late_init_work), diag_glink_late_init_work_fn); link_info.glink_link_state_notif_cb = diag_glink_notify_cb; link_info.transport = NULL; link_info.edge = glink_info->edge; @@ -681,6 +764,8 @@ int diag_glink_init(void) struct diag_glink_info *glink_info = NULL; for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) { + if (peripheral != PERIPHERAL_WDSP) + continue; glink_info = &glink_cntl[peripheral]; __diag_glink_init(glink_info); diagfwd_cntl_register(TRANSPORT_GLINK, glink_info->peripheral, @@ -719,6 +804,8 @@ void diag_glink_early_exit(void) int peripheral = 0; for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) { + if (peripheral != PERIPHERAL_WDSP) + continue; __diag_glink_exit(&glink_cntl[peripheral]); glink_unregister_link_state_cb(&glink_cntl[peripheral].hdl); } @@ -729,6 +816,8 @@ void diag_glink_exit(void) int peripheral = 0; for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) { + if (peripheral != PERIPHERAL_WDSP) + continue; __diag_glink_exit(&glink_data[peripheral]); __diag_glink_exit(&glink_cmd[peripheral]); __diag_glink_exit(&glink_dci[peripheral]); diff --git a/drivers/char/diag/diagfwd_glink.h b/drivers/char/diag/diagfwd_glink.h index bad4629b5ab82a5b9e989b0d486a32d57b873a04..6cad44522ab6d2afd8bea76804e0f067cbf52dd4 100644 --- a/drivers/char/diag/diagfwd_glink.h +++ b/drivers/char/diag/diagfwd_glink.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,6 +35,9 @@ struct diag_glink_info { struct work_struct open_work; struct work_struct close_work; struct work_struct read_work; + struct work_struct connect_work; + struct work_struct remote_disconnect_work; + struct work_struct late_init_work; struct diagfwd_info *fwd_ctxt; }; diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index f27f358ee62ac12d5e72aed84a219bdc7cfdb35d..f8c3fdeb505c7759d0c5619f17eb922bb8162ffc 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 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 @@ -552,6 +552,8 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) struct mhi_result *result = NULL; struct diag_mhi_ch_t *ch = NULL; void *buf = NULL; + struct diag_mhi_info *mhi_info = NULL; + unsigned long flags; if (!cb_info) return; @@ -603,13 +605,6 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].open_work)); break; - case MHI_CB_MHI_DISABLED: - DIAG_LOG(DIAG_DEBUG_BRIDGE, - "received mhi disabled notifiation port: %d ch: %d\n", - index, ch->type); - atomic_set(&(ch->opened), 0); - __mhi_close(&diag_mhi[index], CHANNELS_CLOSED); - break; case MHI_CB_XFER: /* * If the channel is a read channel, this is a read @@ -636,6 +631,24 @@ static void mhi_notifier(struct mhi_cb_info *cb_info) result->bytes_xferd, diag_mhi[index].id); break; + case MHI_CB_MHI_DISABLED: + case MHI_CB_SYS_ERROR: + case MHI_CB_MHI_SHUTDOWN: + DIAG_LOG(DIAG_DEBUG_BRIDGE, + "received mhi link down cb: %d port: %d ch: %d\n", + cb_info->cb_reason, index, ch->type); + mhi_info = &diag_mhi[index]; + if (!mhi_info->enabled) + return; + spin_lock_irqsave(&mhi_info->lock, flags); + mhi_info->enabled = 0; + spin_unlock_irqrestore(&mhi_info->lock, flags); + atomic_set(&(mhi_info->read_ch.opened), 0); + atomic_set(&(mhi_info->write_ch.opened), 0); + flush_workqueue(mhi_info->mhi_wq); + mhi_buf_tbl_clear(mhi_info); + diag_remote_dev_close(mhi_info->dev_id); + break; default: pr_err("diag: In %s, invalid cb reason 0x%x\n", __func__, cb_info->cb_reason); diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 5a8ef044ff598dfd00acc82897ad18559efff0dd..c7bd2205ae910207c817925aa656758c1ba2b035 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -30,6 +30,7 @@ #include "diag_mux.h" #include "diag_ipc_logging.h" #include "diagfwd_glink.h" +#include "diag_memorydevice.h" struct data_header { uint8_t control_char; @@ -45,6 +46,8 @@ static void diagfwd_cntl_open(struct diagfwd_info *fwd_info); static void diagfwd_cntl_close(struct diagfwd_info *fwd_info); static void diagfwd_dci_open(struct diagfwd_info *fwd_info); static void diagfwd_dci_close(struct diagfwd_info *fwd_info); +static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, + unsigned char *buf, int len); static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, unsigned char *buf, int len); static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info, @@ -58,7 +61,7 @@ struct diagfwd_info peripheral_info[NUM_TYPES][NUM_PERIPHERALS]; static struct diag_channel_ops data_ch_ops = { .open = NULL, .close = NULL, - .read_done = diagfwd_data_read_done + .read_done = diagfwd_data_read_untag_done }; static struct diag_channel_ops cntl_ch_ops = { @@ -185,8 +188,10 @@ static int diag_add_hdlc_encoding(unsigned char *dest_buf, int *dest_len, static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) { + int i, ctx = 0; uint32_t max_size = 0; unsigned char *temp_buf = NULL; + struct diag_md_info *ch = NULL; if (!buf || len == 0) return -EINVAL; @@ -200,11 +205,32 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) } if (buf->len < max_size) { + if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || + driver->logging_mode == DIAG_MULTI_MODE) { + ch = &diag_md[DIAG_LOCAL_PROC]; + for (i = 0; ch != NULL && + i < ch->num_tbl_entries; i++) { + if (ch->tbl[i].buf == buf->data) { + ctx = ch->tbl[i].ctx; + ch->tbl[i].buf = NULL; + ch->tbl[i].len = 0; + ch->tbl[i].ctx = 0; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Flushed mdlog table entries before reallocating data buffer, p:%d, t:%d\n", + GET_BUF_PERIPHERAL(ctx), + GET_BUF_TYPE(ctx)); + break; + } + } + } temp_buf = krealloc(buf->data, max_size + APF_DIAG_PADDING, GFP_KERNEL); if (!temp_buf) return -ENOMEM; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Reallocated data buffer: %pK with size: %d\n", + temp_buf, max_size); buf->data = temp_buf; buf->len = max_size; } @@ -213,6 +239,371 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) return buf->len; } +/* + * diag_md_get_peripheral(int ctxt) + * + * Context(ctxt) contains peripheral, channel type, buffer num and diag_id + * The function decodes the ctxt, checks for the active user pd session + * using diag_id and returns peripheral if not active or the PD if active. + * + */ +int diag_md_get_peripheral(int ctxt) +{ + uint8_t diag_id = 0, i = 0, pd = 0; + int type = 0, peripheral = -EINVAL; + int index = 0; + struct diagfwd_info *fwd_info = NULL; + + peripheral = GET_BUF_PERIPHERAL(ctxt); + + /* Check for peripheral value within bounds + * of peripherals and UPD combined. + */ + if (peripheral < 0 || peripheral > NUM_MD_SESSIONS) + return -EINVAL; + + if (peripheral == APPS_DATA) + return peripheral; + + /* With peripheral value bound checked + * return user pd value. + */ + if (peripheral > NUM_PERIPHERALS) + return peripheral; + + type = GET_BUF_TYPE(ctxt); + if (type < 0 || type >= NUM_TYPES) + return -EINVAL; + + fwd_info = &peripheral_info[type][peripheral]; + if (!fwd_info) + return -EINVAL; + + diag_id = GET_PD_CTXT(ctxt); + + if (driver->num_pd_session && + driver->feature[peripheral].untag_header) { + if (diag_id == fwd_info->root_diag_id.diagid_val) { + if (peripheral != fwd_info->root_diag_id.pd) + peripheral = -EINVAL; + } else { + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (diag_id == + fwd_info->upd_diag_id[i].diagid_val) { + pd = fwd_info->upd_diag_id[i].pd; + index = pd - UPD_WLAN; + if ((index >= 0 && index < NUM_UPD) && + driver->pd_logging_mode[index]) { + peripheral = pd; + break; + } + } + } + } + } + return peripheral; +} + +static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, + struct diagfwd_buf_t *buf, int len) +{ + int err = 0; + int write_len = 0, peripheral = 0; + unsigned char *write_buf = NULL; + struct diag_md_session_t *session_info = NULL; + uint8_t hdlc_disabled = 0; + + if (!fwd_info || !buf || len <= 0) { + diag_ws_release(); + return; + } + + switch (fwd_info->type) { + case TYPE_DATA: + case TYPE_CMD: + break; + default: + pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n", + __func__, fwd_info->type, + fwd_info->peripheral); + diag_ws_release(); + return; + } + + mutex_lock(&driver->hdlc_disable_mutex); + mutex_lock(&fwd_info->data_mutex); + + peripheral = + diag_md_get_peripheral(buf->ctxt); + if (peripheral < 0) { + pr_err("diag:%s:%d invalid peripheral = %d\n", + __func__, __LINE__, peripheral); + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); + diag_ws_release(); + return; + } + + session_info = + diag_md_session_get_peripheral(peripheral); + if (session_info) + hdlc_disabled = session_info->hdlc_disabled; + else + hdlc_disabled = driver->hdlc_disabled; + + if (hdlc_disabled) { + /* The data is raw and and on APPS side HDLC is disabled */ + if (!buf) { + pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n", + __func__, buf, fwd_info->peripheral, + fwd_info->type); + goto end; + } + if (len > PERIPHERAL_BUF_SZ) { + pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n", + __func__, len, fwd_info->peripheral, + fwd_info->type); + goto end; + } + write_len = len; + if (write_len <= 0) + goto end; + write_buf = buf->data_raw; + } else { + if (!buf) { + pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n", + __func__, buf, fwd_info->peripheral, + fwd_info->type); + goto end; + } + + write_len = check_bufsize_for_encoding(buf, len); + if (write_len <= 0) { + pr_err("diag: error in checking buf for encoding\n"); + goto end; + } + write_buf = buf->data; + err = diag_add_hdlc_encoding(write_buf, &write_len, + buf->data_raw, len); + if (err) { + pr_err("diag: error in adding hdlc encoding\n"); + goto end; + } + } + + if (write_len > 0) { + err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len, + buf->ctxt); + if (err) { + pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n", + __func__, err); + goto end; + } + } + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); + diagfwd_queue_read(fwd_info); + return; + +end: + diag_ws_release(); + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); + if (buf) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Marking buffer as free p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, + GET_BUF_NUM(buf->ctxt)); + diagfwd_write_done(fwd_info->peripheral, fwd_info->type, + GET_BUF_NUM(buf->ctxt)); + } + diagfwd_queue_read(fwd_info); +} + +/* + * diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, + * unsigned char *buf, int len) + * + * Data received from the peripheral can contain data from core and user PD + * The function segregates the data depending on the diag_id in the header + * of the packet chunk and copies to PD specific buffers. + * Sets the context for the buffers using diag_id and process it later for + * splitting the stream based on active PD logging. + * + */ + +static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info, + unsigned char *buf, int len) +{ + int i = 0; + int len_cpd = 0; + int ctxt_cpd = 0; + int len_upd[MAX_PERIPHERAL_UPD] = {0}; + int ctxt_upd[MAX_PERIPHERAL_UPD] = {0}; + int packet_len = 0, processed = 0; + unsigned char *temp_buf_main = NULL; + unsigned char *temp_buf_cpd = NULL; + unsigned char *temp_buf_upd[MAX_PERIPHERAL_UPD] = {NULL}; + struct diagfwd_buf_t *temp_fwdinfo_cpd = NULL; + struct diagfwd_buf_t *temp_fwdinfo_upd = NULL; + int flag_buf_1 = 0, flag_buf_2 = 0; + uint8_t peripheral; + + if (!fwd_info || !buf || len <= 0) { + diag_ws_release(); + return; + } + + switch (fwd_info->type) { + case TYPE_DATA: + case TYPE_CMD: + break; + default: + pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n", + __func__, fwd_info->type, + fwd_info->peripheral); + diag_ws_release(); + return; + } + peripheral = fwd_info->peripheral; + if (peripheral >= NUM_PERIPHERALS) + return; + + if (driver->feature[peripheral].encode_hdlc && + driver->feature[peripheral].untag_header && + driver->peripheral_untag[peripheral]) { + temp_buf_cpd = buf; + temp_buf_main = buf; + if (fwd_info->buf_1 && + fwd_info->buf_1->data_raw == buf) { + flag_buf_1 = 1; + temp_fwdinfo_cpd = fwd_info->buf_1; + if (fwd_info->type == TYPE_DATA) { + for (i = 0; (i <= (fwd_info->num_pd - 2)) && + fwd_info->buf_upd[i][0]; i++) + temp_buf_upd[i] = + fwd_info->buf_upd[i][0]->data_raw; + } + } else if (fwd_info->buf_2 && + fwd_info->buf_2->data_raw == buf) { + flag_buf_2 = 1; + temp_fwdinfo_cpd = fwd_info->buf_2; + if (fwd_info->type == TYPE_DATA) { + for (i = 0; (i <= (fwd_info->num_pd - 2)) && + fwd_info->buf_upd[i][1]; i++) + temp_buf_upd[i] = + fwd_info->buf_upd[i][1]->data_raw; + } + } else { + pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n", + __func__, buf, peripheral, + fwd_info->type); + goto end; + } + + while (processed < len) { + pr_debug("diag_fr:untagged packet buf contents: %02x %02x %02x %02x\n", + *temp_buf_main, *(temp_buf_main+1), + *(temp_buf_main+2), *(temp_buf_main+3)); + packet_len = + *(uint16_t *) (temp_buf_main + 2); + if (packet_len > PERIPHERAL_BUF_SZ) + goto end; + if ((*temp_buf_main) == + fwd_info->root_diag_id.diagid_val) { + ctxt_cpd = + fwd_info->root_diag_id.diagid_val; + len_cpd += packet_len; + if (temp_buf_cpd) { + memcpy(temp_buf_cpd, + (temp_buf_main + 4), packet_len); + temp_buf_cpd += packet_len; + } + } else { + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if ((*temp_buf_main) == + fwd_info->upd_diag_id[i].diagid_val) { + ctxt_upd[i] = + fwd_info->upd_diag_id[i].diagid_val; + if (temp_buf_upd[i]) { + memcpy(temp_buf_upd[i], + (temp_buf_main + 4), + packet_len); + temp_buf_upd[i] += packet_len; + } + len_upd[i] += packet_len; + } + } + } + len = len - 4; + temp_buf_main += (packet_len + 4); + processed += packet_len; + } + + if (flag_buf_1) { + fwd_info->cpd_len_1 = len_cpd; + for (i = 0; i <= (fwd_info->num_pd - 2); i++) + if (fwd_info->type == TYPE_DATA) + fwd_info->upd_len[i][0] = len_upd[i]; + } else if (flag_buf_2) { + fwd_info->cpd_len_2 = len_cpd; + for (i = 0; i <= (fwd_info->num_pd - 2); i++) + if (fwd_info->type == TYPE_DATA) + fwd_info->upd_len[i][1] = len_upd[i]; + } + + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (fwd_info->type == TYPE_DATA && len_upd[i]) { + if (flag_buf_1) + temp_fwdinfo_upd = + fwd_info->buf_upd[i][0]; + else + temp_fwdinfo_upd = + fwd_info->buf_upd[i][1]; + if (!temp_fwdinfo_upd) + break; + temp_fwdinfo_upd->ctxt &= 0x00FFFFFF; + temp_fwdinfo_upd->ctxt |= + (SET_PD_CTXT(ctxt_upd[i])); + atomic_set(&temp_fwdinfo_upd->in_busy, 1); + diagfwd_data_process_done(fwd_info, + temp_fwdinfo_upd, len_upd[i]); + } else { + if (flag_buf_1) + fwd_info->upd_len[i][0] = 0; + if (flag_buf_2) + fwd_info->upd_len[i][1] = 0; + } + } + + if (len_cpd) { + temp_fwdinfo_cpd->ctxt &= 0x00FFFFFF; + temp_fwdinfo_cpd->ctxt |= (SET_PD_CTXT(ctxt_cpd)); + diagfwd_data_process_done(fwd_info, + temp_fwdinfo_cpd, len_cpd); + } else { + if (flag_buf_1) + fwd_info->cpd_len_1 = 0; + if (flag_buf_2) + fwd_info->cpd_len_2 = 0; + } + } else { + diagfwd_data_read_done(fwd_info, buf, len); + } + return; +end: + diag_ws_release(); + if (temp_fwdinfo_cpd) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Marking buffer as free p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, + GET_BUF_NUM(temp_fwdinfo_cpd->ctxt)); + diagfwd_write_done(fwd_info->peripheral, fwd_info->type, + GET_BUF_NUM(temp_fwdinfo_cpd->ctxt)); + } + diagfwd_queue_read(fwd_info); +} + static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, unsigned char *buf, int len) { @@ -327,6 +718,10 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, mutex_unlock(&fwd_info->data_mutex); mutex_unlock(&driver->hdlc_disable_mutex); if (temp_buf) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Marking buffer as free p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, + GET_BUF_NUM(temp_buf->ctxt)); diagfwd_write_done(fwd_info->peripheral, fwd_info->type, GET_BUF_NUM(temp_buf->ctxt)); } @@ -406,6 +801,16 @@ static void diagfwd_reset_buffers(struct diagfwd_info *fwd_info, else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf) atomic_set(&fwd_info->buf_2->in_busy, 0); } + if (fwd_info->buf_1 && !atomic_read(&(fwd_info->buf_1->in_busy))) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 1 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } + if (fwd_info->buf_2 && !atomic_read(&(fwd_info->buf_2->in_busy))) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 2 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } } int diagfwd_peripheral_init(void) @@ -413,6 +818,7 @@ int diagfwd_peripheral_init(void) uint8_t peripheral; uint8_t transport; uint8_t type; + int i = 0; struct diagfwd_info *fwd_info = NULL; for (transport = 0; transport < NUM_TRANSPORT; transport++) { @@ -436,9 +842,21 @@ int diagfwd_peripheral_init(void) fwd_info->inited = 1; fwd_info->read_bytes = 0; fwd_info->write_bytes = 0; + fwd_info->cpd_len_1 = 0; + fwd_info->cpd_len_2 = 0; + fwd_info->num_pd = 0; + fwd_info->root_diag_id.diagid_val = 0; mutex_init(&fwd_info->buf_mutex); mutex_init(&fwd_info->data_mutex); spin_lock_init(&fwd_info->write_buf_lock); + + for (i = 0; i < MAX_PERIPHERAL_UPD; i++) { + fwd_info->upd_diag_id[i].diagid_val = 0; + fwd_info->upd_len[i][0] = 0; + fwd_info->upd_len[i][1] = 0; + fwd_info->buf_upd[i][0] = NULL; + fwd_info->buf_upd[i][1] = NULL; + } } } @@ -452,9 +870,21 @@ int diagfwd_peripheral_init(void) fwd_info->ch_open = 0; fwd_info->read_bytes = 0; fwd_info->write_bytes = 0; + fwd_info->num_pd = 0; + fwd_info->cpd_len_1 = 0; + fwd_info->cpd_len_2 = 0; + fwd_info->root_diag_id.diagid_val = 0; spin_lock_init(&fwd_info->write_buf_lock); mutex_init(&fwd_info->buf_mutex); mutex_init(&fwd_info->data_mutex); + + for (i = 0; i < MAX_PERIPHERAL_UPD; i++) { + fwd_info->upd_diag_id[i].diagid_val = 0; + fwd_info->upd_len[i][0] = 0; + fwd_info->upd_len[i][1] = 0; + fwd_info->buf_upd[i][0] = NULL; + fwd_info->buf_upd[i][1] = NULL; + } /* * This state shouldn't be set for Control channels * during initialization. This is set when the feature @@ -487,6 +917,7 @@ void diagfwd_peripheral_exit(void) uint8_t peripheral; uint8_t type; struct diagfwd_info *fwd_info = NULL; + int transport = 0; diag_socket_exit(); @@ -508,7 +939,10 @@ void diagfwd_peripheral_exit(void) driver->diagfwd_dci_cmd[peripheral] = NULL; } - kfree(early_init_info); + for (transport = 0; transport < NUM_TRANSPORT; transport++) { + kfree(early_init_info[transport]); + early_init_info[transport] = NULL; + } } int diagfwd_cntl_register(uint8_t transport, uint8_t peripheral, void *ctxt, @@ -721,6 +1155,16 @@ int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len) if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) return -ENODEV; + if (type == TYPE_CMD) { + if (driver->feature[peripheral].diag_id_support) + if (!fwd_info->root_diag_id.diagid_val || + (!driver->diag_id_sent[peripheral])) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: diag_id is not assigned yet\n"); + return 0; + } + } + if (!(fwd_info->p_ops && fwd_info->p_ops->write && fwd_info->ctxt)) return -EIO; @@ -764,10 +1208,28 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info) if (!fwd_info->inited) return; - if (fwd_info->buf_1) - atomic_set(&fwd_info->buf_1->in_busy, 0); - if (fwd_info->buf_2) - atomic_set(&fwd_info->buf_2->in_busy, 0); + /* + * Logging mode here is reflecting previous mode + * status and will be updated to new mode later. + * + * Keeping the buffers busy for Memory Device Mode. + */ + + if ((driver->logging_mode != DIAG_USB_MODE) || + driver->usb_connected) { + if (fwd_info->buf_1) { + atomic_set(&fwd_info->buf_1->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 1 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } + if (fwd_info->buf_2) { + atomic_set(&fwd_info->buf_2->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 2 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } + } if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); @@ -848,10 +1310,17 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) __func__, fwd_info->peripheral, fwd_info->type); return 0; } - + mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 1; diagfwd_buffers_init(fwd_info); - diagfwd_write_buffers_init(fwd_info); + + /* + * Initialize buffers for glink supported + * peripherals only. + */ + if (fwd_info->transport == TRANSPORT_GLINK) + diagfwd_write_buffers_init(fwd_info); + if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open) fwd_info->c_ops->open(fwd_info); for (i = 0; i < NUM_WRITE_BUFFERS; i++) { @@ -866,7 +1335,7 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); } - + mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); return 0; } @@ -877,14 +1346,26 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) if (!fwd_info) return -EIO; + if (fwd_info->type == TYPE_CNTL) + flush_workqueue(driver->cntl_wq); + + mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 0; if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close) fwd_info->c_ops->close(fwd_info); - if (fwd_info->buf_1 && fwd_info->buf_1->data) + if (fwd_info->buf_1 && fwd_info->buf_1->data) { atomic_set(&fwd_info->buf_1->in_busy, 0); - if (fwd_info->buf_2 && fwd_info->buf_2->data) + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 1 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } + if (fwd_info->buf_2 && fwd_info->buf_2->data) { atomic_set(&fwd_info->buf_2->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 2 for core PD is marked free, p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); + } for (i = 0; i < NUM_WRITE_BUFFERS; i++) { if (fwd_info->buf_ptr[i]) @@ -892,7 +1373,7 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered closed\n", fwd_info->peripheral, fwd_info->type); - + mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); return 0; } @@ -910,6 +1391,9 @@ int diagfwd_channel_read_done(struct diagfwd_info *fwd_info, * in_busy flags. No need to queue read in this case. */ if (len == 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Read Length is 0, resetting the diag buffers p: %d, t: %d\n", + fwd_info->peripheral, fwd_info->type); diagfwd_reset_buffers(fwd_info, buf); diag_ws_release(); return 0; @@ -922,20 +1406,138 @@ int diagfwd_channel_read_done(struct diagfwd_info *fwd_info, return 0; } -void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt) +void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num) { + int i = 0, upd_valid_len = 0; struct diagfwd_info *fwd_info = NULL; if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES) return; fwd_info = &peripheral_info[type][peripheral]; - if (ctxt == 1 && fwd_info->buf_1) - atomic_set(&fwd_info->buf_1->in_busy, 0); - else if (ctxt == 2 && fwd_info->buf_2) - atomic_set(&fwd_info->buf_2->in_busy, 0); - else - pr_err("diag: In %s, invalid ctxt %d\n", __func__, ctxt); + if (!fwd_info) + return; + + if (buf_num == 1 && fwd_info->buf_1) { + /* + * Core PD buffer data is processed and + * length in the buffer is marked zero. + * + * Check if the user PD buffer contains any + * data before freeing core PD buffer. + */ + fwd_info->cpd_len_1 = 0; + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (fwd_info->upd_len[i][0]) { + upd_valid_len = 1; + break; + } + } + /* + * Do not free the core pd buffer if valid data + * is present in any user PD buffer. + */ + if (!upd_valid_len) { + atomic_set(&fwd_info->buf_1->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, buf_num); + } + } else if (buf_num == 2 && fwd_info->buf_2) { + /* + * Core PD buffer data is processed and + * length in the buffer is marked zero. + * + * Check if the user PD buffer contains any + * data before freeing core PD buffer. + */ + fwd_info->cpd_len_2 = 0; + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (fwd_info->upd_len[i][1]) { + upd_valid_len = 1; + break; + } + } + /* + * Do not free the core pd buffer if valid data + * is present in any user PD buffer + */ + if (!upd_valid_len) { + atomic_set(&fwd_info->buf_2->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, buf_num); + } + } else if (buf_num >= 3 && (buf_num % 2)) { + /* + * Go through each User PD buffer, validate the + * request for freeing the buffer by validating + * the buffer number. + * + */ + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (fwd_info->buf_upd[i][0] && + (buf_num == ((2 * i) + 3))) { + /* Buffer 1 for ith user PD is freed */ + atomic_set(&fwd_info->buf_upd[i][0]->in_busy, + 0); + fwd_info->upd_len[i][0] = 0; + } + /* + * Check if there is any data in user PD buffer other + * than buffer requested for freeing. + * + */ + if (fwd_info->upd_len[i][0]) + upd_valid_len = 1; + } + /* + * Mark the core pd buffer free if there is no + * data present in core PD buffer and other User PD buffer. + * + */ + if (!upd_valid_len && !fwd_info->cpd_len_1) { + atomic_set(&fwd_info->buf_1->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, buf_num); + } + } else if (buf_num >= 4 && !(buf_num % 2)) { + /* + * Go through each User PD buffer, validate the + * request for freeing the buffer by validating + * the buffer number. + * + */ + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (fwd_info->buf_upd[i][1] && + (buf_num == ((2 * i) + 4))) { + /* Buffer 2 for ith user PD is freed */ + atomic_set(&fwd_info->buf_upd[i][1]->in_busy, + 0); + fwd_info->upd_len[i][1] = 0; + } + /* + * Check if there is any data in user PD buffer other + * than buffer requested for freeing. + * + */ + if (fwd_info->upd_len[i][1]) + upd_valid_len = 1; + } + /* + * Mark the core pd buffer free if there is no + * data present in core PD buffer and other User PD buffer. + * + */ + if (!upd_valid_len && !fwd_info->cpd_len_2) { + atomic_set(&fwd_info->buf_2->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, buf_num); + } + } else + pr_err("diag: In %s, invalid buf_num %d\n", __func__, buf_num); diagfwd_queue_read(fwd_info); } @@ -1034,6 +1636,10 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info) fail_return: diag_ws_release(); atomic_set(&temp_buf->in_busy, 0); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Buffer for core PD is marked free, p: %d, t: %d, buf_num: %d\n", + fwd_info->peripheral, fwd_info->type, + GET_BUF_NUM(temp_buf->ctxt)); } static void diagfwd_queue_read(struct diagfwd_info *fwd_info) @@ -1063,8 +1669,65 @@ static void diagfwd_queue_read(struct diagfwd_info *fwd_info) fwd_info->p_ops->queue_read(fwd_info->ctxt); } +static int diagfwd_buffers_allocate(struct diagfwd_info *fwd_info) +{ + int i, j; + + for (i = 0; ((fwd_info->num_pd > 1) && + (i <= (fwd_info->num_pd - 2))); i++) { + for (j = 0; j < NUM_WRITE_BUFFERS; j++) { + if (!fwd_info->buf_upd[i][j]) { + fwd_info->buf_upd[i][j] = + kzalloc(sizeof(struct diagfwd_buf_t), + GFP_KERNEL); + if (ZERO_OR_NULL_PTR(fwd_info->buf_upd[i][j])) + return -ENOMEM; + kmemleak_not_leak(fwd_info->buf_upd[i][j]); + } + + if (fwd_info->buf_upd[i][j] && + !fwd_info->buf_upd[i][j]->data) { + fwd_info->buf_upd[i][j]->data = + kzalloc(PERIPHERAL_BUF_SZ + + APF_DIAG_PADDING, + GFP_KERNEL); + if (ZERO_OR_NULL_PTR( + fwd_info->buf_upd[i][j]->data)) + return -ENOMEM; + fwd_info->buf_upd[i][j]->len = + PERIPHERAL_BUF_SZ; + kmemleak_not_leak( + fwd_info->buf_upd[i][j]->data); + fwd_info->buf_upd[i][j]->ctxt = + SET_BUF_CTXT(fwd_info->peripheral, + fwd_info->type, ((2 * i) + (j + 3))); + } + + if (driver->supports_apps_hdlc_encoding) { + if (fwd_info->buf_upd[i][j] && + !fwd_info->buf_upd[i][j]->data_raw) { + fwd_info->buf_upd[i][j]->data_raw = + kzalloc(PERIPHERAL_BUF_SZ + + APF_DIAG_PADDING, + GFP_KERNEL); + if (ZERO_OR_NULL_PTR( + fwd_info->buf_upd[i][j]->data_raw)) + return -ENOMEM; + fwd_info->buf_upd[i][j]->len_raw = + PERIPHERAL_BUF_SZ; + kmemleak_not_leak( + fwd_info->buf_upd[i][j]->data_raw); + } + } + } + } + return 0; +} + void diagfwd_buffers_init(struct diagfwd_info *fwd_info) { + int ret = 0; + unsigned char *temp_char_buf; if (!fwd_info) return; @@ -1076,18 +1739,20 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) } mutex_lock(&fwd_info->buf_mutex); + if (!fwd_info->buf_1) { fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t), GFP_KERNEL); - if (!fwd_info->buf_1) + if (ZERO_OR_NULL_PTR(fwd_info->buf_1)) goto err; kmemleak_not_leak(fwd_info->buf_1); } + if (!fwd_info->buf_1->data) { fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ + APF_DIAG_PADDING, GFP_KERNEL); - if (!fwd_info->buf_1->data) + if (ZERO_OR_NULL_PTR(fwd_info->buf_1->data)) goto err; fwd_info->buf_1->len = PERIPHERAL_BUF_SZ; kmemleak_not_leak(fwd_info->buf_1->data); @@ -1099,7 +1764,7 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) if (!fwd_info->buf_2) { fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t), GFP_KERNEL); - if (!fwd_info->buf_2) + if (ZERO_OR_NULL_PTR(fwd_info->buf_2)) goto err; kmemleak_not_leak(fwd_info->buf_2); } @@ -1108,7 +1773,7 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ + APF_DIAG_PADDING, GFP_KERNEL); - if (!fwd_info->buf_2->data) + if (ZERO_OR_NULL_PTR(fwd_info->buf_2->data)) goto err; fwd_info->buf_2->len = PERIPHERAL_BUF_SZ; kmemleak_not_leak(fwd_info->buf_2->data); @@ -1117,6 +1782,12 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) fwd_info->type, 2); } + if (driver->feature[fwd_info->peripheral].untag_header) { + ret = diagfwd_buffers_allocate(fwd_info); + if (ret) + goto err; + } + if (driver->supports_apps_hdlc_encoding) { /* In support of hdlc encoding */ if (!fwd_info->buf_1->data_raw) { @@ -1124,34 +1795,44 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) kzalloc(PERIPHERAL_BUF_SZ + APF_DIAG_PADDING, GFP_KERNEL); - if (!fwd_info->buf_1->data_raw) + temp_char_buf = + fwd_info->buf_1->data_raw; + if (ZERO_OR_NULL_PTR(temp_char_buf)) goto err; - fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ; - kmemleak_not_leak(fwd_info->buf_1->data_raw); + fwd_info->buf_1->len_raw = + PERIPHERAL_BUF_SZ; + kmemleak_not_leak(temp_char_buf); } + if (!fwd_info->buf_2->data_raw) { fwd_info->buf_2->data_raw = kzalloc(PERIPHERAL_BUF_SZ + APF_DIAG_PADDING, GFP_KERNEL); - if (!fwd_info->buf_2->data_raw) + temp_char_buf = + fwd_info->buf_2->data_raw; + if (ZERO_OR_NULL_PTR(temp_char_buf)) goto err; - fwd_info->buf_2->len_raw = PERIPHERAL_BUF_SZ; - kmemleak_not_leak(fwd_info->buf_2->data_raw); + fwd_info->buf_2->len_raw = + PERIPHERAL_BUF_SZ; + kmemleak_not_leak(temp_char_buf); } } } - if (fwd_info->type == TYPE_CMD && driver->supports_apps_hdlc_encoding) { + if (fwd_info->type == TYPE_CMD && + driver->supports_apps_hdlc_encoding) { /* In support of hdlc encoding */ if (!fwd_info->buf_1->data_raw) { fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ + APF_DIAG_PADDING, GFP_KERNEL); - if (!fwd_info->buf_1->data_raw) + temp_char_buf = + fwd_info->buf_1->data_raw; + if (ZERO_OR_NULL_PTR(temp_char_buf)) goto err; fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ; - kmemleak_not_leak(fwd_info->buf_1->data_raw); + kmemleak_not_leak(temp_char_buf); } } @@ -1161,10 +1842,12 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info) err: mutex_unlock(&fwd_info->buf_mutex); diagfwd_buffers_exit(fwd_info); + return; } static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info) { + int i = 0; if (!fwd_info) return; @@ -1186,6 +1869,24 @@ static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info) kfree(fwd_info->buf_2); fwd_info->buf_2 = NULL; } + for (i = 0; i <= (fwd_info->num_pd - 2); i++) { + if (fwd_info->buf_upd[i][0]) { + kfree(fwd_info->buf_upd[i][0]->data); + fwd_info->buf_upd[i][0]->data = NULL; + kfree(fwd_info->buf_upd[i][0]->data_raw); + fwd_info->buf_upd[i][0]->data_raw = NULL; + kfree(fwd_info->buf_upd[i][0]); + fwd_info->buf_upd[i][0] = NULL; + } + if (fwd_info->buf_upd[i][1]) { + kfree(fwd_info->buf_upd[i][1]->data); + fwd_info->buf_upd[i][1]->data = NULL; + kfree(fwd_info->buf_upd[i][1]->data_raw); + fwd_info->buf_upd[i][1]->data_raw = NULL; + kfree(fwd_info->buf_upd[i][1]); + fwd_info->buf_upd[i][1] = NULL; + } + } mutex_unlock(&fwd_info->buf_mutex); } diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h index 5884a124498d4a2e146648bcf72335237b9b1c57..6ddce320df45fd0a04a01221317e6a3854bed2b0 100644 --- a/drivers/char/diag/diagfwd_peripheral.h +++ b/drivers/char/diag/diagfwd_peripheral.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 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 @@ -62,12 +62,22 @@ struct diag_peripheral_ops { void (*queue_read)(void *ctxt); }; +struct diag_id_info { + uint8_t diagid_val; + uint8_t pd; + char *reg_str; +}; + struct diagfwd_info { uint8_t peripheral; uint8_t type; uint8_t transport; uint8_t inited; uint8_t ch_open; + uint8_t num_pd; + int cpd_len_1; + int cpd_len_2; + int upd_len[MAX_PERIPHERAL_UPD][2]; atomic_t opened; unsigned long read_bytes; unsigned long write_bytes; @@ -75,8 +85,11 @@ struct diagfwd_info { struct mutex buf_mutex; struct mutex data_mutex; void *ctxt; + struct diag_id_info root_diag_id; + struct diag_id_info upd_diag_id[MAX_PERIPHERAL_UPD]; struct diagfwd_buf_t *buf_1; struct diagfwd_buf_t *buf_2; + struct diagfwd_buf_t *buf_upd[MAX_PERIPHERAL_UPD][2]; struct diagfwd_buf_t *buf_ptr[NUM_WRITE_BUFFERS]; struct diag_peripheral_ops *p_ops; struct diag_channel_ops *c_ops; @@ -94,6 +107,9 @@ void diagfwd_early_open(uint8_t peripheral); void diagfwd_late_open(struct diagfwd_info *fwd_info); void diagfwd_close(uint8_t peripheral, uint8_t type); + +int diag_md_get_peripheral(int ctxt); + int diagfwd_register(uint8_t transport, uint8_t peripheral, uint8_t type, void *ctxt, struct diag_peripheral_ops *ops, struct diagfwd_info **fwd_ctxt); @@ -103,7 +119,7 @@ int diagfwd_cntl_register(uint8_t transport, uint8_t peripheral, void *ctxt, void diagfwd_deregister(uint8_t peripheral, uint8_t type, void *ctxt); int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len); -void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt); +void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num); void diagfwd_buffers_init(struct diagfwd_info *fwd_info); /* diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index af8bf002e09966e0ba13317d85ebdffa090a680d..f3c587decca6ba4dde2dce361b3badc52f5b6a21 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -513,8 +513,10 @@ static void __socket_close_channel(struct diag_socket_info *info) info->hdl->sk->sk_user_data = NULL; info->hdl->sk->sk_data_ready = NULL; write_unlock_bh(&info->hdl->sk->sk_callback_lock); + mutex_lock(&info->socket_info_mutex); sock_release(info->hdl); info->hdl = NULL; + mutex_unlock(&info->socket_info_mutex); wake_up_interruptible(&info->read_wait_q); } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", info->name); @@ -820,6 +822,8 @@ static void __diag_socket_init(struct diag_socket_info *info) break; } + if (info->port_type == PORT_TYPE_CLIENT) + mutex_init(&info->socket_info_mutex); info->svc_id = DIAG_SVC_ID; info->ins_id = ins_base + ins_offset; info->inited = 1; @@ -1031,6 +1035,8 @@ static void __diag_socket_exit(struct diag_socket_info *info) diagfwd_deregister(info->peripheral, info->type, (void *)info); info->fwd_ctxt = NULL; info->hdl = NULL; + if (info->port_type == PORT_TYPE_CLIENT) + mutex_destroy(&info->socket_info_mutex); if (info->wq) destroy_workqueue(info->wq); @@ -1119,13 +1125,28 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) read_msg.msg_name = &src_addr; read_msg.msg_namelen = sizeof(src_addr); + if (info->port_type != PORT_TYPE_SERVER) { + mutex_lock(&info->socket_info_mutex); + if (!info->hdl) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s closing read thread\n", + info->name); + mutex_unlock(&info->socket_info_mutex); + goto fail; + } + } pkt_len = kernel_recvmsg(info->hdl, &read_msg, &iov, 1, 0, MSG_PEEK); - if (pkt_len <= 0) + if (pkt_len <= 0) { + if (info->port_type != PORT_TYPE_SERVER) + mutex_unlock(&info->socket_info_mutex); break; + } if (pkt_len > bytes_remaining) { buf_full = 1; + if (info->port_type != PORT_TYPE_SERVER) + mutex_unlock(&info->socket_info_mutex); break; } @@ -1135,6 +1156,8 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) read_len = kernel_recvmsg(info->hdl, &read_msg, &iov, 1, pkt_len, 0); + if (info->port_type != PORT_TYPE_SERVER) + mutex_unlock(&info->socket_info_mutex); if (read_len <= 0) goto fail; @@ -1211,7 +1234,16 @@ static int diag_socket_write(void *ctxt, unsigned char *buf, int len) write_msg.msg_name = &info->remote_addr; write_msg.msg_namelen = sizeof(info->remote_addr); write_msg.msg_flags |= MSG_DONTWAIT; + if (info->port_type != PORT_TYPE_SERVER) { + mutex_lock(&info->socket_info_mutex); + if (!info->hdl) { + mutex_unlock(&info->socket_info_mutex); + return -ENODEV; + } + } write_len = kernel_sendmsg(info->hdl, &write_msg, &iov, 1, len); + if (info->port_type != PORT_TYPE_SERVER) + mutex_unlock(&info->socket_info_mutex); if (write_len < 0) { err = write_len; /* diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h index a9487b1b3ac1171a1e4b61abac90230084819dea..c42be06aa9768a0609e3c44fefc91d0fbba90ad0 100644 --- a/drivers/char/diag/diagfwd_socket.h +++ b/drivers/char/diag/diagfwd_socket.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 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 @@ -65,6 +65,7 @@ struct diag_socket_info { struct work_struct read_work; struct diagfwd_info *fwd_ctxt; wait_queue_head_t read_wait_q; + struct mutex socket_info_mutex; }; union cntl_port_msg { diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c index 7641a6a82c36beb1c0a3f93958dc088219018b8c..fdcef1de8152cbd2841f6222462322f0a1988ff9 100644 --- a/drivers/char/hw_random/msm_rng.c +++ b/drivers/char/hw_random/msm_rng.c @@ -53,6 +53,9 @@ #define MAX_HW_FIFO_DEPTH 16 /* FIFO is 16 words deep */ #define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) /* FIFO is 32 bits wide */ +#define RETRY_MAX_CNT 5 /* max retry times to read register */ +#define RETRY_DELAY_INTERVAL 440 /* retry delay interval in us */ + struct msm_rng_device { struct platform_device *pdev; void __iomem *base; @@ -96,7 +99,7 @@ static int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, struct platform_device *pdev; void __iomem *base; size_t currsize = 0; - u32 val; + u32 val = 0; u32 *retdata = data; int ret; int failed = 0; @@ -113,40 +116,40 @@ static int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, if (msm_rng_dev->qrng_perf_client) { ret = msm_bus_scale_client_update_request( msm_rng_dev->qrng_perf_client, 1); - if (ret) + if (ret) { pr_err("bus_scale_client_update_req failed!\n"); + goto bus_err; + } } /* enable PRNG clock */ ret = clk_prepare_enable(msm_rng_dev->prng_clk); if (ret) { - dev_err(&pdev->dev, "failed to enable clock in callback\n"); + pr_err("failed to enable prng clock\n"); goto err; } /* read random data from h/w */ do { /* check status bit if data is available */ - while (!(readl_relaxed(base + PRNG_STATUS_OFFSET) + if (!(readl_relaxed(base + PRNG_STATUS_OFFSET) & 0x00000001)) { - if (failed == 10) { - pr_err("Data not available after retry\n"); + if (failed++ == RETRY_MAX_CNT) { + if (currsize == 0) + pr_err("Data not available\n"); break; } - pr_err("msm_rng:Data not available!\n"); - msleep_interruptible(10); - failed++; - } + udelay(RETRY_DELAY_INTERVAL); + } else { - /* read FIFO */ - val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET); - if (!val) - break; /* no data to read so just bail */ + /* read FIFO */ + val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET); - /* write data back to callers pointer */ - *(retdata++) = val; - currsize += 4; - /* make sure we stay on 32bit boundary */ - if ((max - currsize) < 4) - break; + /* write data back to callers pointer */ + *(retdata++) = val; + currsize += 4; + /* make sure we stay on 32bit boundary */ + if ((max - currsize) < 4) + break; + } } while (currsize < max); @@ -159,6 +162,7 @@ static int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev, if (ret) pr_err("bus_scale_client_update_req failed!\n"); } +bus_err: mutex_unlock(&msm_rng_dev->rng_lock); val = 0L; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index fcdd886819f5c85d88767d9d2042b8fef7a1d11f..5d509ccf1299c3e71264339f780b838c1cabc424 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3877,6 +3877,9 @@ static void smi_recv_tasklet(unsigned long val) * because the lower layer is allowed to hold locks while calling * message delivery. */ + + rcu_read_lock(); + if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); if (intf->curr_msg == NULL && !intf->in_shutdown) { @@ -3899,6 +3902,8 @@ static void smi_recv_tasklet(unsigned long val) if (newmsg) intf->handlers->sender(intf->send_info, newmsg); + rcu_read_unlock(); + handle_new_recv_msgs(intf); } @@ -4024,7 +4029,8 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, } static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, - struct list_head *timeouts, long timeout_period, + struct list_head *timeouts, + unsigned long timeout_period, int slot, unsigned long *flags, unsigned int *waiting_msgs) { @@ -4037,8 +4043,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, if (!ent->inuse) return; - ent->timeout -= timeout_period; - if (ent->timeout > 0) { + if (timeout_period < ent->timeout) { + ent->timeout -= timeout_period; (*waiting_msgs)++; return; } @@ -4104,7 +4110,8 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, } } -static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, long timeout_period) +static unsigned int ipmi_timeout_handler(ipmi_smi_t intf, + unsigned long timeout_period) { struct list_head timeouts; struct ipmi_recv_msg *msg, *msg2; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a112c0146012e2ba1fb58b54be59d758d0349108..e0a53156b782f086e944ac333652873faf71cad1 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -241,6 +241,9 @@ struct smi_info { /* The timer for this si. */ struct timer_list si_timer; + /* This flag is set, if the timer can be set */ + bool timer_can_start; + /* This flag is set, if the timer is running (timer_pending() isn't enough) */ bool timer_running; @@ -416,6 +419,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) { + if (!smi_info->timer_can_start) + return; smi_info->last_timeout_jiffies = jiffies; mod_timer(&smi_info->si_timer, new_val); smi_info->timer_running = true; @@ -435,21 +440,18 @@ static void start_new_msg(struct smi_info *smi_info, unsigned char *msg, smi_info->handlers->start_transaction(smi_info->si_sm, msg, size); } -static void start_check_enables(struct smi_info *smi_info, bool start_timer) +static void start_check_enables(struct smi_info *smi_info) { unsigned char msg[2]; msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; - if (start_timer) - start_new_msg(smi_info, msg, 2); - else - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + start_new_msg(smi_info, msg, 2); smi_info->si_state = SI_CHECKING_ENABLES; } -static void start_clear_flags(struct smi_info *smi_info, bool start_timer) +static void start_clear_flags(struct smi_info *smi_info) { unsigned char msg[3]; @@ -458,10 +460,7 @@ static void start_clear_flags(struct smi_info *smi_info, bool start_timer) msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; msg[2] = WDT_PRE_TIMEOUT_INT; - if (start_timer) - start_new_msg(smi_info, msg, 3); - else - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); + start_new_msg(smi_info, msg, 3); smi_info->si_state = SI_CLEARING_FLAGS; } @@ -496,11 +495,11 @@ static void start_getting_events(struct smi_info *smi_info) * Note that we cannot just use disable_irq(), since the interrupt may * be shared. */ -static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) +static inline bool disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = true; - start_check_enables(smi_info, start_timer); + start_check_enables(smi_info); return true; } return false; @@ -510,7 +509,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = false; - start_check_enables(smi_info, true); + start_check_enables(smi_info); return true; } return false; @@ -528,7 +527,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) msg = ipmi_alloc_smi_msg(); if (!msg) { - if (!disable_si_irq(smi_info, true)) + if (!disable_si_irq(smi_info)) smi_info->si_state = SI_NORMAL; } else if (enable_si_irq(smi_info)) { ipmi_free_smi_msg(msg); @@ -544,7 +543,7 @@ static void handle_flags(struct smi_info *smi_info) /* Watchdog pre-timeout */ smi_inc_stat(smi_info, watchdog_pretimeouts); - start_clear_flags(smi_info, true); + start_clear_flags(smi_info); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; if (smi_info->intf) ipmi_smi_watchdog_pretimeout(smi_info->intf); @@ -927,7 +926,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, * disable and messages disabled. */ if (smi_info->supports_event_msg_buff || smi_info->irq) { - start_check_enables(smi_info, true); + start_check_enables(smi_info); } else { smi_info->curr_msg = alloc_msg_handle_irq(smi_info); if (!smi_info->curr_msg) @@ -1234,6 +1233,7 @@ static int smi_start_processing(void *send_info, /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); + new_smi->timer_can_start = true; smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); /* Try to claim any interrupts. */ @@ -3448,10 +3448,12 @@ static void check_for_broken_irqs(struct smi_info *smi_info) check_set_rcv_irq(smi_info); } -static inline void wait_for_timer_and_thread(struct smi_info *smi_info) +static inline void stop_timer_and_thread(struct smi_info *smi_info) { if (smi_info->thread != NULL) kthread_stop(smi_info->thread); + + smi_info->timer_can_start = false; if (smi_info->timer_running) del_timer_sync(&smi_info->si_timer); } @@ -3593,7 +3595,7 @@ static int try_smi_init(struct smi_info *new_smi) * Start clearing the flags before we enable interrupts or the * timer to avoid racing with the timer. */ - start_clear_flags(new_smi, false); + start_clear_flags(new_smi); /* * IRQ is defined to be set when non-zero. req_events will @@ -3671,7 +3673,7 @@ static int try_smi_init(struct smi_info *new_smi) return 0; out_err_stop_timer: - wait_for_timer_and_thread(new_smi); + stop_timer_and_thread(new_smi); out_err: new_smi->interrupt_disabled = true; @@ -3865,7 +3867,7 @@ static void cleanup_one_si(struct smi_info *to_clean) */ if (to_clean->irq_cleanup) to_clean->irq_cleanup(to_clean); - wait_for_timer_and_thread(to_clean); + stop_timer_and_thread(to_clean); /* * Timeouts are stopped, now make sure the interrupts are off @@ -3876,7 +3878,7 @@ static void cleanup_one_si(struct smi_info *to_clean) poll(to_clean); schedule_timeout_uninterruptible(1); } - disable_si_irq(to_clean, false); + disable_si_irq(to_clean); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 5673ffff00be7438e49d157d2b17a935ee9abb01..510fc104bcdc25992323774f1fbd26ef94d9c79e 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -762,6 +762,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, result, len, data[2]); } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || data[1] != IPMI_GET_MSG_FLAGS_CMD) { + /* + * Don't abort here, maybe it was a queued + * response to a previous command. + */ + ipmi_ssif_unlock_cond(ssif_info, flags); pr_warn(PFX "Invalid response getting flags: %x %x\n", data[0], data[1]); } else { @@ -892,6 +897,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, * for details on the intricacies of this. */ int left; + unsigned char *data_to_send; ssif_inc_stat(ssif_info, sent_messages_parts); @@ -900,6 +906,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, left = 32; /* Length byte. */ ssif_info->multi_data[ssif_info->multi_pos] = left; + data_to_send = ssif_info->multi_data + ssif_info->multi_pos; ssif_info->multi_pos += left; if (left < 32) /* @@ -913,7 +920,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, rv = ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE, SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE, - ssif_info->multi_data + ssif_info->multi_pos, + data_to_send, I2C_SMBUS_BLOCK_DATA); if (rv < 0) { /* request failed, just return the error. */ diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 4facc7517a6a222350f2478568f81422980ff108..9093110161083f7e031b9fb1f802b12488ebacc9 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1162,10 +1162,11 @@ static int wdog_reboot_handler(struct notifier_block *this, ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { - /* Set a long timer to let the reboot happens, but - reboot if it hangs, but only if the watchdog + /* Set a long timer to let the reboot happen or + reset if it hangs, but only if the watchdog timer was already running. */ - timeout = 120; + if (timeout < 120) + timeout = 120; pretimeout = 0; ipmi_watchdog_state = WDOG_TIMEOUT_RESET; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index c4094c4e22c11dda9647d3d472a18203f98f9649..34ef474a3923c4183a65d038ad9d1a31ad6fc025 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -859,7 +859,11 @@ static int __init lp_setup (char *str) } else if (!strcmp(str, "auto")) { parport_nr[0] = LP_PARPORT_AUTO; } else if (!strcmp(str, "none")) { - parport_nr[parport_ptr++] = LP_PARPORT_NONE; + if (parport_ptr < LP_NO) + parport_nr[parport_ptr++] = LP_PARPORT_NONE; + else + printk(KERN_INFO "lp: too many ports, %s ignored.\n", + str); } else if (!strcmp(str, "reset")) { reset = 1; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 7e4a9d1296bb7fb666f6b37ced2757a8585b7d75..593a8818aca99e345e03d0fb56eabd25b5ffd05a 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -340,6 +340,11 @@ static const struct vm_operations_struct mmap_mem_ops = { static int mmap_mem(struct file *file, struct vm_area_struct *vma) { size_t size = vma->vm_end - vma->vm_start; + phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT; + + /* It's illegal to wrap around the end of the physical address space. */ + if (offset + (phys_addr_t)size - 1 < offset) + return -EINVAL; if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) return -EINVAL; diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c new file mode 100644 index 0000000000000000000000000000000000000000..ff77cb29caeb9fc739063bb34bcb941d78081a99 --- /dev/null +++ b/drivers/char/msm_smd_pkt.c @@ -0,0 +1,1397 @@ +/* Copyright (c) 2008-2017, 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. + * + */ +/* + * SMD Packet Driver -- Provides a binary SMD non-muxed packet port + * interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "msm_smdpkt" +#define DEVICE_NAME "smdpkt" +#define WAKEUPSOURCE_TIMEOUT (2000) /* two seconds */ + +struct smd_pkt_dev { + struct list_head dev_list; + char dev_name[SMD_MAX_CH_NAME_LEN]; + char ch_name[SMD_MAX_CH_NAME_LEN]; + uint32_t edge; + + struct cdev cdev; + struct device *devicep; + void *pil; + + struct smd_channel *ch; + struct mutex ch_lock; + struct mutex rx_lock; + struct mutex tx_lock; + wait_queue_head_t ch_read_wait_queue; + wait_queue_head_t ch_write_wait_queue; + wait_queue_head_t ch_opened_wait_queue; + + int i; + int ref_cnt; + + int blocking_write; + int is_open; + int poll_mode; + unsigned int ch_size; + uint open_modem_wait; + + int has_reset; + int do_reset_notification; + struct completion ch_allocated; + struct wakeup_source pa_ws; /* Packet Arrival Wakeup Source */ + struct work_struct packet_arrival_work; + spinlock_t pa_spinlock; + int ws_locked; +}; + + +struct smd_pkt_driver { + struct list_head list; + int ref_cnt; + char pdriver_name[SMD_MAX_CH_NAME_LEN]; + struct platform_driver driver; +}; + +static DEFINE_MUTEX(smd_pkt_driver_lock_lha1); +static LIST_HEAD(smd_pkt_driver_list); + +struct class *smd_pkt_classp; +static dev_t smd_pkt_number; +static struct delayed_work loopback_work; +static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp); +static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp); +static uint32_t is_modem_smsm_inited(void); + +static DEFINE_MUTEX(smd_pkt_dev_lock_lha1); +static LIST_HEAD(smd_pkt_dev_list); +static int num_smd_pkt_ports; + +#define SMD_PKT_IPC_LOG_PAGE_CNT 2 +static void *smd_pkt_ilctxt; + +static int msm_smd_pkt_debug_mask; +module_param_named(debug_mask, msm_smd_pkt_debug_mask, int, 0664); + +enum { + SMD_PKT_STATUS = 1U << 0, + SMD_PKT_READ = 1U << 1, + SMD_PKT_WRITE = 1U << 2, + SMD_PKT_POLL = 1U << 5, +}; + +#define DEBUG + +#ifdef DEBUG + +#define SMD_PKT_LOG_STRING(x...) \ +do { \ + if (smd_pkt_ilctxt) \ + ipc_log_string(smd_pkt_ilctxt, ": "x); \ +} while (0) + +#define D_STATUS(x...) \ +do { \ + if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \ + pr_info("Status: "x); \ + SMD_PKT_LOG_STRING(x); \ +} while (0) + +#define D_READ(x...) \ +do { \ + if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \ + pr_info("Read: "x); \ + SMD_PKT_LOG_STRING(x); \ +} while (0) + +#define D_WRITE(x...) \ +do { \ + if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \ + pr_info("Write: "x); \ + SMD_PKT_LOG_STRING(x); \ +} while (0) + +#define D_POLL(x...) \ +do { \ + if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \ + pr_info("Poll: "x); \ + SMD_PKT_LOG_STRING(x); \ +} while (0) + +#define E_SMD_PKT_SSR(x) \ +do { \ + if (x->do_reset_notification) \ + pr_err("%s notifying reset for smd_pkt_dev id:%d\n", \ + __func__, x->i); \ +} while (0) +#else +#define D_STATUS(x...) do {} while (0) +#define D_READ(x...) do {} while (0) +#define D_WRITE(x...) do {} while (0) +#define D_POLL(x...) do {} while (0) +#define E_SMD_PKT_SSR(x) do {} while (0) +#endif + +static ssize_t open_timeout_store(struct device *d, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct smd_pkt_dev *smd_pkt_devp; + unsigned long tmp; + + mutex_lock(&smd_pkt_dev_lock_lha1); + list_for_each_entry(smd_pkt_devp, &smd_pkt_dev_list, dev_list) { + if (smd_pkt_devp->devicep == d) { + if (!kstrtoul(buf, 10, &tmp)) { + smd_pkt_devp->open_modem_wait = tmp; + mutex_unlock(&smd_pkt_dev_lock_lha1); + return n; + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + pr_err("%s: unable to convert: %s to an int\n", + __func__, buf); + return -EINVAL; + } + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + + pr_err("%s: unable to match device to valid smd_pkt port\n", __func__); + return -EINVAL; +} + +static ssize_t open_timeout_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct smd_pkt_dev *smd_pkt_devp; + + mutex_lock(&smd_pkt_dev_lock_lha1); + list_for_each_entry(smd_pkt_devp, &smd_pkt_dev_list, dev_list) { + if (smd_pkt_devp->devicep == d) { + mutex_unlock(&smd_pkt_dev_lock_lha1); + return snprintf(buf, PAGE_SIZE, "%d\n", + smd_pkt_devp->open_modem_wait); + } + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + pr_err("%s: unable to match device to valid smd_pkt port\n", __func__); + return -EINVAL; + +} + +static DEVICE_ATTR(open_timeout, 0664, open_timeout_show, open_timeout_store); + +/** + * loopback_edge_store() - Set the edge type for loopback device + * @d: Linux device structure + * @attr: Device attribute structure + * @buf: Input string + * @n: Length of the input string + * + * This function is used to set the loopback device edge runtime + * by writing to the loopback_edge node. + */ +static ssize_t loopback_edge_store(struct device *d, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct smd_pkt_dev *smd_pkt_devp; + unsigned long tmp; + + mutex_lock(&smd_pkt_dev_lock_lha1); + list_for_each_entry(smd_pkt_devp, &smd_pkt_dev_list, dev_list) { + if (smd_pkt_devp->devicep == d) { + if (!kstrtoul(buf, 10, &tmp)) { + smd_pkt_devp->edge = tmp; + mutex_unlock(&smd_pkt_dev_lock_lha1); + return n; + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + pr_err("%s: unable to convert: %s to an int\n", + __func__, buf); + return -EINVAL; + } + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + pr_err("%s: unable to match device to valid smd_pkt port\n", __func__); + return -EINVAL; +} + +/** + * loopback_edge_show() - Get the edge type for loopback device + * @d: Linux device structure + * @attr: Device attribute structure + * @buf: Output buffer + * + * This function is used to get the loopback device edge runtime + * by reading the loopback_edge node. + */ +static ssize_t loopback_edge_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct smd_pkt_dev *smd_pkt_devp; + + mutex_lock(&smd_pkt_dev_lock_lha1); + list_for_each_entry(smd_pkt_devp, &smd_pkt_dev_list, dev_list) { + if (smd_pkt_devp->devicep == d) { + mutex_unlock(&smd_pkt_dev_lock_lha1); + return snprintf(buf, PAGE_SIZE, "%d\n", + smd_pkt_devp->edge); + } + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + pr_err("%s: unable to match device to valid smd_pkt port\n", __func__); + return -EINVAL; + +} + +static DEVICE_ATTR(loopback_edge, 0664, loopback_edge_show, + loopback_edge_store); + +static int notify_reset(struct smd_pkt_dev *smd_pkt_devp) +{ + smd_pkt_devp->do_reset_notification = 0; + + return -ENETRESET; +} + +static void clean_and_signal(struct smd_pkt_dev *smd_pkt_devp) +{ + smd_pkt_devp->do_reset_notification = 1; + smd_pkt_devp->has_reset = 1; + + smd_pkt_devp->is_open = 0; + + wake_up(&smd_pkt_devp->ch_read_wait_queue); + wake_up(&smd_pkt_devp->ch_write_wait_queue); + wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue); + D_STATUS("%s smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i); +} + +static void loopback_probe_worker(struct work_struct *work) +{ + + /* Wait for the modem SMSM to be inited for the SMD + ** Loopback channel to be allocated at the modem. Since + ** the wait need to be done atmost once, using msleep + ** doesn't degrade the performance. + */ + if (!is_modem_smsm_inited()) + schedule_delayed_work(&loopback_work, msecs_to_jiffies(1000)); + else + smsm_change_state(SMSM_APPS_STATE, + 0, SMSM_SMD_LOOPBACK); + +} + +static void packet_arrival_worker(struct work_struct *work) +{ + struct smd_pkt_dev *smd_pkt_devp; + unsigned long flags; + + smd_pkt_devp = container_of(work, struct smd_pkt_dev, + packet_arrival_work); + mutex_lock(&smd_pkt_devp->ch_lock); + spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags); + if (smd_pkt_devp->ch && smd_pkt_devp->ws_locked) { + D_READ("%s locking smd_pkt_dev id:%d wakeup source\n", + __func__, smd_pkt_devp->i); + /* + * Keep system awake long enough to allow userspace client + * to process the packet. + */ + __pm_wakeup_event(&smd_pkt_devp->pa_ws, WAKEUPSOURCE_TIMEOUT); + } + spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags); + mutex_unlock(&smd_pkt_devp->ch_lock); +} + +static long smd_pkt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct smd_pkt_dev *smd_pkt_devp; + uint32_t val; + + smd_pkt_devp = file->private_data; + if (!smd_pkt_devp) + return -EINVAL; + + mutex_lock(&smd_pkt_devp->ch_lock); + switch (cmd) { + case TIOCMGET: + D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + ret = smd_tiocmget(smd_pkt_devp->ch); + break; + case TIOCMSET: + ret = get_user(val, (uint32_t *)arg); + if (ret) { + pr_err("Error getting TIOCMSET value\n"); + mutex_unlock(&smd_pkt_devp->ch_lock); + return ret; + } + D_STATUS("%s TIOCSET command on smd_pkt_dev id:%d arg[0x%x]\n", + __func__, smd_pkt_devp->i, val); + ret = smd_tiocmset(smd_pkt_devp->ch, val, ~val); + break; + case SMD_PKT_IOCTL_BLOCKING_WRITE: + ret = get_user(smd_pkt_devp->blocking_write, (int *)arg); + break; + default: + pr_err_ratelimited("%s: Unrecognized ioctl command %d\n", + __func__, cmd); + ret = -ENOIOCTLCMD; + } + mutex_unlock(&smd_pkt_devp->ch_lock); + + return ret; +} + +ssize_t smd_pkt_read(struct file *file, + char __user *_buf, + size_t count, + loff_t *ppos) +{ + int r; + int bytes_read; + int pkt_size; + struct smd_pkt_dev *smd_pkt_devp; + unsigned long flags; + void *buf; + + smd_pkt_devp = file->private_data; + + if (!smd_pkt_devp) { + pr_err_ratelimited("%s on NULL smd_pkt_dev\n", __func__); + return -EINVAL; + } + + if (!smd_pkt_devp->ch) { + pr_err_ratelimited("%s on a closed smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + return -EINVAL; + } + + if (smd_pkt_devp->do_reset_notification) { + /* notify client that a reset occurred */ + E_SMD_PKT_SSR(smd_pkt_devp); + return notify_reset(smd_pkt_devp); + } + D_READ("Begin %s on smd_pkt_dev id:%d buffer_size %zu\n", + __func__, smd_pkt_devp->i, count); + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + +wait_for_packet: + r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue, + !smd_pkt_devp->ch || + (smd_cur_packet_size(smd_pkt_devp->ch) > 0 + && smd_read_avail(smd_pkt_devp->ch)) || + smd_pkt_devp->has_reset); + + mutex_lock(&smd_pkt_devp->rx_lock); + if (smd_pkt_devp->has_reset) { + mutex_unlock(&smd_pkt_devp->rx_lock); + E_SMD_PKT_SSR(smd_pkt_devp); + kfree(buf); + return notify_reset(smd_pkt_devp); + } + + if (!smd_pkt_devp->ch) { + mutex_unlock(&smd_pkt_devp->rx_lock); + pr_err_ratelimited("%s on a closed smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + kfree(buf); + return -EINVAL; + } + + if (r < 0) { + mutex_unlock(&smd_pkt_devp->rx_lock); + /* qualify error message */ + if (r != -ERESTARTSYS) { + /* we get this anytime a signal comes in */ + pr_err_ratelimited("%s: wait_event_interruptible on smd_pkt_dev id:%d ret %i\n", + __func__, smd_pkt_devp->i, r); + } + kfree(buf); + return r; + } + + /* Here we have a whole packet waiting for us */ + pkt_size = smd_cur_packet_size(smd_pkt_devp->ch); + + if (!pkt_size) { + pr_err_ratelimited("%s: No data on smd_pkt_dev id:%d, False wakeup\n", + __func__, smd_pkt_devp->i); + mutex_unlock(&smd_pkt_devp->rx_lock); + goto wait_for_packet; + } + + if (pkt_size < 0) { + pr_err_ratelimited("%s: Error %d obtaining packet size for Channel %s", + __func__, pkt_size, smd_pkt_devp->ch_name); + kfree(buf); + return pkt_size; + } + + if ((uint32_t)pkt_size > count) { + pr_err_ratelimited("%s: failure on smd_pkt_dev id: %d - packet size %d > buffer size %zu,", + __func__, smd_pkt_devp->i, + pkt_size, count); + mutex_unlock(&smd_pkt_devp->rx_lock); + kfree(buf); + return -ETOOSMALL; + } + + bytes_read = 0; + do { + r = smd_read(smd_pkt_devp->ch, + (buf + bytes_read), + (pkt_size - bytes_read)); + if (r < 0) { + mutex_unlock(&smd_pkt_devp->rx_lock); + if (smd_pkt_devp->has_reset) { + E_SMD_PKT_SSR(smd_pkt_devp); + return notify_reset(smd_pkt_devp); + } + pr_err_ratelimited("%s Error while reading %d\n", + __func__, r); + kfree(buf); + return r; + } + bytes_read += r; + if (pkt_size != bytes_read) + wait_event(smd_pkt_devp->ch_read_wait_queue, + smd_read_avail(smd_pkt_devp->ch) || + smd_pkt_devp->has_reset); + if (smd_pkt_devp->has_reset) { + mutex_unlock(&smd_pkt_devp->rx_lock); + E_SMD_PKT_SSR(smd_pkt_devp); + kfree(buf); + return notify_reset(smd_pkt_devp); + } + } while (pkt_size != bytes_read); + mutex_unlock(&smd_pkt_devp->rx_lock); + + mutex_lock(&smd_pkt_devp->ch_lock); + spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags); + if (smd_pkt_devp->poll_mode && + !smd_cur_packet_size(smd_pkt_devp->ch)) { + __pm_relax(&smd_pkt_devp->pa_ws); + smd_pkt_devp->ws_locked = 0; + smd_pkt_devp->poll_mode = 0; + D_READ("%s unlocked smd_pkt_dev id:%d wakeup_source\n", + __func__, smd_pkt_devp->i); + } + spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags); + mutex_unlock(&smd_pkt_devp->ch_lock); + + r = copy_to_user(_buf, buf, bytes_read); + if (r) { + kfree(buf); + return -EFAULT; + } + D_READ("Finished %s on smd_pkt_dev id:%d %d bytes\n", + __func__, smd_pkt_devp->i, bytes_read); + kfree(buf); + + /* check and wakeup read threads waiting on this device */ + check_and_wakeup_reader(smd_pkt_devp); + + return bytes_read; +} + +ssize_t smd_pkt_write(struct file *file, + const char __user *_buf, + size_t count, + loff_t *ppos) +{ + int r = 0, bytes_written; + struct smd_pkt_dev *smd_pkt_devp; + DEFINE_WAIT(write_wait); + void *buf; + + smd_pkt_devp = file->private_data; + + if (!smd_pkt_devp) { + pr_err_ratelimited("%s on NULL smd_pkt_dev\n", __func__); + return -EINVAL; + } + + if (!smd_pkt_devp->ch) { + pr_err_ratelimited("%s on a closed smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + return -EINVAL; + } + + if (smd_pkt_devp->do_reset_notification || smd_pkt_devp->has_reset) { + E_SMD_PKT_SSR(smd_pkt_devp); + /* notify client that a reset occurred */ + return notify_reset(smd_pkt_devp); + } + D_WRITE("Begin %s on smd_pkt_dev id:%d data_size %zu\n", + __func__, smd_pkt_devp->i, count); + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + r = copy_from_user(buf, _buf, count); + if (r) { + kfree(buf); + return -EFAULT; + } + + mutex_lock(&smd_pkt_devp->tx_lock); + if (!smd_pkt_devp->blocking_write) { + if (smd_write_avail(smd_pkt_devp->ch) < count) { + pr_err_ratelimited("%s: Not enough space in smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + mutex_unlock(&smd_pkt_devp->tx_lock); + kfree(buf); + return -ENOMEM; + } + } + + r = smd_write_start(smd_pkt_devp->ch, count); + if (r < 0) { + mutex_unlock(&smd_pkt_devp->tx_lock); + pr_err_ratelimited("%s: Error:%d in smd_pkt_dev id:%d @ smd_write_start\n", + __func__, r, smd_pkt_devp->i); + kfree(buf); + return r; + } + + bytes_written = 0; + do { + prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue, + &write_wait, TASK_UNINTERRUPTIBLE); + if (!smd_write_segment_avail(smd_pkt_devp->ch) && + !smd_pkt_devp->has_reset) { + smd_enable_read_intr(smd_pkt_devp->ch); + schedule(); + } + finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait); + smd_disable_read_intr(smd_pkt_devp->ch); + + if (smd_pkt_devp->has_reset) { + mutex_unlock(&smd_pkt_devp->tx_lock); + E_SMD_PKT_SSR(smd_pkt_devp); + kfree(buf); + return notify_reset(smd_pkt_devp); + } + r = smd_write_segment(smd_pkt_devp->ch, + (void *)(buf + bytes_written), + (count - bytes_written)); + if (r < 0) { + mutex_unlock(&smd_pkt_devp->tx_lock); + if (smd_pkt_devp->has_reset) { + E_SMD_PKT_SSR(smd_pkt_devp); + return notify_reset(smd_pkt_devp); + } + pr_err_ratelimited("%s on smd_pkt_dev id:%d failed r:%d\n", + __func__, smd_pkt_devp->i, r); + kfree(buf); + return r; + } + bytes_written += r; + } while (bytes_written != count); + smd_write_end(smd_pkt_devp->ch); + mutex_unlock(&smd_pkt_devp->tx_lock); + D_WRITE("Finished %s on smd_pkt_dev id:%d %zu bytes\n", + __func__, smd_pkt_devp->i, count); + + kfree(buf); + return count; +} + +static unsigned int smd_pkt_poll(struct file *file, poll_table *wait) +{ + struct smd_pkt_dev *smd_pkt_devp; + unsigned int mask = 0; + + smd_pkt_devp = file->private_data; + if (!smd_pkt_devp) { + pr_err_ratelimited("%s on a NULL device\n", __func__); + return POLLERR; + } + + smd_pkt_devp->poll_mode = 1; + poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait); + mutex_lock(&smd_pkt_devp->ch_lock); + if (smd_pkt_devp->has_reset || !smd_pkt_devp->ch) { + mutex_unlock(&smd_pkt_devp->ch_lock); + return POLLERR; + } + + if (smd_read_avail(smd_pkt_devp->ch)) { + mask |= POLLIN | POLLRDNORM; + D_POLL("%s sets POLLIN for smd_pkt_dev id: %d\n", + __func__, smd_pkt_devp->i); + } + mutex_unlock(&smd_pkt_devp->ch_lock); + + return mask; +} + +static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp) +{ + int sz; + unsigned long flags; + + if (!smd_pkt_devp) { + pr_err("%s on a NULL device\n", __func__); + return; + } + + if (!smd_pkt_devp->ch) { + pr_err("%s on a closed smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + return; + } + + sz = smd_cur_packet_size(smd_pkt_devp->ch); + if (sz == 0) { + D_READ("%s: No packet in smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + return; + } + if (!smd_read_avail(smd_pkt_devp->ch)) { + D_READ( + "%s: packet size is %d in smd_pkt_dev id:%d - but the data isn't here\n", + __func__, sz, smd_pkt_devp->i); + return; + } + + /* here we have a packet of size sz ready */ + spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags); + __pm_stay_awake(&smd_pkt_devp->pa_ws); + smd_pkt_devp->ws_locked = 1; + spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags); + wake_up(&smd_pkt_devp->ch_read_wait_queue); + schedule_work(&smd_pkt_devp->packet_arrival_work); + D_READ("%s: wake_up smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i); +} + +static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp) +{ + int sz; + + if (!smd_pkt_devp) { + pr_err("%s on a NULL device\n", __func__); + return; + } + + if (!smd_pkt_devp->ch) { + pr_err("%s on a closed smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + return; + } + + sz = smd_write_segment_avail(smd_pkt_devp->ch); + if (sz) { + D_WRITE("%s: %d bytes write space in smd_pkt_dev id:%d\n", + __func__, sz, smd_pkt_devp->i); + smd_disable_read_intr(smd_pkt_devp->ch); + wake_up(&smd_pkt_devp->ch_write_wait_queue); + } +} + +static void ch_notify(void *priv, unsigned int event) +{ + struct smd_pkt_dev *smd_pkt_devp = priv; + + if (smd_pkt_devp->ch == 0) { + if (event != SMD_EVENT_CLOSE) + pr_err("%s on a closed smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + return; + } + + switch (event) { + case SMD_EVENT_DATA: { + D_STATUS("%s: DATA event in smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + check_and_wakeup_reader(smd_pkt_devp); + if (smd_pkt_devp->blocking_write) + check_and_wakeup_writer(smd_pkt_devp); + break; + } + case SMD_EVENT_OPEN: + D_STATUS("%s: OPEN event in smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + smd_pkt_devp->has_reset = 0; + smd_pkt_devp->is_open = 1; + wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue); + break; + case SMD_EVENT_CLOSE: + D_STATUS("%s: CLOSE event in smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + smd_pkt_devp->is_open = 0; + /* put port into reset state */ + clean_and_signal(smd_pkt_devp); + if (!strcmp(smd_pkt_devp->ch_name, "LOOPBACK")) + schedule_delayed_work(&loopback_work, + msecs_to_jiffies(1000)); + break; + } +} + +static int smd_pkt_dummy_probe(struct platform_device *pdev) +{ + struct smd_pkt_dev *smd_pkt_devp; + + mutex_lock(&smd_pkt_dev_lock_lha1); + list_for_each_entry(smd_pkt_devp, &smd_pkt_dev_list, dev_list) { + if (smd_pkt_devp->edge == pdev->id + && !strcmp(pdev->name, smd_pkt_devp->ch_name)) { + complete_all(&smd_pkt_devp->ch_allocated); + D_STATUS("%s allocated SMD ch for smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + break; + } + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + return 0; +} + +static uint32_t is_modem_smsm_inited(void) +{ + uint32_t modem_state; + uint32_t ready_state = (SMSM_INIT | SMSM_SMDINIT); + + modem_state = smsm_get_state(SMSM_MODEM_STATE); + return (modem_state & ready_state) == ready_state; +} + +/** + * smd_pkt_add_driver() - Add platform drivers for smd pkt device + * + * @smd_pkt_devp: pointer to the smd pkt device structure + * + * @returns: 0 for success, standard Linux error code otherwise + * + * This function is used to register platform driver once for all + * smd pkt devices which have same names and increment the reference + * count for 2nd to nth devices. + */ +static int smd_pkt_add_driver(struct smd_pkt_dev *smd_pkt_devp) +{ + int r = 0; + struct smd_pkt_driver *smd_pkt_driverp; + struct smd_pkt_driver *item; + + if (!smd_pkt_devp) { + pr_err("%s on a NULL device\n", __func__); + return -EINVAL; + } + D_STATUS("Begin %s on smd_pkt_ch[%s]\n", __func__, + smd_pkt_devp->ch_name); + + mutex_lock(&smd_pkt_driver_lock_lha1); + list_for_each_entry(item, &smd_pkt_driver_list, list) { + if (!strcmp(item->pdriver_name, smd_pkt_devp->ch_name)) { + D_STATUS("%s:%s Already Platform driver reg. cnt:%d\n", + __func__, smd_pkt_devp->ch_name, item->ref_cnt); + ++item->ref_cnt; + goto exit; + } + } + + smd_pkt_driverp = kzalloc(sizeof(*smd_pkt_driverp), GFP_KERNEL); + if (IS_ERR_OR_NULL(smd_pkt_driverp)) { + pr_err("%s: kzalloc() failed for smd_pkt_driver[%s]\n", + __func__, smd_pkt_devp->ch_name); + r = -ENOMEM; + goto exit; + } + + smd_pkt_driverp->driver.probe = smd_pkt_dummy_probe; + scnprintf(smd_pkt_driverp->pdriver_name, SMD_MAX_CH_NAME_LEN, + "%s", smd_pkt_devp->ch_name); + smd_pkt_driverp->driver.driver.name = smd_pkt_driverp->pdriver_name; + smd_pkt_driverp->driver.driver.owner = THIS_MODULE; + r = platform_driver_register(&smd_pkt_driverp->driver); + if (r) { + pr_err("%s: %s Platform driver reg. failed\n", + __func__, smd_pkt_devp->ch_name); + kfree(smd_pkt_driverp); + goto exit; + } + ++smd_pkt_driverp->ref_cnt; + list_add(&smd_pkt_driverp->list, &smd_pkt_driver_list); + +exit: + D_STATUS("End %s on smd_pkt_ch[%s]\n", __func__, smd_pkt_devp->ch_name); + mutex_unlock(&smd_pkt_driver_lock_lha1); + return r; +} + +/** + * smd_pkt_remove_driver() - Remove the platform drivers for smd pkt device + * + * @smd_pkt_devp: pointer to the smd pkt device structure + * + * This function is used to decrement the reference count on + * platform drivers for smd pkt devices and removes the drivers + * when the reference count becomes zero. + */ +static void smd_pkt_remove_driver(struct smd_pkt_dev *smd_pkt_devp) +{ + struct smd_pkt_driver *smd_pkt_driverp; + bool found_item = false; + + if (!smd_pkt_devp) { + pr_err("%s on a NULL device\n", __func__); + return; + } + + D_STATUS("Begin %s on smd_pkt_ch[%s]\n", __func__, + smd_pkt_devp->ch_name); + mutex_lock(&smd_pkt_driver_lock_lha1); + list_for_each_entry(smd_pkt_driverp, &smd_pkt_driver_list, list) { + if (!strcmp(smd_pkt_driverp->pdriver_name, + smd_pkt_devp->ch_name)) { + found_item = true; + D_STATUS("%s:%s Platform driver cnt:%d\n", + __func__, smd_pkt_devp->ch_name, + smd_pkt_driverp->ref_cnt); + if (smd_pkt_driverp->ref_cnt > 0) + --smd_pkt_driverp->ref_cnt; + else + pr_warn("%s reference count <= 0\n", __func__); + break; + } + } + if (!found_item) + pr_err("%s:%s No item found in list.\n", + __func__, smd_pkt_devp->ch_name); + + if (found_item && smd_pkt_driverp->ref_cnt == 0) { + platform_driver_unregister(&smd_pkt_driverp->driver); + smd_pkt_driverp->driver.probe = NULL; + list_del(&smd_pkt_driverp->list); + kfree(smd_pkt_driverp); + } + mutex_unlock(&smd_pkt_driver_lock_lha1); + D_STATUS("End %s on smd_pkt_ch[%s]\n", __func__, smd_pkt_devp->ch_name); +} + +int smd_pkt_open(struct inode *inode, struct file *file) +{ + int r = 0; + struct smd_pkt_dev *smd_pkt_devp; + const char *peripheral = NULL; + + smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev); + + if (!smd_pkt_devp) { + pr_err_ratelimited("%s on a NULL device\n", __func__); + return -EINVAL; + } + D_STATUS("Begin %s on smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i); + + file->private_data = smd_pkt_devp; + + mutex_lock(&smd_pkt_devp->ch_lock); + if (smd_pkt_devp->ch == 0) { + unsigned int open_wait_rem; + + open_wait_rem = smd_pkt_devp->open_modem_wait * 1000; + reinit_completion(&smd_pkt_devp->ch_allocated); + + r = smd_pkt_add_driver(smd_pkt_devp); + if (r) { + pr_err_ratelimited("%s: %s Platform driver reg. failed\n", + __func__, smd_pkt_devp->ch_name); + goto out; + } + + peripheral = smd_edge_to_pil_str(smd_pkt_devp->edge); + if (!IS_ERR_OR_NULL(peripheral)) { + smd_pkt_devp->pil = subsystem_get(peripheral); + if (IS_ERR(smd_pkt_devp->pil)) { + r = PTR_ERR(smd_pkt_devp->pil); + pr_err_ratelimited("%s failed on smd_pkt_dev id:%d - subsystem_get failed for %s\n", + __func__, smd_pkt_devp->i, peripheral); + /* + * Sleep inorder to reduce the frequency of + * retry by user-space modules and to avoid + * possible watchdog bite. + */ + msleep(open_wait_rem); + goto release_pd; + } + } + + /* Wait for the modem SMSM to be inited for the SMD + ** Loopback channel to be allocated at the modem. Since + ** the wait need to be done atmost once, using msleep + ** doesn't degrade the performance. + */ + if (!strcmp(smd_pkt_devp->ch_name, "LOOPBACK")) { + if (!is_modem_smsm_inited()) + msleep(5000); + smsm_change_state(SMSM_APPS_STATE, + 0, SMSM_SMD_LOOPBACK); + msleep(100); + } + + /* + * Wait for a packet channel to be allocated so we know + * the modem is ready enough. + */ + if (open_wait_rem) { + r = wait_for_completion_interruptible_timeout( + &smd_pkt_devp->ch_allocated, + msecs_to_jiffies(open_wait_rem)); + if (r >= 0) + open_wait_rem = jiffies_to_msecs(r); + if (r == 0) + r = -ETIMEDOUT; + if (r == -ERESTARTSYS) { + pr_info_ratelimited("%s: wait on smd_pkt_dev id:%d allocation interrupted\n", + __func__, smd_pkt_devp->i); + goto release_pil; + } + if (r < 0) { + pr_err_ratelimited("%s: wait on smd_pkt_dev id:%d allocation failed rc:%d\n", + __func__, smd_pkt_devp->i, r); + goto release_pil; + } + } + + r = smd_named_open_on_edge(smd_pkt_devp->ch_name, + smd_pkt_devp->edge, + &smd_pkt_devp->ch, + smd_pkt_devp, + ch_notify); + if (r < 0) { + pr_err_ratelimited("%s: %s open failed %d\n", __func__, + smd_pkt_devp->ch_name, r); + goto release_pil; + } + + open_wait_rem = max_t(unsigned int, 2000, open_wait_rem); + r = wait_event_interruptible_timeout( + smd_pkt_devp->ch_opened_wait_queue, + smd_pkt_devp->is_open, + msecs_to_jiffies(open_wait_rem)); + if (r == 0) + r = -ETIMEDOUT; + + if (r < 0) { + /* close the ch to sync smd's state with smd_pkt */ + smd_close(smd_pkt_devp->ch); + smd_pkt_devp->ch = NULL; + } + + if (r == -ERESTARTSYS) { + pr_info_ratelimited("%s: wait on smd_pkt_dev id:%d OPEN interrupted\n", + __func__, smd_pkt_devp->i); + } else if (r < 0) { + pr_err_ratelimited("%s: wait on smd_pkt_dev id:%d OPEN event failed rc:%d\n", + __func__, smd_pkt_devp->i, r); + } else if (!smd_pkt_devp->is_open) { + pr_err_ratelimited("%s: Invalid OPEN event on smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + r = -ENODEV; + } else { + smd_disable_read_intr(smd_pkt_devp->ch); + smd_pkt_devp->ch_size = + smd_write_avail(smd_pkt_devp->ch); + r = 0; + smd_pkt_devp->ref_cnt++; + D_STATUS("Finished %s on smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + } + } else { + smd_pkt_devp->ref_cnt++; + } +release_pil: + if (peripheral && (r < 0)) { + subsystem_put(smd_pkt_devp->pil); + smd_pkt_devp->pil = NULL; + } + +release_pd: + if (r < 0) + smd_pkt_remove_driver(smd_pkt_devp); +out: + mutex_unlock(&smd_pkt_devp->ch_lock); + + + return r; +} + +int smd_pkt_release(struct inode *inode, struct file *file) +{ + int r = 0; + struct smd_pkt_dev *smd_pkt_devp = file->private_data; + unsigned long flags; + + if (!smd_pkt_devp) { + pr_err_ratelimited("%s on a NULL device\n", __func__); + return -EINVAL; + } + D_STATUS("Begin %s on smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + + mutex_lock(&smd_pkt_devp->ch_lock); + mutex_lock(&smd_pkt_devp->rx_lock); + mutex_lock(&smd_pkt_devp->tx_lock); + if (smd_pkt_devp->ref_cnt > 0) + smd_pkt_devp->ref_cnt--; + + if (smd_pkt_devp->ch != 0 && smd_pkt_devp->ref_cnt == 0) { + clean_and_signal(smd_pkt_devp); + r = smd_close(smd_pkt_devp->ch); + smd_pkt_devp->ch = 0; + smd_pkt_devp->blocking_write = 0; + smd_pkt_devp->poll_mode = 0; + smd_pkt_remove_driver(smd_pkt_devp); + if (smd_pkt_devp->pil) + subsystem_put(smd_pkt_devp->pil); + smd_pkt_devp->has_reset = 0; + smd_pkt_devp->do_reset_notification = 0; + spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags); + if (smd_pkt_devp->ws_locked) { + __pm_relax(&smd_pkt_devp->pa_ws); + smd_pkt_devp->ws_locked = 0; + } + spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags); + } + mutex_unlock(&smd_pkt_devp->tx_lock); + mutex_unlock(&smd_pkt_devp->rx_lock); + mutex_unlock(&smd_pkt_devp->ch_lock); + + if (flush_work(&smd_pkt_devp->packet_arrival_work)) + D_STATUS("%s: Flushed work for smd_pkt_dev id:%d\n", __func__, + smd_pkt_devp->i); + + D_STATUS("Finished %s on smd_pkt_dev id:%d\n", + __func__, smd_pkt_devp->i); + + return r; +} + +static const struct file_operations smd_pkt_fops = { + .owner = THIS_MODULE, + .open = smd_pkt_open, + .release = smd_pkt_release, + .read = smd_pkt_read, + .write = smd_pkt_write, + .poll = smd_pkt_poll, + .unlocked_ioctl = smd_pkt_ioctl, + .compat_ioctl = smd_pkt_ioctl, +}; + +static int smd_pkt_init_add_device(struct smd_pkt_dev *smd_pkt_devp, int i) +{ + int r = 0; + + smd_pkt_devp->i = i; + + init_waitqueue_head(&smd_pkt_devp->ch_read_wait_queue); + init_waitqueue_head(&smd_pkt_devp->ch_write_wait_queue); + smd_pkt_devp->is_open = 0; + smd_pkt_devp->poll_mode = 0; + smd_pkt_devp->ws_locked = 0; + init_waitqueue_head(&smd_pkt_devp->ch_opened_wait_queue); + + spin_lock_init(&smd_pkt_devp->pa_spinlock); + mutex_init(&smd_pkt_devp->ch_lock); + mutex_init(&smd_pkt_devp->rx_lock); + mutex_init(&smd_pkt_devp->tx_lock); + wakeup_source_init(&smd_pkt_devp->pa_ws, smd_pkt_devp->dev_name); + INIT_WORK(&smd_pkt_devp->packet_arrival_work, packet_arrival_worker); + init_completion(&smd_pkt_devp->ch_allocated); + + cdev_init(&smd_pkt_devp->cdev, &smd_pkt_fops); + smd_pkt_devp->cdev.owner = THIS_MODULE; + + r = cdev_add(&smd_pkt_devp->cdev, (smd_pkt_number + i), 1); + if (r) { + pr_err("%s: cdev_add() failed for smd_pkt_dev id:%d ret:%i\n", + __func__, i, r); + return r; + } + + smd_pkt_devp->devicep = + device_create(smd_pkt_classp, + NULL, + (smd_pkt_number + i), + NULL, + smd_pkt_devp->dev_name); + + if (IS_ERR_OR_NULL(smd_pkt_devp->devicep)) { + pr_err("%s: device_create() failed for smd_pkt_dev id:%d\n", + __func__, i); + r = -ENOMEM; + cdev_del(&smd_pkt_devp->cdev); + wakeup_source_trash(&smd_pkt_devp->pa_ws); + return r; + } + if (device_create_file(smd_pkt_devp->devicep, + &dev_attr_open_timeout)) + pr_err("%s: unable to create device attr for smd_pkt_dev id:%d\n", + __func__, i); + + if (!strcmp(smd_pkt_devp->ch_name, "LOOPBACK")) { + if (device_create_file(smd_pkt_devp->devicep, + &dev_attr_loopback_edge)) + pr_err("%s: unable to create device attr for smd_pkt_dev id:%d\n", + __func__, i); + } + mutex_lock(&smd_pkt_dev_lock_lha1); + list_add(&smd_pkt_devp->dev_list, &smd_pkt_dev_list); + mutex_unlock(&smd_pkt_dev_lock_lha1); + + return r; +} + +static void smd_pkt_core_deinit(void) +{ + struct smd_pkt_dev *smd_pkt_devp; + struct smd_pkt_dev *index; + + mutex_lock(&smd_pkt_dev_lock_lha1); + list_for_each_entry_safe(smd_pkt_devp, index, &smd_pkt_dev_list, + dev_list) { + cdev_del(&smd_pkt_devp->cdev); + list_del(&smd_pkt_devp->dev_list); + device_destroy(smd_pkt_classp, + MKDEV(MAJOR(smd_pkt_number), smd_pkt_devp->i)); + kfree(smd_pkt_devp); + } + mutex_unlock(&smd_pkt_dev_lock_lha1); + + if (!IS_ERR_OR_NULL(smd_pkt_classp)) + class_destroy(smd_pkt_classp); + + unregister_chrdev_region(MAJOR(smd_pkt_number), num_smd_pkt_ports); +} + +static int smd_pkt_alloc_chrdev_region(void) +{ + int r = alloc_chrdev_region(&smd_pkt_number, + 0, + num_smd_pkt_ports, + DEVICE_NAME); + + if (r) { + pr_err("%s: alloc_chrdev_region() failed ret:%i\n", + __func__, r); + return r; + } + + smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(smd_pkt_classp)) { + pr_err("%s: class_create() failed ENOMEM\n", __func__); + r = -ENOMEM; + unregister_chrdev_region(MAJOR(smd_pkt_number), + num_smd_pkt_ports); + return r; + } + + return 0; +} + +static int parse_smdpkt_devicetree(struct device_node *node, + struct smd_pkt_dev *smd_pkt_devp) +{ + int edge; + char *key; + const char *ch_name; + const char *dev_name; + const char *remote_ss; + + key = "qcom,smdpkt-remote"; + remote_ss = of_get_property(node, key, NULL); + if (!remote_ss) + goto error; + + edge = smd_remote_ss_to_edge(remote_ss); + if (edge < 0) + goto error; + + smd_pkt_devp->edge = edge; + D_STATUS("%s: %s = %d", __func__, key, edge); + + key = "qcom,smdpkt-port-name"; + ch_name = of_get_property(node, key, NULL); + if (!ch_name) + goto error; + + strlcpy(smd_pkt_devp->ch_name, ch_name, SMD_MAX_CH_NAME_LEN); + D_STATUS("%s ch_name = %s\n", __func__, ch_name); + + key = "qcom,smdpkt-dev-name"; + dev_name = of_get_property(node, key, NULL); + if (!dev_name) + goto error; + + strlcpy(smd_pkt_devp->dev_name, dev_name, SMD_MAX_CH_NAME_LEN); + D_STATUS("%s dev_name = %s\n", __func__, dev_name); + + return 0; + +error: + pr_err("%s: missing key: %s\n", __func__, key); + return -ENODEV; + +} + +static int smd_pkt_devicetree_init(struct platform_device *pdev) +{ + int ret; + int i = 0; + struct device_node *node; + struct smd_pkt_dev *smd_pkt_devp; + int subnode_num = 0; + + for_each_child_of_node(pdev->dev.of_node, node) + ++subnode_num; + + num_smd_pkt_ports = subnode_num; + + ret = smd_pkt_alloc_chrdev_region(); + if (ret) { + pr_err("%s: smd_pkt_alloc_chrdev_region() failed ret:%i\n", + __func__, ret); + return ret; + } + + for_each_child_of_node(pdev->dev.of_node, node) { + smd_pkt_devp = kzalloc(sizeof(struct smd_pkt_dev), GFP_KERNEL); + if (IS_ERR_OR_NULL(smd_pkt_devp)) { + pr_err("%s: kzalloc() failed for smd_pkt_dev id:%d\n", + __func__, i); + ret = -ENOMEM; + goto error_destroy; + } + + ret = parse_smdpkt_devicetree(node, smd_pkt_devp); + if (ret) { + pr_err(" failed to parse_smdpkt_devicetree %d\n", i); + kfree(smd_pkt_devp); + goto error_destroy; + } + + ret = smd_pkt_init_add_device(smd_pkt_devp, i); + if (ret < 0) { + pr_err("add device failed for idx:%d ret=%d\n", i, ret); + kfree(smd_pkt_devp); + goto error_destroy; + } + i++; + } + + INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker); + + D_STATUS("SMD Packet Port Driver Initialized.\n"); + return 0; + +error_destroy: + smd_pkt_core_deinit(); + return ret; +} + +static int msm_smd_pkt_probe(struct platform_device *pdev) +{ + int ret; + + if (pdev) { + if (pdev->dev.of_node) { + D_STATUS("%s device tree implementation\n", __func__); + ret = smd_pkt_devicetree_init(pdev); + if (ret) + pr_err("%s: device tree init failed\n", + __func__); + } + } + + return 0; +} + +static const struct of_device_id msm_smd_pkt_match_table[] = { + { .compatible = "qcom,smdpkt" }, + {}, +}; + +static struct platform_driver msm_smd_pkt_driver = { + .probe = msm_smd_pkt_probe, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_smd_pkt_match_table, + }, +}; + +static int __init smd_pkt_init(void) +{ + int rc; + + INIT_LIST_HEAD(&smd_pkt_dev_list); + INIT_LIST_HEAD(&smd_pkt_driver_list); + rc = platform_driver_register(&msm_smd_pkt_driver); + if (rc) { + pr_err("%s: msm_smd_driver register failed %d\n", + __func__, rc); + return rc; + } + + smd_pkt_ilctxt = ipc_log_context_create(SMD_PKT_IPC_LOG_PAGE_CNT, + "smd_pkt", 0); + return 0; +} + +static void __exit smd_pkt_cleanup(void) +{ + smd_pkt_core_deinit(); +} + +module_init(smd_pkt_init); +module_exit(smd_pkt_cleanup); + +MODULE_DESCRIPTION("MSM Shared Memory Packet Port"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index fc061f7c2bd1f7a850f96737c00cb06ac5dd56c1..a7de8ae185a5fb3b7355866454530c3a085ac499 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -374,7 +374,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, rc = write_sync_reg(SCR_HOST_TO_READER_START, dev); if (rc <= 0) { - DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc); + DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc); DEBUGP(2, dev, "<- cm4040_write (failed)\n"); if (rc == -ERESTARTSYS) return rc; @@ -387,7 +387,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, for (i = 0; i < bytes_to_write; i++) { rc = wait_for_bulk_out_ready(dev); if (rc <= 0) { - DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n", + DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n", rc); DEBUGP(2, dev, "<- cm4040_write (failed)\n"); if (rc == -ERESTARTSYS) @@ -403,7 +403,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev); if (rc <= 0) { - DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc); + DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc); DEBUGP(2, dev, "<- cm4040_write (failed)\n"); if (rc == -ERESTARTSYS) return rc; diff --git a/drivers/char/random.c b/drivers/char/random.c index 08d1dd58c0d27996699f86e7aab29f2601d3c895..ee737ef41ce92e05240e4218579ed1ff70a0b543 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2044,8 +2044,8 @@ struct ctl_table random_table[] = { struct batched_entropy { union { - unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)]; - unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)]; + u64 entropy_u64[CHACHA20_BLOCK_SIZE / sizeof(u64)]; + u32 entropy_u32[CHACHA20_BLOCK_SIZE / sizeof(u32)]; }; unsigned int position; }; @@ -2055,52 +2055,51 @@ struct batched_entropy { * number is either as good as RDRAND or as good as /dev/urandom, with the * goal of being quite fast and not depleting entropy. */ -static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long); -unsigned long get_random_long(void) +static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64); +u64 get_random_u64(void) { - unsigned long ret; + u64 ret; struct batched_entropy *batch; - if (arch_get_random_long(&ret)) +#if BITS_PER_LONG == 64 + if (arch_get_random_long((unsigned long *)&ret)) return ret; +#else + if (arch_get_random_long((unsigned long *)&ret) && + arch_get_random_long((unsigned long *)&ret + 1)) + return ret; +#endif - batch = &get_cpu_var(batched_entropy_long); - if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) { - extract_crng((u8 *)batch->entropy_long); + batch = &get_cpu_var(batched_entropy_u64); + if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) { + extract_crng((u8 *)batch->entropy_u64); batch->position = 0; } - ret = batch->entropy_long[batch->position++]; - put_cpu_var(batched_entropy_long); + ret = batch->entropy_u64[batch->position++]; + put_cpu_var(batched_entropy_u64); return ret; } -EXPORT_SYMBOL(get_random_long); +EXPORT_SYMBOL(get_random_u64); -#if BITS_PER_LONG == 32 -unsigned int get_random_int(void) -{ - return get_random_long(); -} -#else -static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int); -unsigned int get_random_int(void) +static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32); +u32 get_random_u32(void) { - unsigned int ret; + u32 ret; struct batched_entropy *batch; if (arch_get_random_int(&ret)) return ret; - batch = &get_cpu_var(batched_entropy_int); - if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) { - extract_crng((u8 *)batch->entropy_int); + batch = &get_cpu_var(batched_entropy_u32); + if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) { + extract_crng((u8 *)batch->entropy_u32); batch->position = 0; } - ret = batch->entropy_int[batch->position++]; - put_cpu_var(batched_entropy_int); + ret = batch->entropy_u32[batch->position++]; + put_cpu_var(batched_entropy_u32); return ret; } -#endif -EXPORT_SYMBOL(get_random_int); +EXPORT_SYMBOL(get_random_u32); /** * randomize_page - Generate a random, page aligned address diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c new file mode 100644 index 0000000000000000000000000000000000000000..8612112c133b1c256522ef52f95515fa3a36d13a --- /dev/null +++ b/drivers/char/rdbg.c @@ -0,0 +1,1175 @@ +/* + * Copyright (c) 2013-2017, 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define SMP2P_NUM_PROCS 16 +#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*/ + {"rdbg_cdsp", SMEM_LC_DEBUGGER, 16*1024}, /*CDSP*/ + {NULL}, /*SMP2P_POWER_PROC*/ + {NULL}, /*SMP2P_TZ_PROC*/ + {NULL}, /*EMPTY*/ + {NULL}, /*EMPTY*/ + {NULL}, /*EMPTY*/ + {NULL}, /*EMPTY*/ + {NULL}, /*EMPTY*/ + {NULL}, /*EMPTY*/ + {NULL}, /*EMPTY*/ + {NULL} /*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/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e5950131bd907dbee3f4b4c3598c05572fcea416..9ff8532299570315aa1fd7f366d30bd4020e98b6 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -130,6 +130,41 @@ static void tpm_dev_release(struct device *dev) kfree(chip); } + +/** + * tpm_class_shutdown() - prepare the TPM device for loss of power. + * @dev: device to which the chip is associated. + * + * Issues a TPM2_Shutdown command prior to loss of power, as required by the + * TPM 2.0 spec. + * Then, calls bus- and device- specific shutdown code. + * + * XXX: This codepath relies on the fact that sysfs is not enabled for + * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2 + * has sysfs support enabled before TPM sysfs's implicit locking is fixed. + */ +static int tpm_class_shutdown(struct device *dev) +{ + struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + down_write(&chip->ops_sem); + tpm2_shutdown(chip, TPM2_SU_CLEAR); + chip->ops = NULL; + up_write(&chip->ops_sem); + } + /* Allow bus- and device-specific code to run. Note: since chip->ops + * is NULL, more-specific shutdown code will not be able to issue TPM + * commands. + */ + if (dev->bus && dev->bus->shutdown) + dev->bus->shutdown(dev); + else if (dev->driver && dev->driver->shutdown) + dev->driver->shutdown(dev); + return 0; +} + + /** * tpm_chip_alloc() - allocate a new struct tpm_chip instance * @pdev: device to which the chip is associated @@ -140,7 +175,7 @@ static void tpm_dev_release(struct device *dev) * Allocates a new struct tpm_chip instance and assigns a free * device number for it. Must be paired with put_device(&chip->dev). */ -struct tpm_chip *tpm_chip_alloc(struct device *dev, +struct tpm_chip *tpm_chip_alloc(struct device *pdev, const struct tpm_class_ops *ops) { struct tpm_chip *chip; @@ -159,7 +194,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL); mutex_unlock(&idr_lock); if (rc < 0) { - dev_err(dev, "No available tpm device numbers\n"); + dev_err(pdev, "No available tpm device numbers\n"); kfree(chip); return ERR_PTR(rc); } @@ -168,8 +203,9 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, device_initialize(&chip->dev); chip->dev.class = tpm_class; + chip->dev.class->shutdown = tpm_class_shutdown; chip->dev.release = tpm_dev_release; - chip->dev.parent = dev; + chip->dev.parent = pdev; chip->dev.groups = chip->groups; if (chip->dev_num == 0) @@ -181,7 +217,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, if (rc) goto out; - if (!dev) + if (!pdev) chip->flags |= TPM_CHIP_FLAG_VIRTUAL; cdev_init(&chip->cdev, &tpm_fops); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3a9149cf011048f21fa742785c9ff0b6f9da6c0b..d0ac2d56520f3c6050bcca97285d3b2a78285ac3 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -489,8 +489,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) int tpm_get_timeouts(struct tpm_chip *chip) { struct tpm_cmd_t tpm_cmd; - unsigned long new_timeout[4]; - unsigned long old_timeout[4]; + unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4]; struct duration_t *duration_cap; ssize_t rc; @@ -542,11 +541,15 @@ int tpm_get_timeouts(struct tpm_chip *chip) != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) return -EINVAL; - old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); - old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); - old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); - old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); - memcpy(new_timeout, old_timeout, sizeof(new_timeout)); + timeout_old[0] = jiffies_to_usecs(chip->timeout_a); + timeout_old[1] = jiffies_to_usecs(chip->timeout_b); + timeout_old[2] = jiffies_to_usecs(chip->timeout_c); + timeout_old[3] = jiffies_to_usecs(chip->timeout_d); + timeout_chip[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); + timeout_chip[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); + timeout_chip[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); + timeout_chip[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); + memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff)); /* * Provide ability for vendor overrides of timeout values in case @@ -554,16 +557,24 @@ int tpm_get_timeouts(struct tpm_chip *chip) */ if (chip->ops->update_timeouts != NULL) chip->timeout_adjusted = - chip->ops->update_timeouts(chip, new_timeout); + chip->ops->update_timeouts(chip, timeout_eff); if (!chip->timeout_adjusted) { - /* Don't overwrite default if value is 0 */ - if (new_timeout[0] != 0 && new_timeout[0] < 1000) { - int i; + /* Restore default if chip reported 0 */ + int i; + for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) { + if (timeout_eff[i]) + continue; + + timeout_eff[i] = timeout_old[i]; + chip->timeout_adjusted = true; + } + + if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) { /* timeouts in msec rather usec */ - for (i = 0; i != ARRAY_SIZE(new_timeout); i++) - new_timeout[i] *= 1000; + for (i = 0; i != ARRAY_SIZE(timeout_eff); i++) + timeout_eff[i] *= 1000; chip->timeout_adjusted = true; } } @@ -572,16 +583,16 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (chip->timeout_adjusted) { dev_info(&chip->dev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", - old_timeout[0], new_timeout[0], - old_timeout[1], new_timeout[1], - old_timeout[2], new_timeout[2], - old_timeout[3], new_timeout[3]); + timeout_chip[0], timeout_eff[0], + timeout_chip[1], timeout_eff[1], + timeout_chip[2], timeout_eff[2], + timeout_chip[3], timeout_eff[3]); } - chip->timeout_a = usecs_to_jiffies(new_timeout[0]); - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); + chip->timeout_a = usecs_to_jiffies(timeout_eff[0]); + chip->timeout_b = usecs_to_jiffies(timeout_eff[1]); + chip->timeout_c = usecs_to_jiffies(timeout_eff[2]); + chip->timeout_d = usecs_to_jiffies(timeout_eff[3]); duration: tpm_cmd.header.in = tpm_getcap_header; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index a76ab4af9fb22f863446be1383e4a60d006cf481..edf8c59a6ed47cf7daafb39673e139b717bb77d0 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -35,9 +35,10 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ssize_t err; int i, rc; char *str = buf; - struct tpm_chip *chip = to_tpm_chip(dev); + memset(&tpm_cmd, 0, sizeof(tpm_cmd)); + tpm_cmd.header.in = tpm_readpubek_header; err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0, "attempting to read the PUBEK"); @@ -284,6 +285,11 @@ static const struct attribute_group tpm_dev_group = { void tpm_sysfs_add_device(struct tpm_chip *chip) { + /* XXX: If you wish to remove this restriction, you must first update + * tpm_sysfs to explicitly lock chip->ops. + */ + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return; /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del * is called before ops is null'd and the sysfs core synchronizes this * removal so that no callbacks are running or can run again diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 4d183c97f6a6bce33fb2494276de3cbef1a393c9..aa4299cf7e5aa48dee72afd2c1fbef3708b0f4d5 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -518,6 +518,11 @@ static inline void tpm_add_ppi(struct tpm_chip *chip) } #endif +static inline inline u32 tpm2_rc_value(u32 rc) +{ + return (rc & BIT(7)) ? rc & 0xff : rc; +} + int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 7df55d58c93904374ea0faf9bceaf59cfeb6ccd4..17896d65403343dcf7fc6a4665ec51e65b07bbc8 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -529,7 +529,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, tpm_buf_destroy(&buf); if (rc > 0) { - if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH) + if (tpm2_rc_value(rc) == TPM2_RC_HASH) rc = -EINVAL; else rc = -EPERM; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index a7c870af916c3d68df408b802299995a2f15007e..fa0f66809503196943e70c59424683261cdb405f 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -111,8 +111,7 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) memcpy_fromio(buf, priv->rsp, 6); expected = be32_to_cpup((__be32 *) &buf[2]); - - if (expected > count) + if (expected > count || expected < 6) return -EIO; memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index e3a9155ee671ff3b0348a1c9ac28cfb4692eacb1..c6428771841f814a891719fab16e92d7e0723fc7 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -49,9 +49,10 @@ */ #define TPM_I2C_MAX_BUF_SIZE 32 #define TPM_I2C_RETRY_COUNT 32 -#define TPM_I2C_BUS_DELAY 1 /* msec */ -#define TPM_I2C_RETRY_DELAY_SHORT 2 /* msec */ -#define TPM_I2C_RETRY_DELAY_LONG 10 /* msec */ +#define TPM_I2C_BUS_DELAY 1000 /* usec */ +#define TPM_I2C_RETRY_DELAY_SHORT (2 * 1000) /* usec */ +#define TPM_I2C_RETRY_DELAY_LONG (10 * 1000) /* usec */ +#define TPM_I2C_DELAY_RANGE 300 /* usec */ #define OF_IS_TPM2 ((void *)1) #define I2C_IS_TPM2 1 @@ -123,7 +124,9 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) /* this causes the current command to be aborted */ for (i = 0, status = -1; i < TPM_I2C_RETRY_COUNT && status < 0; i++) { status = i2c_nuvoton_write_buf(client, TPM_STS, 1, &data); - msleep(TPM_I2C_BUS_DELAY); + if (status < 0) + usleep_range(TPM_I2C_BUS_DELAY, TPM_I2C_BUS_DELAY + + TPM_I2C_DELAY_RANGE); } return status; } @@ -160,7 +163,8 @@ static int i2c_nuvoton_get_burstcount(struct i2c_client *client, burst_count = min_t(u8, TPM_I2C_MAX_BUF_SIZE, data); break; } - msleep(TPM_I2C_BUS_DELAY); + usleep_range(TPM_I2C_BUS_DELAY, TPM_I2C_BUS_DELAY + + TPM_I2C_DELAY_RANGE); } while (time_before(jiffies, stop)); return burst_count; @@ -203,13 +207,17 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, return 0; /* use polling to wait for the event */ - ten_msec = jiffies + msecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG); + ten_msec = jiffies + usecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG); stop = jiffies + timeout; do { if (time_before(jiffies, ten_msec)) - msleep(TPM_I2C_RETRY_DELAY_SHORT); + usleep_range(TPM_I2C_RETRY_DELAY_SHORT, + TPM_I2C_RETRY_DELAY_SHORT + + TPM_I2C_DELAY_RANGE); else - msleep(TPM_I2C_RETRY_DELAY_LONG); + usleep_range(TPM_I2C_RETRY_DELAY_LONG, + TPM_I2C_RETRY_DELAY_LONG + + TPM_I2C_DELAY_RANGE); status_valid = i2c_nuvoton_check_status(chip, mask, value); if (status_valid) diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 946025a7413b6b6e771e54a66a7bb42d75ed803e..84eca4f93b82852ebcd5d5d297cb0fa373c937aa 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -295,6 +295,8 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) } kfree(ibmvtpm); + /* For tpm_ibmvtpm_get_desired_dma */ + dev_set_drvdata(&vdev->dev, NULL); return 0; } @@ -309,13 +311,16 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) { struct tpm_chip *chip = dev_get_drvdata(&vdev->dev); - struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); + struct ibmvtpm_dev *ibmvtpm; - /* ibmvtpm initializes at probe time, so the data we are - * asking for may not be set yet. Estimate that 4K required - * for TCE-mapped buffer in addition to CRQ. - */ - if (!ibmvtpm) + /* + * ibmvtpm initializes at probe time, so the data we are + * asking for may not be set yet. Estimate that 4K required + * for TCE-mapped buffer in addition to CRQ. + */ + if (chip) + ibmvtpm = dev_get_drvdata(&chip->dev); + else return CRQ_RES_BUF_SIZE + PAGE_SIZE; return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index a1ce0607bf7b450bd64d1101e44bd60368bbb0d7..4d24ec3d7cd67fb4ede78deddeda3451ba2acfba 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -160,8 +160,10 @@ static int get_burstcount(struct tpm_chip *chip) u32 value; /* wait for burstcount */ - /* which timeout value, spec has 2 answers (c & d) */ - stop = jiffies + chip->timeout_d; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + stop = jiffies + chip->timeout_a; + else + stop = jiffies + chip->timeout_d; do { rc = tpm_tis_read32(priv, TPM_STS(priv->locality), &value); if (rc < 0) diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index dbaad9c681e37c119831a63d20b71c43ac7078d2..3b97b14c3417e085d917126d86a437192e73d251 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -48,8 +48,8 @@ struct tpm_tis_spi_phy { struct tpm_tis_data priv; struct spi_device *spi_device; - u8 tx_buf[MAX_SPI_FRAMESIZE + 4]; - u8 rx_buf[MAX_SPI_FRAMESIZE + 4]; + u8 tx_buf[4]; + u8 rx_buf[4]; }; static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data) @@ -57,122 +57,98 @@ static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *da return container_of(data, struct tpm_tis_spi_phy, priv); } -static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr, - u16 len, u8 *result) +static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, + u8 *buffer, u8 direction) { struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data); - int ret, i; + int ret = 0; + int i; struct spi_message m; - struct spi_transfer spi_xfer = { - .tx_buf = phy->tx_buf, - .rx_buf = phy->rx_buf, - .len = 4, - }; + struct spi_transfer spi_xfer; + u8 transfer_len; - if (len > MAX_SPI_FRAMESIZE) - return -ENOMEM; + spi_bus_lock(phy->spi_device->master); - phy->tx_buf[0] = 0x80 | (len - 1); - phy->tx_buf[1] = 0xd4; - phy->tx_buf[2] = (addr >> 8) & 0xFF; - phy->tx_buf[3] = addr & 0xFF; + while (len) { + transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE); - spi_xfer.cs_change = 1; - spi_message_init(&m); - spi_message_add_tail(&spi_xfer, &m); + phy->tx_buf[0] = direction | (transfer_len - 1); + phy->tx_buf[1] = 0xd4; + phy->tx_buf[2] = addr >> 8; + phy->tx_buf[3] = addr; + + memset(&spi_xfer, 0, sizeof(spi_xfer)); + spi_xfer.tx_buf = phy->tx_buf; + spi_xfer.rx_buf = phy->rx_buf; + spi_xfer.len = 4; + spi_xfer.cs_change = 1; - spi_bus_lock(phy->spi_device->master); - ret = spi_sync_locked(phy->spi_device, &m); - if (ret < 0) - goto exit; - - memset(phy->tx_buf, 0, len); - - /* According to TCG PTP specification, if there is no TPM present at - * all, then the design has a weak pull-up on MISO. If a TPM is not - * present, a pull-up on MISO means that the SB controller sees a 1, - * and will latch in 0xFF on the read. - */ - for (i = 0; (phy->rx_buf[0] & 0x01) == 0 && i < TPM_RETRY; i++) { - spi_xfer.len = 1; spi_message_init(&m); spi_message_add_tail(&spi_xfer, &m); ret = spi_sync_locked(phy->spi_device, &m); if (ret < 0) goto exit; - } - - spi_xfer.cs_change = 0; - spi_xfer.len = len; - spi_xfer.rx_buf = result; - - spi_message_init(&m); - spi_message_add_tail(&spi_xfer, &m); - ret = spi_sync_locked(phy->spi_device, &m); - -exit: - spi_bus_unlock(phy->spi_device->master); - return ret; -} - -static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, - u16 len, u8 *value) -{ - struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data); - int ret, i; - struct spi_message m; - struct spi_transfer spi_xfer = { - .tx_buf = phy->tx_buf, - .rx_buf = phy->rx_buf, - .len = 4, - }; - - if (len > MAX_SPI_FRAMESIZE) - return -ENOMEM; - - phy->tx_buf[0] = len - 1; - phy->tx_buf[1] = 0xd4; - phy->tx_buf[2] = (addr >> 8) & 0xFF; - phy->tx_buf[3] = addr & 0xFF; - spi_xfer.cs_change = 1; - spi_message_init(&m); - spi_message_add_tail(&spi_xfer, &m); + if ((phy->rx_buf[3] & 0x01) == 0) { + // handle SPI wait states + phy->tx_buf[0] = 0; + + for (i = 0; i < TPM_RETRY; i++) { + spi_xfer.len = 1; + spi_message_init(&m); + spi_message_add_tail(&spi_xfer, &m); + ret = spi_sync_locked(phy->spi_device, &m); + if (ret < 0) + goto exit; + if (phy->rx_buf[0] & 0x01) + break; + } + + if (i == TPM_RETRY) { + ret = -ETIMEDOUT; + goto exit; + } + } + + spi_xfer.cs_change = 0; + spi_xfer.len = transfer_len; + spi_xfer.delay_usecs = 5; + + if (direction) { + spi_xfer.tx_buf = NULL; + spi_xfer.rx_buf = buffer; + } else { + spi_xfer.tx_buf = buffer; + spi_xfer.rx_buf = NULL; + } - spi_bus_lock(phy->spi_device->master); - ret = spi_sync_locked(phy->spi_device, &m); - if (ret < 0) - goto exit; - - memset(phy->tx_buf, 0, len); - - /* According to TCG PTP specification, if there is no TPM present at - * all, then the design has a weak pull-up on MISO. If a TPM is not - * present, a pull-up on MISO means that the SB controller sees a 1, - * and will latch in 0xFF on the read. - */ - for (i = 0; (phy->rx_buf[0] & 0x01) == 0 && i < TPM_RETRY; i++) { - spi_xfer.len = 1; spi_message_init(&m); spi_message_add_tail(&spi_xfer, &m); ret = spi_sync_locked(phy->spi_device, &m); if (ret < 0) goto exit; - } - spi_xfer.len = len; - spi_xfer.tx_buf = value; - spi_xfer.cs_change = 0; - spi_xfer.tx_buf = value; - spi_message_init(&m); - spi_message_add_tail(&spi_xfer, &m); - ret = spi_sync_locked(phy->spi_device, &m); + len -= transfer_len; + buffer += transfer_len; + } exit: spi_bus_unlock(phy->spi_device->master); return ret; } +static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr, + u16 len, u8 *result) +{ + return tpm_tis_spi_transfer(data, addr, len, result, 0x80); +} + +static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, + u16 len, u8 *value) +{ + return tpm_tis_spi_transfer(data, addr, len, value, 0); +} + static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result) { int rc; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 471a301d63e33bd2a8910c195f716f959b8a77cd..8f890c1aca577fe7a950a1b35d61cd8ee6d8bf8c 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1870,7 +1870,7 @@ static void config_work_handler(struct work_struct *work) { struct ports_device *portdev; - portdev = container_of(work, struct ports_device, control_work); + portdev = container_of(work, struct ports_device, config_work); if (!use_multiport(portdev)) { struct virtio_device *vdev; struct port *port; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 6a8ac04bedebdf13c2a2d1ff9c6e4543d7cc792b..f9cc7c8551ccbabc669e59d925a8e6a906aef9f3 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -212,3 +212,5 @@ source "drivers/clk/ti/Kconfig" source "drivers/clk/uniphier/Kconfig" endmenu + +source "drivers/clk/msm/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 925081ec14c04935e1eb17bf2709640c7ae3ae10..4fdbebbd9a71ff85677f4616de5521aa72b0f026 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,7 +1,7 @@ # common clock types obj-$(CONFIG_HAVE_CLK) += clk-devres.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_OF) += clk.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o @@ -87,6 +87,9 @@ obj-y += ti/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ +ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_X86) += x86/ +endif obj-$(CONFIG_ARCH_ZX) += zte/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/ +obj-$(CONFIG_ARCH_QCOM) += msm/ diff --git a/drivers/clk/axs10x/i2s_pll_clock.c b/drivers/clk/axs10x/i2s_pll_clock.c index 411310d295816cb3ef645edb7562689e83ff141a..02d3bcd6216cbac49ea584a0e205c6d664c58ce7 100644 --- a/drivers/clk/axs10x/i2s_pll_clock.c +++ b/drivers/clk/axs10x/i2s_pll_clock.c @@ -182,6 +182,7 @@ static int i2s_pll_clk_probe(struct platform_device *pdev) if (IS_ERR(pll_clk->base)) return PTR_ERR(pll_clk->base); + memset(&init, 0, sizeof(init)); clk_name = node->name; init.name = clk_name; init.ops = &i2s_pll_ops; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 3d6754e74f6949e4e81760e48f6856a6631e840a..3e131863787bf74e526d169e3d8ef66d1e80f749 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -258,6 +258,9 @@ static bool _is_best_div(unsigned long rate, unsigned long now, { if (flags & CLK_DIVIDER_ROUND_CLOSEST) return abs(rate - now) < abs(rate - best); + else if (flags & CLK_DIVIDER_ROUND_KHZ) + return (DIV_ROUND_CLOSEST(abs(rate - now), 1000) + < DIV_ROUND_CLOSEST(abs(rate - best), 1000)); return now <= rate && now > best; } @@ -280,10 +283,14 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, const struct clk_div_table *table, u8 width, unsigned long flags) { + struct clk_hw *parent = clk_hw_get_parent(hw); int i, bestdiv = 0; unsigned long parent_rate, best = 0, now, maxdiv; unsigned long parent_rate_saved = *best_parent_rate; + if (!parent) + return -EINVAL; + if (!rate) rate = 1; @@ -314,8 +321,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, *best_parent_rate = parent_rate_saved; return i; } - parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), - rate * i); + parent_rate = clk_hw_round_rate(parent, rate * i); now = DIV_ROUND_UP_ULL((u64)parent_rate, i); if (_is_best_div(rate, now, best, flags)) { bestdiv = i; @@ -326,7 +332,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (!bestdiv) { bestdiv = _get_maxdiv(table, width, flags); - *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1); + *best_parent_rate = clk_hw_round_rate(parent, 1); } return bestdiv; diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 2a3e9d8e88b0ed0151b513f452cf5bd2ecbcf0f5..96d37175d0ad59f47abd218db271f558c5921a4d 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -290,13 +290,15 @@ static int scpi_clocks_probe(struct platform_device *pdev) of_node_put(child); return ret; } - } - /* Add the virtual cpufreq device */ - cpufreq_dev = platform_device_register_simple("scpi-cpufreq", - -1, NULL, 0); - if (IS_ERR(cpufreq_dev)) - pr_warn("unable to register cpufreq device"); + if (match->data != &scpi_dvfs_ops) + continue; + /* Add the virtual cpufreq device if it's DVFS clock provider */ + cpufreq_dev = platform_device_register_simple("scpi-cpufreq", + -1, NULL, 0); + if (IS_ERR(cpufreq_dev)) + pr_warn("unable to register cpufreq device"); + } return 0; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index beffe356c964388d5cc1bcb5b4ac3a9885256404..020e8addb15d556d9b04399e97b10bf1664a3603 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -10,6 +10,8 @@ * Standard functionality for the common clock API. See Documentation/clk.txt */ +#define pr_fmt(fmt) "clk: " fmt + #include #include #include @@ -30,6 +32,8 @@ #include "clk.h" +#if defined(CONFIG_COMMON_CLK) + static DEFINE_SPINLOCK(enable_lock); static DEFINE_MUTEX(prepare_lock); @@ -557,7 +561,7 @@ static int clk_update_vdd(struct clk_vdd_class *vdd_class) pr_debug("Set Voltage level Min %d, Max %d\n", uv[new_base + i], uv[max_lvl + i]); rc = regulator_set_voltage(r[i], uv[new_base + i], - uv[max_lvl + i]); + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); if (rc) goto set_voltage_fail; @@ -578,11 +582,13 @@ static int clk_update_vdd(struct clk_vdd_class *vdd_class) return rc; enable_disable_fail: - regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]); + regulator_set_voltage(r[i], uv[cur_base + i], + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); set_voltage_fail: for (i--; i >= 0; i--) { - regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]); + regulator_set_voltage(r[i], uv[cur_base + i], + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels) regulator_disable(r[i]); else if (level == 0) @@ -693,6 +699,9 @@ static int clk_vdd_class_init(struct clk_vdd_class *vdd) { struct clk_handoff_vdd *v; + if (vdd->skip_handoff) + return 0; + list_for_each_entry(v, &clk_handoff_vdd_list, list) { if (v->vdd_class == vdd) return 0; @@ -1709,8 +1718,14 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, } } + /* + * The Fabia PLLs only have 16 bits to program the fractional divider. + * Hence the programmed rate might be slightly different than the + * requested one. + */ if ((core->flags & CLK_SET_RATE_PARENT) && parent && - best_parent_rate != parent->rate) + (DIV_ROUND_CLOSEST(best_parent_rate, 1000) != + DIV_ROUND_CLOSEST(parent->rate, 1000))) top = clk_calc_new_rates(parent, best_parent_rate); out: @@ -1795,6 +1810,15 @@ static int clk_change_rate(struct clk_core *core) clk_enable_unlock(flags); } + trace_clk_set_rate(core, core->new_rate); + + /* Enforce vdd requirements for new frequency. */ + if (core->prepare_count) { + rc = clk_vote_rate_vdd(core, core->new_rate); + if (rc) + goto out; + } + if (core->new_parent && core->new_parent != core->parent) { old_parent = __clk_set_parent_before(core, core->new_parent); trace_clk_set_parent(core, core->new_parent); @@ -1815,15 +1839,6 @@ static int clk_change_rate(struct clk_core *core) if (core->flags & CLK_OPS_PARENT_ENABLE) clk_core_prepare_enable(parent); - trace_clk_set_rate(core, core->new_rate); - - /* Enforce vdd requirements for new frequency. */ - if (core->prepare_count) { - rc = clk_vote_rate_vdd(core, core->new_rate); - if (rc) - goto out; - } - if (!skip_set_rate && core->ops->set_rate) { rc = core->ops->set_rate(core->hw, core->new_rate, best_parent_rate); @@ -2323,6 +2338,21 @@ int clk_set_flags(struct clk *clk, unsigned long flags) } EXPORT_SYMBOL_GPL(clk_set_flags); +unsigned long clk_list_frequency(struct clk *clk, unsigned int index) +{ + int ret = 0; + + if (!clk || !clk->core->ops->list_rate) + return -EINVAL; + + clk_prepare_lock(); + ret = clk->core->ops->list_rate(clk->core->hw, index, ULONG_MAX); + clk_prepare_unlock(); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_list_frequency); + /*** debugfs support ***/ #ifdef CONFIG_DEBUG_FS @@ -2603,7 +2633,46 @@ do { \ pr_info(fmt, ##__VA_ARGS__); \ } while (0) -int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) +/* + * clock_debug_print_enabled_debug_suspend() - Print names of enabled clocks + * during suspend. + */ +static void clock_debug_print_enabled_debug_suspend(struct seq_file *s) +{ + struct clk_core *core; + int cnt = 0; + + if (!mutex_trylock(&clk_debug_lock)) + return; + + clock_debug_output(s, 0, "Enabled clocks:\n"); + + hlist_for_each_entry(core, &clk_debug_list, debug_node) { + if (!core || !core->prepare_count) + continue; + + if (core->vdd_class) + clock_debug_output(s, 0, " %s:%u:%u [%ld, %d]", + core->name, core->prepare_count, + core->enable_count, core->rate, + clk_find_vdd_level(core, core->rate)); + + else + clock_debug_output(s, 0, " %s:%u:%u [%ld]", + core->name, core->prepare_count, + core->enable_count, core->rate); + cnt++; + } + + mutex_unlock(&clk_debug_lock); + + if (cnt) + clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt); + else + clock_debug_output(s, 0, "No clocks enabled.\n"); +} + +static int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) { char *start = ""; struct clk *clk; @@ -2645,9 +2714,10 @@ static void clock_debug_print_enabled_clocks(struct seq_file *s) struct clk_core *core; int cnt = 0; - clock_debug_output(s, 0, "Enabled clocks:\n"); + if (!mutex_trylock(&clk_debug_lock)) + return; - mutex_lock(&clk_debug_lock); + clock_debug_output(s, 0, "Enabled clocks:\n"); hlist_for_each_entry(core, &clk_debug_list, debug_node) cnt += clock_debug_print_clock(core, s); @@ -2970,14 +3040,19 @@ EXPORT_SYMBOL_GPL(clk_debugfs_add_file); /* * Print the names of all enabled clocks and their parents if - * debug_suspend is set from debugfs. + * debug_suspend is set from debugfs along with print_parent flag set to 1. + * Otherwise if print_parent set to 0, print only enabled clocks + * */ -void clock_debug_print_enabled(void) +void clock_debug_print_enabled(bool print_parent) { if (likely(!debug_suspend)) return; - clock_debug_print_enabled_clocks(NULL); + if (print_parent) + clock_debug_print_enabled_clocks(NULL); + else + clock_debug_print_enabled_debug_suspend(NULL); } EXPORT_SYMBOL_GPL(clock_debug_print_enabled); @@ -3959,6 +4034,8 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(clk_notifier_unregister); +#endif /* CONFIG_COMMON_CLK */ + #ifdef CONFIG_OF /** * struct of_clk_provider - Clock provider registration structure @@ -3996,6 +4073,8 @@ struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data) } EXPORT_SYMBOL_GPL(of_clk_hw_simple_get); +#if defined(CONFIG_COMMON_CLK) + struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data) { struct clk_onecell_data *clk_data = data; @@ -4025,6 +4104,29 @@ of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data) } EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get); +#endif /* CONFIG_COMMON_CLK */ + +/** + * of_clk_del_provider() - Remove a previously registered clock provider + * @np: Device node pointer associated with clock provider + */ +void of_clk_del_provider(struct device_node *np) +{ + struct of_clk_provider *cp; + + mutex_lock(&of_clk_mutex); + list_for_each_entry(cp, &of_clk_providers, link) { + if (cp->node == np) { + list_del(&cp->link); + of_node_put(cp->node); + kfree(cp); + break; + } + } + mutex_unlock(&of_clk_mutex); +} +EXPORT_SYMBOL_GPL(of_clk_del_provider); + /** * of_clk_add_provider() - Register a clock provider for a node * @np: Device node pointer associated with clock provider @@ -4095,27 +4197,6 @@ int of_clk_add_hw_provider(struct device_node *np, } EXPORT_SYMBOL_GPL(of_clk_add_hw_provider); -/** - * of_clk_del_provider() - Remove a previously registered clock provider - * @np: Device node pointer associated with clock provider - */ -void of_clk_del_provider(struct device_node *np) -{ - struct of_clk_provider *cp; - - mutex_lock(&of_clk_mutex); - list_for_each_entry(cp, &of_clk_providers, link) { - if (cp->node == np) { - list_del(&cp->link); - of_node_put(cp->node); - kfree(cp); - break; - } - } - mutex_unlock(&of_clk_mutex); -} -EXPORT_SYMBOL_GPL(of_clk_del_provider); - static struct clk_hw * __of_clk_get_hw_from_provider(struct of_clk_provider *provider, struct of_phandle_args *clkspec) @@ -4244,8 +4325,10 @@ const char *of_clk_get_parent_name(struct device_node *np, int index) else clk_name = NULL; } else { +#if defined(CONFIG_COMMON_CLK) clk_name = __clk_get_name(clk); clk_put(clk); +#endif } } @@ -4276,6 +4359,8 @@ int of_clk_parent_fill(struct device_node *np, const char **parents, } EXPORT_SYMBOL_GPL(of_clk_parent_fill); +#if defined(CONFIG_COMMON_CLK) + struct clock_provider { of_clk_init_cb_t clk_init_cb; struct device_node *np; @@ -4426,4 +4511,7 @@ void __init of_clk_init(const struct of_device_id *matches) force = true; } } + +#endif /* CONFIG_COMMON_CLK */ + #endif diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index f0db049d8c1e0b2683237d477c7b5b8cd9255404..9776a1c83642ae5f00374873759ddd32bcb71d16 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -10,8 +10,9 @@ */ struct clk_hw; +struct clk_core; -#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) +#if defined(CONFIG_OF) struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, const char *dev_id, const char *con_id); #endif @@ -22,7 +23,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, void __clk_free_clk(struct clk *clk); /* Debugfs API to print the enabled clocks */ -void clock_debug_print_enabled(void); +void clock_debug_print_enabled(bool print_parent); void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f); #else diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index bb8a77a5985f8627e6ea396298745c9b6c7eaf77..94dcad5190fc55fcf11649181410a00c59b7c700 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -27,7 +27,7 @@ static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); -#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) +#if defined(CONFIG_OF) static struct clk *__of_clk_get(struct device_node *np, int index, const char *dev_id, const char *con_id) { @@ -73,14 +73,10 @@ static struct clk *__of_clk_get_by_name(struct device_node *np, if (name) index = of_property_match_string(np, "clock-names", name); clk = __of_clk_get(np, index, dev_id, name); - if (!IS_ERR(clk)) { + if (!IS_ERR(clk)) break; - } else if (name && index >= 0) { - if (PTR_ERR(clk) != -EPROBE_DEFER) - pr_err("ERROR: could not get clock %s:%s(%i)\n", - np->full_name, name ? name : "", index); + else if (name && index >= 0) return clk; - } /* * No matching clock found on this node. If the parent node @@ -190,7 +186,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) out: mutex_unlock(&clocks_mutex); - return cl ? clk : ERR_PTR(-ENOENT); + return cl ? cl->clk : ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get_sys); diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index c0e8e1f196aae4f15c39bf39a725db8fd192f101..2bfaf22e6ffc09ddffeea2d5f9442006df34137a 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -144,7 +144,7 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = { { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, }, { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, }, { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, }, - { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, }, + { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IS_CRITICAL, 0x270, 12, 0, }, }; static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = { diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index ce8ea10407e48647aed9fdcf8d98c30ab29bd514..93a19667003d464b9423606c9196acf87b2ac5b5 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -487,7 +487,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); - clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4); + clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "mipi_core_cfg", base + 0x70, 4); clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 9f24fcfa304f9c975b63af33e6597722a403afbd..e425e50173c5ac1eeff3e430916ba0dfc0f9b0ce 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -185,6 +185,7 @@ struct mtk_pll_data { uint32_t pcw_reg; int pcw_shift; const struct mtk_pll_div_table *div_table; + const char *parent_name; }; void mtk_clk_register_plls(struct device_node *node, diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 0c2deac17ce958fd415bf80a67944b12b5ca39c1..1502384a30938ef0f501549770aeece66b8dcd56 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -302,7 +302,10 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, init.name = data->name; init.ops = &mtk_pll_ops; - init.parent_names = &parent_name; + if (data->parent_name) + init.parent_names = &data->parent_name; + else + init.parent_names = &parent_name; init.num_parents = 1; clk = clk_register(NULL, &pll->hw); diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..16f8c324acbc1a3aa44b2e2122a239c197bd2158 --- /dev/null +++ b/drivers/clk/msm/Kconfig @@ -0,0 +1,18 @@ +config COMMON_CLK_MSM + tristate "Support for MSM clock controllers" + depends on OF + depends on ARCH_QCOM + select RATIONAL + help + This support clock controller used by MSM devices which support + global, mmss and gpu clock controller. + Say Y if you want to support the clocks exposed by the MSM on + platforms such as msm8953 etc. + +config MSM_CLK_CONTROLLER_V2 + bool "QTI clock driver" + depends on COMMON_CLK_MSM + ---help--- + Generate clock data structures from definitions found in + device tree. + diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..41765533d550afb464c4438ebba9796b6c13d62f --- /dev/null +++ b/drivers/clk/msm/Makefile @@ -0,0 +1,19 @@ +obj-$(CONFIG_COMMON_CLK_MSM) += clock.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-dummy.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-generic.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-local2.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-pll.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-alpha-pll.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-rpm.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-voter.o +obj-$(CONFIG_COMMON_CLK_MSM) += reset.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-debug.o +obj-$(CONFIG_COMMON_CLK_MSM) += gdsc.o + +obj-$(CONFIG_MSM_CLK_CONTROLLER_V2) += msm-clock-controller.o + +ifeq ($(CONFIG_COMMON_CLK_MSM), y) +obj-$(CONFIG_ARCH_MSM8953) += clock-gcc-8953.o +obj-$(CONFIG_ARCH_MSM8953) += clock-cpu-8953.o +obj-$(CONFIG_ARCH_MSM8953) += clock-rcgwr.o +endif diff --git a/drivers/clk/msm/clock-alpha-pll.c b/drivers/clk/msm/clock-alpha-pll.c new file mode 100644 index 0000000000000000000000000000000000000000..dbe8d8e1ff614a6167d8732576e991cf692ded16 --- /dev/null +++ b/drivers/clk/msm/clock-alpha-pll.c @@ -0,0 +1,1265 @@ +/* + * Copyright (c) 2012-2017, 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 +#include +#include +#include +#include +#include +#include + +#include "clock.h" + +#define WAIT_MAX_LOOPS 100 + +#define MODE_REG(pll) (*pll->base + pll->offset + 0x0) +#define LOCK_REG(pll) (*pll->base + pll->offset + 0x0) +#define ACTIVE_REG(pll) (*pll->base + pll->offset + 0x0) +#define UPDATE_REG(pll) (*pll->base + pll->offset + 0x0) +#define L_REG(pll) (*pll->base + pll->offset + 0x4) +#define A_REG(pll) (*pll->base + pll->offset + 0x8) +#define VCO_REG(pll) (*pll->base + pll->offset + 0x10) +#define ALPHA_EN_REG(pll) (*pll->base + pll->offset + 0x10) +#define OUTPUT_REG(pll) (*pll->base + pll->offset + 0x10) +#define VOTE_REG(pll) (*pll->base + pll->fsm_reg_offset) +#define USER_CTL_LO_REG(pll) (*pll->base + pll->offset + 0x10) +#define USER_CTL_HI_REG(pll) (*pll->base + pll->offset + 0x14) +#define CONFIG_CTL_REG(pll) (*pll->base + pll->offset + 0x18) +#define TEST_CTL_LO_REG(pll) (*pll->base + pll->offset + 0x1c) +#define TEST_CTL_HI_REG(pll) (*pll->base + pll->offset + 0x20) + +#define PLL_BYPASSNL 0x2 +#define PLL_RESET_N 0x4 +#define PLL_OUTCTRL 0x1 +#define PLL_LATCH_INTERFACE BIT(11) + +#define FABIA_CONFIG_CTL_REG(pll) (*pll->base + pll->offset + 0x14) +#define FABIA_USER_CTL_LO_REG(pll) (*pll->base + pll->offset + 0xc) +#define FABIA_USER_CTL_HI_REG(pll) (*pll->base + pll->offset + 0x10) +#define FABIA_TEST_CTL_LO_REG(pll) (*pll->base + pll->offset + 0x1c) +#define FABIA_TEST_CTL_HI_REG(pll) (*pll->base + pll->offset + 0x20) +#define FABIA_L_REG(pll) (*pll->base + pll->offset + 0x4) +#define FABIA_FRAC_REG(pll) (*pll->base + pll->offset + 0x38) +#define FABIA_PLL_OPMODE(pll) (*pll->base + pll->offset + 0x2c) +#define FABIA_FRAC_OFF(pll) (*pll->base + pll->fabia_frac_offset) + +#define FABIA_PLL_STANDBY 0x0 +#define FABIA_PLL_RUN 0x1 +#define FABIA_PLL_OUT_MAIN 0x7 +#define FABIA_RATE_MARGIN 500 +#define ALPHA_PLL_ACK_LATCH BIT(29) +#define ALPHA_PLL_HW_UPDATE_LOGIC_BYPASS BIT(23) + +/* + * Even though 40 bits are present, use only 32 for ease of calculation. + */ +#define ALPHA_REG_BITWIDTH 40 +#define ALPHA_BITWIDTH 32 +#define FABIA_ALPHA_BITWIDTH 16 + +/* + * Enable/disable registers could be shared among PLLs when FSM voting + * is used. This lock protects against potential race when multiple + * PLLs are being enabled/disabled together. + */ +static DEFINE_SPINLOCK(alpha_pll_reg_lock); + +static unsigned long compute_rate(struct alpha_pll_clk *pll, + u32 l_val, u32 a_val) +{ + u64 rate, parent_rate; + int alpha_bw = ALPHA_BITWIDTH; + + if (pll->is_fabia) + alpha_bw = FABIA_ALPHA_BITWIDTH; + + parent_rate = clk_get_rate(pll->c.parent); + rate = parent_rate * l_val; + rate += (parent_rate * a_val) >> alpha_bw; + + return rate; +} + +static bool is_locked(struct alpha_pll_clk *pll) +{ + u32 reg = readl_relaxed(LOCK_REG(pll)); + u32 mask = pll->masks->lock_mask; + + return (reg & mask) == mask; +} + +static bool is_active(struct alpha_pll_clk *pll) +{ + u32 reg = readl_relaxed(ACTIVE_REG(pll)); + u32 mask = pll->masks->active_mask; + + return (reg & mask) == mask; +} + +/* + * Check active_flag if PLL is in FSM mode, otherwise check lock_det + * bit. This function assumes PLLs are already configured to the + * right mode. + */ +static bool update_finish(struct alpha_pll_clk *pll) +{ + if (pll->fsm_en_mask) + return is_active(pll); + else + return is_locked(pll); +} + +static int wait_for_update(struct alpha_pll_clk *pll) +{ + int count; + + for (count = WAIT_MAX_LOOPS; count > 0; count--) { + if (update_finish(pll)) + break; + udelay(1); + } + + if (!count) { + pr_err("%s didn't lock after enabling it!\n", pll->c.dbg_name); + return -EINVAL; + } + + return 0; +} + +static int __alpha_pll_vote_enable(struct alpha_pll_clk *pll) +{ + u32 ena; + + ena = readl_relaxed(VOTE_REG(pll)); + ena |= pll->fsm_en_mask; + writel_relaxed(ena, VOTE_REG(pll)); + + /* Make sure enable request goes through before waiting for update */ + mb(); + + return wait_for_update(pll); +} + +static int __alpha_pll_enable(struct alpha_pll_clk *pll, int enable_output) +{ + int rc; + u32 mode; + + mode = readl_relaxed(MODE_REG(pll)); + mode |= PLL_BYPASSNL; + writel_relaxed(mode, MODE_REG(pll)); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. + */ + mb(); + udelay(5); + + mode |= PLL_RESET_N; + writel_relaxed(mode, MODE_REG(pll)); + + rc = wait_for_update(pll); + if (rc < 0) + return rc; + + /* Enable PLL output. */ + if (enable_output) { + mode |= PLL_OUTCTRL; + writel_relaxed(mode, MODE_REG(pll)); + } + + /* Ensure that the write above goes through before returning. */ + mb(); + return 0; +} + +static void setup_alpha_pll_values(u64 a_val, u32 l_val, u32 vco_val, + struct alpha_pll_clk *pll) +{ + struct alpha_pll_masks *masks = pll->masks; + u32 regval; + + a_val = a_val << (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + writel_relaxed(l_val, L_REG(pll)); + __iowrite32_copy(A_REG(pll), &a_val, 2); + + if (vco_val != UINT_MAX) { + regval = readl_relaxed(VCO_REG(pll)); + regval &= ~(masks->vco_mask << masks->vco_shift); + regval |= vco_val << masks->vco_shift; + writel_relaxed(regval, VCO_REG(pll)); + } + + regval = readl_relaxed(ALPHA_EN_REG(pll)); + regval |= masks->alpha_en_mask; + writel_relaxed(regval, ALPHA_EN_REG(pll)); +} + +static int alpha_pll_enable(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags; + int rc; + + if (unlikely(!pll->inited)) + __init_alpha_pll(c); + + spin_lock_irqsave(&alpha_pll_reg_lock, flags); + if (pll->fsm_en_mask) + rc = __alpha_pll_vote_enable(pll); + else + rc = __alpha_pll_enable(pll, true); + spin_unlock_irqrestore(&alpha_pll_reg_lock, flags); + + return rc; +} + +static int __calibrate_alpha_pll(struct alpha_pll_clk *pll); +static int dyna_alpha_pll_enable(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags; + int rc; + + if (unlikely(!pll->inited)) + __init_alpha_pll(c); + + spin_lock_irqsave(&alpha_pll_reg_lock, flags); + + if (pll->slew) + __calibrate_alpha_pll(pll); + + if (pll->fsm_en_mask) + rc = __alpha_pll_vote_enable(pll); + else + rc = __alpha_pll_enable(pll, true); + spin_unlock_irqrestore(&alpha_pll_reg_lock, flags); + + return rc; +} + +#define PLL_OFFLINE_REQ_BIT BIT(7) +#define PLL_FSM_ENA_BIT BIT(20) +#define PLL_OFFLINE_ACK_BIT BIT(28) +#define PLL_ACTIVE_FLAG BIT(30) + +static int alpha_pll_enable_hwfsm(struct clk *c) +{ + u32 mode; + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + + /* Re-enable HW FSM mode, clear OFFLINE request */ + mode = readl_relaxed(MODE_REG(pll)); + mode |= PLL_FSM_ENA_BIT; + mode &= ~PLL_OFFLINE_REQ_BIT; + writel_relaxed(mode, MODE_REG(pll)); + + /* Make sure enable request goes through before waiting for update */ + mb(); + + if (wait_for_update(pll) < 0) + panic("PLL %s failed to lock", c->dbg_name); + + return 0; +} + +static void alpha_pll_disable_hwfsm(struct clk *c) +{ + u32 mode; + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + + /* Request PLL_OFFLINE and wait for ack */ + mode = readl_relaxed(MODE_REG(pll)); + writel_relaxed(mode | PLL_OFFLINE_REQ_BIT, MODE_REG(pll)); + while (!(readl_relaxed(MODE_REG(pll)) & PLL_OFFLINE_ACK_BIT)) + ; + + /* Disable HW FSM */ + mode = readl_relaxed(MODE_REG(pll)); + mode &= ~PLL_FSM_ENA_BIT; + if (pll->offline_bit_workaround) + mode &= ~PLL_OFFLINE_REQ_BIT; + writel_relaxed(mode, MODE_REG(pll)); + + while (readl_relaxed(MODE_REG(pll)) & PLL_ACTIVE_FLAG) + ; +} + +static void __alpha_pll_vote_disable(struct alpha_pll_clk *pll) +{ + u32 ena; + + ena = readl_relaxed(VOTE_REG(pll)); + ena &= ~pll->fsm_en_mask; + writel_relaxed(ena, VOTE_REG(pll)); +} + +static void __alpha_pll_disable(struct alpha_pll_clk *pll) +{ + u32 mode; + + mode = readl_relaxed(MODE_REG(pll)); + mode &= ~PLL_OUTCTRL; + writel_relaxed(mode, MODE_REG(pll)); + + /* Delay of 2 output clock ticks required until output is disabled */ + mb(); + udelay(1); + + mode &= ~(PLL_BYPASSNL | PLL_RESET_N); + writel_relaxed(mode, MODE_REG(pll)); +} + +static void alpha_pll_disable(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags; + + spin_lock_irqsave(&alpha_pll_reg_lock, flags); + if (pll->fsm_en_mask) + __alpha_pll_vote_disable(pll); + else + __alpha_pll_disable(pll); + spin_unlock_irqrestore(&alpha_pll_reg_lock, flags); +} + +static void dyna_alpha_pll_disable(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags; + + spin_lock_irqsave(&alpha_pll_reg_lock, flags); + if (pll->fsm_en_mask) + __alpha_pll_vote_disable(pll); + else + __alpha_pll_disable(pll); + + spin_unlock_irqrestore(&alpha_pll_reg_lock, flags); +} + +static u32 find_vco(struct alpha_pll_clk *pll, unsigned long rate) +{ + unsigned long i; + struct alpha_pll_vco_tbl *v = pll->vco_tbl; + + for (i = 0; i < pll->num_vco; i++) { + if (rate >= v[i].min_freq && rate <= v[i].max_freq) + return v[i].vco_val; + } + + return -EINVAL; +} + +static unsigned long __calc_values(struct alpha_pll_clk *pll, + unsigned long rate, int *l_val, u64 *a_val, bool round_up) +{ + u32 parent_rate; + u64 remainder; + u64 quotient; + unsigned long freq_hz; + int alpha_bw = ALPHA_BITWIDTH; + + parent_rate = clk_get_rate(pll->c.parent); + quotient = rate; + remainder = do_div(quotient, parent_rate); + *l_val = quotient; + + if (!remainder) { + *a_val = 0; + return rate; + } + + if (pll->is_fabia) + alpha_bw = FABIA_ALPHA_BITWIDTH; + + /* Upper ALPHA_BITWIDTH bits of Alpha */ + quotient = remainder << alpha_bw; + remainder = do_div(quotient, parent_rate); + + if (remainder && round_up) + quotient++; + + *a_val = quotient; + freq_hz = compute_rate(pll, *l_val, *a_val); + return freq_hz; +} + +static unsigned long round_rate_down(struct alpha_pll_clk *pll, + unsigned long rate, int *l_val, u64 *a_val) +{ + return __calc_values(pll, rate, l_val, a_val, false); +} + +static unsigned long round_rate_up(struct alpha_pll_clk *pll, + unsigned long rate, int *l_val, u64 *a_val) +{ + return __calc_values(pll, rate, l_val, a_val, true); +} + +static bool dynamic_update_finish(struct alpha_pll_clk *pll) +{ + u32 reg = readl_relaxed(UPDATE_REG(pll)); + u32 mask = pll->masks->update_mask; + + return (reg & mask) == 0; +} + +static int wait_for_dynamic_update(struct alpha_pll_clk *pll) +{ + int count; + + for (count = WAIT_MAX_LOOPS; count > 0; count--) { + if (dynamic_update_finish(pll)) + break; + udelay(1); + } + + if (!count) { + pr_err("%s didn't latch after updating it!\n", pll->c.dbg_name); + return -EINVAL; + } + + return 0; +} + +static int dyna_alpha_pll_dynamic_update(struct alpha_pll_clk *pll) +{ + struct alpha_pll_masks *masks = pll->masks; + u32 regval; + int rc; + + regval = readl_relaxed(UPDATE_REG(pll)); + regval |= masks->update_mask; + writel_relaxed(regval, UPDATE_REG(pll)); + + rc = wait_for_dynamic_update(pll); + if (rc < 0) + return rc; + + /* + * HPG mandates a wait of at least 570ns before polling the LOCK + * detect bit. Have a delay of 1us just to be safe. + */ + mb(); + udelay(1); + + rc = wait_for_update(pll); + if (rc < 0) + return rc; + + return 0; +} + +static int alpha_pll_set_rate(struct clk *c, unsigned long rate); +static int dyna_alpha_pll_set_rate(struct clk *c, unsigned long rate) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long freq_hz, flags; + u32 l_val, vco_val; + u64 a_val; + int ret; + + freq_hz = round_rate_up(pll, rate, &l_val, &a_val); + if (freq_hz != rate) { + pr_err("alpha_pll: Call clk_set_rate with rounded rates!\n"); + return -EINVAL; + } + + vco_val = find_vco(pll, freq_hz); + + /* + * Dynamic pll update will not support switching frequencies across + * vco ranges. In those cases fall back to normal alpha set rate. + */ + if (pll->current_vco_val != vco_val) { + ret = alpha_pll_set_rate(c, rate); + if (!ret) + pll->current_vco_val = vco_val; + else + return ret; + return 0; + } + + spin_lock_irqsave(&c->lock, flags); + + a_val = a_val << (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + writel_relaxed(l_val, L_REG(pll)); + __iowrite32_copy(A_REG(pll), &a_val, 2); + + /* Ensure that the write above goes through before proceeding. */ + mb(); + + if (c->count) + dyna_alpha_pll_dynamic_update(pll); + + spin_unlock_irqrestore(&c->lock, flags); + return 0; +} + +/* + * Slewing plls should be bought up at frequency which is in the middle of the + * desired VCO range. So after bringing up the pll at calibration freq, set it + * back to desired frequency(that was set by previous clk_set_rate). + */ +static int __calibrate_alpha_pll(struct alpha_pll_clk *pll) +{ + unsigned long calibration_freq, freq_hz; + struct alpha_pll_vco_tbl *vco_tbl = pll->vco_tbl; + u64 a_val; + u32 l_val, vco_val; + int rc; + + vco_val = find_vco(pll, pll->c.rate); + if (IS_ERR_VALUE((unsigned long)vco_val)) { + pr_err("alpha pll: not in a valid vco range\n"); + return -EINVAL; + } + /* + * As during slewing plls vco_sel won't be allowed to change, vco table + * should have only one entry table, i.e. index = 0, find the + * calibration frequency. + */ + calibration_freq = (vco_tbl[0].min_freq + + vco_tbl[0].max_freq)/2; + + freq_hz = round_rate_up(pll, calibration_freq, &l_val, &a_val); + if (freq_hz != calibration_freq) { + pr_err("alpha_pll: call clk_set_rate with rounded rates!\n"); + return -EINVAL; + } + + setup_alpha_pll_values(a_val, l_val, vco_tbl->vco_val, pll); + + /* Bringup the pll at calibration frequency */ + rc = __alpha_pll_enable(pll, false); + if (rc) { + pr_err("alpha pll calibration failed\n"); + return rc; + } + + /* + * PLL is already running at calibration frequency. + * So slew pll to the previously set frequency. + */ + pr_debug("pll %s: setting back to required rate %lu\n", pll->c.dbg_name, + pll->c.rate); + freq_hz = round_rate_up(pll, pll->c.rate, &l_val, &a_val); + setup_alpha_pll_values(a_val, l_val, UINT_MAX, pll); + dyna_alpha_pll_dynamic_update(pll); + + return 0; +} + +static int alpha_pll_dynamic_update(struct alpha_pll_clk *pll) +{ + u32 regval; + + /* Latch the input to the PLL */ + regval = readl_relaxed(MODE_REG(pll)); + regval |= pll->masks->update_mask; + writel_relaxed(regval, MODE_REG(pll)); + + /* Wait for 2 reference cycle before checking ACK bit */ + udelay(1); + if (!(readl_relaxed(MODE_REG(pll)) & ALPHA_PLL_ACK_LATCH)) { + WARN(1, "%s: PLL latch failed. Output may be unstable!\n", + pll->c.dbg_name); + return -EINVAL; + } + + /* Return latch input to 0 */ + regval = readl_relaxed(MODE_REG(pll)); + regval &= ~pll->masks->update_mask; + writel_relaxed(regval, MODE_REG(pll)); + + /* Wait for PLL output to stabilize */ + udelay(100); + + return 0; +} + +static int alpha_pll_set_rate(struct clk *c, unsigned long rate) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + struct alpha_pll_masks *masks = pll->masks; + unsigned long flags = 0, freq_hz = 0; + u32 l_val, regval; + int vco_val; + u64 a_val; + + freq_hz = round_rate_up(pll, rate, &l_val, &a_val); + if (freq_hz != rate) { + pr_err("alpha_pll: Call clk_set_rate with rounded rates!\n"); + return -EINVAL; + } + + vco_val = find_vco(pll, freq_hz); + if (IS_ERR_VALUE((unsigned long)vco_val)) { + pr_err("alpha pll: not in a valid vco range\n"); + return -EINVAL; + } + + if (pll->no_irq_dis) + spin_lock(&c->lock); + else + spin_lock_irqsave(&c->lock, flags); + + /* + * For PLLs that do not support dynamic programming (dynamic_update + * is not set), ensure PLL is off before changing rate. For + * optimization reasons, assume no downstream clock is actively + * using it. + */ + if (c->count && !pll->dynamic_update) + c->ops->disable(c); + + a_val = a_val << (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + writel_relaxed(l_val, L_REG(pll)); + __iowrite32_copy(A_REG(pll), &a_val, 2); + + if (masks->vco_mask) { + regval = readl_relaxed(VCO_REG(pll)); + regval &= ~(masks->vco_mask << masks->vco_shift); + regval |= vco_val << masks->vco_shift; + writel_relaxed(regval, VCO_REG(pll)); + } + + regval = readl_relaxed(ALPHA_EN_REG(pll)); + regval |= masks->alpha_en_mask; + writel_relaxed(regval, ALPHA_EN_REG(pll)); + + if (c->count && pll->dynamic_update) + alpha_pll_dynamic_update(pll); + + if (c->count && !pll->dynamic_update) + c->ops->enable(c); + + if (pll->no_irq_dis) + spin_unlock(&c->lock); + else + spin_unlock_irqrestore(&c->lock, flags); + return 0; +} + +static long alpha_pll_round_rate(struct clk *c, unsigned long rate) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + struct alpha_pll_vco_tbl *v = pll->vco_tbl; + int ret; + u32 l_val; + unsigned long freq_hz; + u64 a_val; + int i; + + if (pll->no_prepared_reconfig && c->prepare_count) + return -EINVAL; + + freq_hz = round_rate_up(pll, rate, &l_val, &a_val); + if (rate < pll->min_supported_freq) + return pll->min_supported_freq; + if (pll->is_fabia) + return freq_hz; + + ret = find_vco(pll, freq_hz); + if (!IS_ERR_VALUE((unsigned long)ret)) + return freq_hz; + + freq_hz = 0; + for (i = 0; i < pll->num_vco; i++) { + if (is_better_rate(rate, freq_hz, v[i].min_freq)) + freq_hz = v[i].min_freq; + if (is_better_rate(rate, freq_hz, v[i].max_freq)) + freq_hz = v[i].max_freq; + } + if (!freq_hz) + return -EINVAL; + return freq_hz; +} + +static void update_vco_tbl(struct alpha_pll_clk *pll) +{ + int i, l_val; + u64 a_val; + unsigned long hz; + + /* Round vco limits to valid rates */ + for (i = 0; i < pll->num_vco; i++) { + hz = round_rate_up(pll, pll->vco_tbl[i].min_freq, &l_val, + &a_val); + pll->vco_tbl[i].min_freq = hz; + + hz = round_rate_down(pll, pll->vco_tbl[i].max_freq, &l_val, + &a_val); + pll->vco_tbl[i].max_freq = hz; + } +} + +/* + * Program bias count to be 0x6 (corresponds to 5us), and lock count + * bits to 0 (check lock_det for locking). + */ +static void __set_fsm_mode(void __iomem *mode_reg) +{ + u32 regval = readl_relaxed(mode_reg); + + /* De-assert reset to FSM */ + regval &= ~BIT(21); + writel_relaxed(regval, mode_reg); + + /* Program bias count */ + regval &= ~BM(19, 14); + regval |= BVAL(19, 14, 0x6); + writel_relaxed(regval, mode_reg); + + /* Program lock count */ + regval &= ~BM(13, 8); + regval |= BVAL(13, 8, 0x0); + writel_relaxed(regval, mode_reg); + + /* Enable PLL FSM voting */ + regval |= BIT(20); + writel_relaxed(regval, mode_reg); +} + +static bool is_fsm_mode(void __iomem *mode_reg) +{ + return !!(readl_relaxed(mode_reg) & BIT(20)); +} + +void __init_alpha_pll(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + struct alpha_pll_masks *masks = pll->masks; + u32 regval; + + if (pll->config_ctl_val) + writel_relaxed(pll->config_ctl_val, CONFIG_CTL_REG(pll)); + + if (masks->output_mask && pll->enable_config) { + regval = readl_relaxed(OUTPUT_REG(pll)); + regval &= ~masks->output_mask; + regval |= pll->enable_config; + writel_relaxed(regval, OUTPUT_REG(pll)); + } + + if (masks->post_div_mask) { + regval = readl_relaxed(USER_CTL_LO_REG(pll)); + regval &= ~masks->post_div_mask; + regval |= pll->post_div_config; + writel_relaxed(regval, USER_CTL_LO_REG(pll)); + } + + if (pll->slew) { + regval = readl_relaxed(USER_CTL_HI_REG(pll)); + regval &= ~PLL_LATCH_INTERFACE; + writel_relaxed(regval, USER_CTL_HI_REG(pll)); + } + + if (masks->test_ctl_lo_mask) { + regval = readl_relaxed(TEST_CTL_LO_REG(pll)); + regval &= ~masks->test_ctl_lo_mask; + regval |= pll->test_ctl_lo_val; + writel_relaxed(regval, TEST_CTL_LO_REG(pll)); + } + + if (masks->test_ctl_hi_mask) { + regval = readl_relaxed(TEST_CTL_HI_REG(pll)); + regval &= ~masks->test_ctl_hi_mask; + regval |= pll->test_ctl_hi_val; + writel_relaxed(regval, TEST_CTL_HI_REG(pll)); + } + + if (pll->fsm_en_mask) + __set_fsm_mode(MODE_REG(pll)); + + pll->inited = true; +} + +static enum handoff alpha_pll_handoff(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + struct alpha_pll_masks *masks = pll->masks; + u64 a_val; + u32 alpha_en, l_val, regval; + + /* Set the PLL_HW_UPDATE_LOGIC_BYPASS bit before continuing */ + if (pll->dynamic_update) { + regval = readl_relaxed(MODE_REG(pll)); + regval |= ALPHA_PLL_HW_UPDATE_LOGIC_BYPASS; + writel_relaxed(regval, MODE_REG(pll)); + } + + update_vco_tbl(pll); + + if (!is_locked(pll)) { + if (pll->slew) { + if (c->rate && dyna_alpha_pll_set_rate(c, c->rate)) + WARN(1, "%s: Failed to configure rate\n", + c->dbg_name); + } else { + if (c->rate && alpha_pll_set_rate(c, c->rate)) + WARN(1, "%s: Failed to configure rate\n", + c->dbg_name); + } + __init_alpha_pll(c); + return HANDOFF_DISABLED_CLK; + } else if (pll->fsm_en_mask && !is_fsm_mode(MODE_REG(pll))) { + WARN(1, "%s should be in FSM mode but is not\n", c->dbg_name); + } + + l_val = readl_relaxed(L_REG(pll)); + /* read u64 in two steps to satisfy alignment constraint */ + a_val = readl_relaxed(A_REG(pll) + 0x4); + a_val = a_val << 32 | readl_relaxed(A_REG(pll)); + /* get upper 32 bits */ + a_val = a_val >> (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + alpha_en = readl_relaxed(ALPHA_EN_REG(pll)); + alpha_en &= masks->alpha_en_mask; + if (!alpha_en) + a_val = 0; + + c->rate = compute_rate(pll, l_val, a_val); + + /* + * Unconditionally vote for the PLL; it might be on because of + * another master's vote. + */ + if (pll->fsm_en_mask) + __alpha_pll_vote_enable(pll); + + return HANDOFF_ENABLED_CLK; +} + +static void __iomem *alpha_pll_list_registers(struct clk *clk, int n, + struct clk_register_data **regs, u32 *size) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(clk); + static struct clk_register_data data[] = { + {"PLL_MODE", 0x0}, + {"PLL_L_VAL", 0x4}, + {"PLL_ALPHA_VAL", 0x8}, + {"PLL_ALPHA_VAL_U", 0xC}, + {"PLL_USER_CTL", 0x10}, + {"PLL_CONFIG_CTL", 0x18}, + }; + + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return MODE_REG(pll); +} + +static int __fabia_alpha_pll_enable(struct alpha_pll_clk *pll) +{ + int rc; + u32 mode; + + /* Disable PLL output */ + mode = readl_relaxed(MODE_REG(pll)); + mode &= ~PLL_OUTCTRL; + writel_relaxed(mode, MODE_REG(pll)); + + /* Set operation mode to STANDBY */ + writel_relaxed(FABIA_PLL_STANDBY, FABIA_PLL_OPMODE(pll)); + + /* PLL should be in STANDBY mode before continuing */ + mb(); + + /* Bring PLL out of reset */ + mode = readl_relaxed(MODE_REG(pll)); + mode |= PLL_RESET_N; + writel_relaxed(mode, MODE_REG(pll)); + + /* Set operation mode to RUN */ + writel_relaxed(FABIA_PLL_RUN, FABIA_PLL_OPMODE(pll)); + + rc = wait_for_update(pll); + if (rc < 0) + return rc; + + /* Enable the main PLL output */ + mode = readl_relaxed(FABIA_USER_CTL_LO_REG(pll)); + mode |= FABIA_PLL_OUT_MAIN; + writel_relaxed(mode, FABIA_USER_CTL_LO_REG(pll)); + + /* Enable PLL outputs */ + mode = readl_relaxed(MODE_REG(pll)); + mode |= PLL_OUTCTRL; + writel_relaxed(mode, MODE_REG(pll)); + + /* Ensure that the write above goes through before returning. */ + mb(); + return 0; +} + +static int fabia_alpha_pll_enable(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags; + int rc; + + spin_lock_irqsave(&alpha_pll_reg_lock, flags); + if (pll->fsm_en_mask) + rc = __alpha_pll_vote_enable(pll); + else + rc = __fabia_alpha_pll_enable(pll); + spin_unlock_irqrestore(&alpha_pll_reg_lock, flags); + + return rc; +} + +static void __fabia_alpha_pll_disable(struct alpha_pll_clk *pll) +{ + u32 mode; + + /* Disable PLL outputs */ + mode = readl_relaxed(MODE_REG(pll)); + mode &= ~PLL_OUTCTRL; + writel_relaxed(mode, MODE_REG(pll)); + + /* Disable the main PLL output */ + mode = readl_relaxed(FABIA_USER_CTL_LO_REG(pll)); + mode &= ~FABIA_PLL_OUT_MAIN; + writel_relaxed(mode, FABIA_USER_CTL_LO_REG(pll)); + + /* Place PLL is the OFF state */ + mode = readl_relaxed(MODE_REG(pll)); + mode &= ~PLL_RESET_N; + writel_relaxed(mode, MODE_REG(pll)); + + /* Place the PLL mode in STANDBY */ + writel_relaxed(FABIA_PLL_STANDBY, FABIA_PLL_OPMODE(pll)); +} + +static void fabia_alpha_pll_disable(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags; + + spin_lock_irqsave(&alpha_pll_reg_lock, flags); + if (pll->fsm_en_mask) + __alpha_pll_vote_disable(pll); + else + __fabia_alpha_pll_disable(pll); + spin_unlock_irqrestore(&alpha_pll_reg_lock, flags); +} + +static int fabia_alpha_pll_set_rate(struct clk *c, unsigned long rate) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + unsigned long flags, freq_hz; + u32 l_val; + u64 a_val; + + freq_hz = round_rate_up(pll, rate, &l_val, &a_val); + if (freq_hz > rate + FABIA_RATE_MARGIN || freq_hz < rate) { + pr_err("%s: Call clk_set_rate with rounded rates!\n", + c->dbg_name); + return -EINVAL; + } + + spin_lock_irqsave(&c->lock, flags); + /* Set the new L value */ + writel_relaxed(l_val, FABIA_L_REG(pll)); + if (pll->fabia_frac_offset) + writel_relaxed(a_val, FABIA_FRAC_OFF(pll)); + else + writel_relaxed(a_val, FABIA_FRAC_REG(pll)); + + alpha_pll_dynamic_update(pll); + + spin_unlock_irqrestore(&c->lock, flags); + return 0; +} + +void __init_fabia_alpha_pll(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + struct alpha_pll_masks *masks = pll->masks; + u32 regval; + + if (pll->config_ctl_val) + writel_relaxed(pll->config_ctl_val, FABIA_CONFIG_CTL_REG(pll)); + + if (masks->output_mask && pll->enable_config) { + regval = readl_relaxed(FABIA_USER_CTL_LO_REG(pll)); + regval &= ~masks->output_mask; + regval |= pll->enable_config; + writel_relaxed(regval, FABIA_USER_CTL_LO_REG(pll)); + } + + if (masks->post_div_mask) { + regval = readl_relaxed(FABIA_USER_CTL_LO_REG(pll)); + regval &= ~masks->post_div_mask; + regval |= pll->post_div_config; + writel_relaxed(regval, FABIA_USER_CTL_LO_REG(pll)); + } + + if (pll->slew) { + regval = readl_relaxed(FABIA_USER_CTL_HI_REG(pll)); + regval &= ~PLL_LATCH_INTERFACE; + writel_relaxed(regval, FABIA_USER_CTL_HI_REG(pll)); + } + + if (masks->test_ctl_lo_mask) { + regval = readl_relaxed(FABIA_TEST_CTL_LO_REG(pll)); + regval &= ~masks->test_ctl_lo_mask; + regval |= pll->test_ctl_lo_val; + writel_relaxed(regval, FABIA_TEST_CTL_LO_REG(pll)); + } + + if (masks->test_ctl_hi_mask) { + regval = readl_relaxed(FABIA_TEST_CTL_HI_REG(pll)); + regval &= ~masks->test_ctl_hi_mask; + regval |= pll->test_ctl_hi_val; + writel_relaxed(regval, FABIA_TEST_CTL_HI_REG(pll)); + } + + if (pll->fsm_en_mask) + __set_fsm_mode(MODE_REG(pll)); + + pll->inited = true; +} + +static enum handoff fabia_alpha_pll_handoff(struct clk *c) +{ + struct alpha_pll_clk *pll = to_alpha_pll_clk(c); + u64 a_val; + u32 l_val, regval; + + /* Set the PLL_HW_UPDATE_LOGIC_BYPASS bit before continuing */ + regval = readl_relaxed(MODE_REG(pll)); + regval |= ALPHA_PLL_HW_UPDATE_LOGIC_BYPASS; + writel_relaxed(regval, MODE_REG(pll)); + + if (!is_locked(pll)) { + if (c->rate && fabia_alpha_pll_set_rate(c, c->rate)) + WARN(1, "%s: Failed to configure rate\n", c->dbg_name); + __init_alpha_pll(c); + return HANDOFF_DISABLED_CLK; + } else if (pll->fsm_en_mask && !is_fsm_mode(MODE_REG(pll))) { + WARN(1, "%s should be in FSM mode but is not\n", c->dbg_name); + } + + l_val = readl_relaxed(FABIA_L_REG(pll)); + + if (pll->fabia_frac_offset) + a_val = readl_relaxed(FABIA_FRAC_OFF(pll)); + else + a_val = readl_relaxed(FABIA_FRAC_REG(pll)); + + c->rate = compute_rate(pll, l_val, a_val); + + /* + * Unconditionally vote for the PLL; it might be on because of + * another master's vote. + */ + if (pll->fsm_en_mask) + __alpha_pll_vote_enable(pll); + + return HANDOFF_ENABLED_CLK; +} + +const struct clk_ops clk_ops_alpha_pll = { + .enable = alpha_pll_enable, + .disable = alpha_pll_disable, + .round_rate = alpha_pll_round_rate, + .set_rate = alpha_pll_set_rate, + .handoff = alpha_pll_handoff, + .list_registers = alpha_pll_list_registers, +}; + +const struct clk_ops clk_ops_alpha_pll_hwfsm = { + .enable = alpha_pll_enable_hwfsm, + .disable = alpha_pll_disable_hwfsm, + .round_rate = alpha_pll_round_rate, + .set_rate = alpha_pll_set_rate, + .handoff = alpha_pll_handoff, + .list_registers = alpha_pll_list_registers, +}; + +const struct clk_ops clk_ops_fixed_alpha_pll = { + .enable = alpha_pll_enable, + .disable = alpha_pll_disable, + .handoff = alpha_pll_handoff, + .list_registers = alpha_pll_list_registers, +}; + +const struct clk_ops clk_ops_fixed_fabia_alpha_pll = { + .enable = fabia_alpha_pll_enable, + .disable = fabia_alpha_pll_disable, + .handoff = fabia_alpha_pll_handoff, +}; + +const struct clk_ops clk_ops_fabia_alpha_pll = { + .enable = fabia_alpha_pll_enable, + .disable = fabia_alpha_pll_disable, + .round_rate = alpha_pll_round_rate, + .set_rate = fabia_alpha_pll_set_rate, + .handoff = fabia_alpha_pll_handoff, +}; + +const struct clk_ops clk_ops_dyna_alpha_pll = { + .enable = dyna_alpha_pll_enable, + .disable = dyna_alpha_pll_disable, + .round_rate = alpha_pll_round_rate, + .set_rate = dyna_alpha_pll_set_rate, + .handoff = alpha_pll_handoff, + .list_registers = alpha_pll_list_registers, +}; + +static struct alpha_pll_masks masks_20nm_p = { + .lock_mask = BIT(31), + .active_mask = BIT(30), + .vco_mask = BM(21, 20) >> 20, + .vco_shift = 20, + .alpha_en_mask = BIT(24), + .output_mask = 0xF, + .post_div_mask = 0xF00, +}; + +static struct alpha_pll_vco_tbl vco_20nm_p[] = { + VCO(3, 250000000, 500000000), + VCO(2, 500000000, 1000000000), + VCO(1, 1000000000, 1500000000), + VCO(0, 1500000000, 2000000000), +}; + +static struct alpha_pll_masks masks_20nm_t = { + .lock_mask = BIT(31), + .alpha_en_mask = BIT(24), + .output_mask = 0xf, +}; + +static struct alpha_pll_vco_tbl vco_20nm_t[] = { + VCO(0, 500000000, 1250000000), +}; + +static struct alpha_pll_clk *alpha_pll_dt_parser(struct device *dev, + struct device_node *np) +{ + struct alpha_pll_clk *pll; + struct msmclk_data *drv; + + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + if (of_property_read_u32(np, "qcom,base-offset", &pll->offset)) { + dt_err(np, "missing qcom,base-offset\n"); + return ERR_PTR(-EINVAL); + } + + /* Optional property */ + of_property_read_u32(np, "qcom,post-div-config", + &pll->post_div_config); + + pll->masks = devm_kzalloc(dev, sizeof(*pll->masks), GFP_KERNEL); + if (!pll->masks) + return ERR_PTR(-ENOMEM); + + if (of_device_is_compatible(np, "qcom,fixed-alpha-pll-20p") || + of_device_is_compatible(np, "qcom,alpha-pll-20p")) { + *pll->masks = masks_20nm_p; + pll->vco_tbl = vco_20nm_p; + pll->num_vco = ARRAY_SIZE(vco_20nm_p); + } else if (of_device_is_compatible(np, "qcom,fixed-alpha-pll-20t") || + of_device_is_compatible(np, "qcom,alpha-pll-20t")) { + *pll->masks = masks_20nm_t; + pll->vco_tbl = vco_20nm_t; + pll->num_vco = ARRAY_SIZE(vco_20nm_t); + } else { + dt_err(np, "unexpected compatible string\n"); + return ERR_PTR(-EINVAL); + } + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + pll->base = &drv->base; + return pll; +} + +static void *variable_rate_alpha_pll_dt_parser(struct device *dev, + struct device_node *np) +{ + struct alpha_pll_clk *pll; + + pll = alpha_pll_dt_parser(dev, np); + if (IS_ERR(pll)) + return pll; + + /* Optional Property */ + of_property_read_u32(np, "qcom,output-enable", &pll->enable_config); + + pll->c.ops = &clk_ops_alpha_pll; + return msmclk_generic_clk_init(dev, np, &pll->c); +} + +static void *fixed_rate_alpha_pll_dt_parser(struct device *dev, + struct device_node *np) +{ + struct alpha_pll_clk *pll; + int rc; + u32 val; + + pll = alpha_pll_dt_parser(dev, np); + if (IS_ERR(pll)) + return pll; + + rc = of_property_read_u32(np, "qcom,pll-config-rate", &val); + if (rc) { + dt_err(np, "missing qcom,pll-config-rate\n"); + return ERR_PTR(-EINVAL); + } + pll->c.rate = val; + + rc = of_property_read_u32(np, "qcom,output-enable", + &pll->enable_config); + if (rc) { + dt_err(np, "missing qcom,output-enable\n"); + return ERR_PTR(-EINVAL); + } + + /* Optional Property */ + rc = of_property_read_u32(np, "qcom,fsm-en-bit", &val); + if (!rc) { + rc = of_property_read_u32(np, "qcom,fsm-en-offset", + &pll->fsm_reg_offset); + if (rc) { + dt_err(np, "missing qcom,fsm-en-offset\n"); + return ERR_PTR(-EINVAL); + } + pll->fsm_en_mask = BIT(val); + } + + pll->c.ops = &clk_ops_fixed_alpha_pll; + return msmclk_generic_clk_init(dev, np, &pll->c); +} + +MSMCLK_PARSER(fixed_rate_alpha_pll_dt_parser, "qcom,fixed-alpha-pll-20p", 0); +MSMCLK_PARSER(fixed_rate_alpha_pll_dt_parser, "qcom,fixed-alpha-pll-20t", 1); +MSMCLK_PARSER(variable_rate_alpha_pll_dt_parser, "qcom,alpha-pll-20p", 0); +MSMCLK_PARSER(variable_rate_alpha_pll_dt_parser, "qcom,alpha-pll-20t", 1); diff --git a/drivers/clk/msm/clock-cpu-8953.c b/drivers/clk/msm/clock-cpu-8953.c new file mode 100644 index 0000000000000000000000000000000000000000..c771755b4b10222fb712f6efd019e0c04e4cdb2b --- /dev/null +++ b/drivers/clk/msm/clock-cpu-8953.c @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2015-2017, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clock.h" + +#define APCS_PLL_MODE 0x0 +#define APCS_PLL_L_VAL 0x8 +#define APCS_PLL_ALPHA_VAL 0x10 +#define APCS_PLL_USER_CTL 0x18 +#define APCS_PLL_CONFIG_CTL_LO 0x20 +#define APCS_PLL_CONFIG_CTL_HI 0x24 +#define APCS_PLL_STATUS 0x28 +#define APCS_PLL_TEST_CTL_LO 0x30 +#define APCS_PLL_TEST_CTL_HI 0x34 + +#define UPDATE_CHECK_MAX_LOOPS 5000 +#define CCI_RATE(rate) (div_u64((rate * 10ULL), 25)) +#define PLL_MODE(x) (*(x)->base + (unsigned long) (x)->mode_reg) + +#define GLB_DIAG 0x0b11101c + +enum { + APCS_C0_PLL_BASE, + APCS0_DBG_BASE, + N_BASES, +}; + +static void __iomem *virt_bases[N_BASES]; +struct platform_device *cpu_clock_dev; + +DEFINE_EXT_CLK(xo_a_clk, NULL); +DEFINE_VDD_REGS_INIT(vdd_pwrcl, 1); + +enum { + A53SS_MUX_C0, + A53SS_MUX_C1, + A53SS_MUX_CCI, + A53SS_MUX_NUM, +}; + +enum vdd_mx_pll_levels { + VDD_MX_OFF, + VDD_MX_SVS, + VDD_MX_NOM, + VDD_MX_TUR, + VDD_MX_NUM, +}; + +static int vdd_pll_levels[] = { + RPM_REGULATOR_LEVEL_NONE, /* VDD_PLL_OFF */ + RPM_REGULATOR_LEVEL_SVS, /* VDD_PLL_SVS */ + RPM_REGULATOR_LEVEL_NOM, /* VDD_PLL_NOM */ + RPM_REGULATOR_LEVEL_TURBO, /* VDD_PLL_TUR */ +}; + +static DEFINE_VDD_REGULATORS(vdd_pll, VDD_MX_NUM, 1, + vdd_pll_levels, NULL); + +#define VDD_MX_HF_FMAX_MAP1(l1, f1) \ + .vdd_class = &vdd_pll, \ + .fmax = (unsigned long[VDD_MX_NUM]) { \ + [VDD_MX_##l1] = (f1), \ + }, \ + .num_fmax = VDD_MX_NUM + +static struct clk_ops clk_ops_variable_rate; + +/* Early output of PLL */ +static struct pll_clk apcs_hf_pll = { + .mode_reg = (void __iomem *)APCS_PLL_MODE, + .l_reg = (void __iomem *)APCS_PLL_L_VAL, + .alpha_reg = (void __iomem *)APCS_PLL_ALPHA_VAL, + .config_reg = (void __iomem *)APCS_PLL_USER_CTL, + .config_ctl_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_LO, + .config_ctl_hi_reg = (void __iomem *)APCS_PLL_CONFIG_CTL_HI, + .test_ctl_lo_reg = (void __iomem *)APCS_PLL_TEST_CTL_LO, + .test_ctl_hi_reg = (void __iomem *)APCS_PLL_TEST_CTL_HI, + .status_reg = (void __iomem *)APCS_PLL_MODE, + .init_test_ctl = true, + .test_ctl_dbg = true, + .masks = { + .pre_div_mask = BIT(12), + .post_div_mask = BM(9, 8), + .mn_en_mask = BIT(24), + .main_output_mask = BIT(0), + .early_output_mask = BIT(3), + .lock_mask = BIT(31), + }, + .vals = { + .post_div_masked = 0x100, + .pre_div_masked = 0x0, + .config_ctl_val = 0x200D4828, + .config_ctl_hi_val = 0x006, + .test_ctl_hi_val = 0x00004000, + .test_ctl_lo_val = 0x1C000000, + }, + .base = &virt_bases[APCS_C0_PLL_BASE], + .max_rate = 2208000000UL, + .min_rate = 652800000UL, + .src_rate = 19200000UL, + .c = { + .parent = &xo_a_clk.c, + .dbg_name = "apcs_hf_pll", + .ops = &clk_ops_variable_rate, + /* MX level of MSM is much higher than of PLL */ + VDD_MX_HF_FMAX_MAP1(SVS, 2400000000UL), + CLK_INIT(apcs_hf_pll.c), + }, +}; + +static const char * const mux_names[] = {"c0", "c1", "cci"}; + +/* Perf Cluster */ +static struct mux_div_clk a53ssmux_perf = { + .ops = &rcg_mux_div_ops, + .data = { + .max_div = 32, + .min_div = 2, + .is_half_divider = true, + }, + .c = { + .dbg_name = "a53ssmux_perf", + .ops = &clk_ops_mux_div_clk, + CLK_INIT(a53ssmux_perf.c), + }, + .div_mask = BM(4, 0), + .src_mask = BM(10, 8) >> 8, + .src_shift = 8, + MUX_SRC_LIST( + { &apcs_hf_pll.c, 5 }, /* PLL early */ + ), +}; + +/* Little Cluster */ +static struct mux_div_clk a53ssmux_pwr = { + .ops = &rcg_mux_div_ops, + .data = { + .max_div = 32, + .min_div = 2, + .is_half_divider = true, + }, + .c = { + .dbg_name = "a53ssmux_pwr", + .ops = &clk_ops_mux_div_clk, + CLK_INIT(a53ssmux_pwr.c), + }, + .div_mask = BM(4, 0), + .src_mask = BM(10, 8) >> 8, + .src_shift = 8, + MUX_SRC_LIST( + { &apcs_hf_pll.c, 5 }, /* PLL early */ + ), +}; + +static struct mux_div_clk ccissmux = { + .ops = &rcg_mux_div_ops, + .data = { + .max_div = 32, + .min_div = 2, + .is_half_divider = true, + }, + .c = { + .dbg_name = "ccissmux", + .ops = &clk_ops_mux_div_clk, + CLK_INIT(ccissmux.c), + }, + .div_mask = BM(4, 0), + .src_mask = BM(10, 8) >> 8, + .src_shift = 8, + MUX_SRC_LIST( + { &apcs_hf_pll.c, 5 }, /* PLL early */ + ), +}; + +struct cpu_clk_8953 { + u32 cpu_reg_mask; + cpumask_t cpumask; + bool hw_low_power_ctrl; + struct pm_qos_request req; + struct clk c; + bool set_rate_done; + s32 cpu_latency_no_l2_pc_us; +}; + +static struct cpu_clk_8953 a53_pwr_clk; +static struct cpu_clk_8953 a53_perf_clk; +static struct cpu_clk_8953 cci_clk; +static void do_nothing(void *unused) { } + +static inline struct cpu_clk_8953 *to_cpu_clk_8953(struct clk *c) +{ + return container_of(c, struct cpu_clk_8953, c); +} + +static enum handoff cpu_clk_8953_handoff(struct clk *c) +{ + c->rate = clk_get_rate(c->parent); + return HANDOFF_DISABLED_CLK; +} + +static long cpu_clk_8953_round_rate(struct clk *c, unsigned long rate) +{ + return clk_round_rate(c->parent, rate); +} + +static int cpu_clk_8953_set_rate(struct clk *c, unsigned long rate) +{ + int ret = 0; + struct cpu_clk_8953 *cpuclk = to_cpu_clk_8953(c); + bool hw_low_power_ctrl = cpuclk->hw_low_power_ctrl; + + /* + * If hardware control of the clock tree is enabled during power + * collapse, setup a PM QOS request to prevent power collapse and + * wake up one of the CPUs in this clock domain, to ensure software + * control while the clock rate is being switched. + */ + if (hw_low_power_ctrl) { + memset(&cpuclk->req, 0, sizeof(cpuclk->req)); + cpumask_copy(&cpuclk->req.cpus_affine, + (const struct cpumask *)&cpuclk->cpumask); + cpuclk->req.type = PM_QOS_REQ_AFFINE_CORES; + pm_qos_add_request(&cpuclk->req, PM_QOS_CPU_DMA_LATENCY, + cpuclk->cpu_latency_no_l2_pc_us); + smp_call_function_any(&cpuclk->cpumask, do_nothing, + NULL, 1); + } + + ret = clk_set_rate(c->parent, rate); + if (!ret) { + /* update the rates of perf & power cluster */ + if (c == &a53_pwr_clk.c) + a53_perf_clk.c.rate = rate; + if (c == &a53_perf_clk.c) + a53_pwr_clk.c.rate = rate; + cci_clk.c.rate = CCI_RATE(rate); + } + + /* Remove PM QOS request */ + if (hw_low_power_ctrl) + pm_qos_remove_request(&cpuclk->req); + + return ret; +} + +static int cpu_clk_cci_set_rate(struct clk *c, unsigned long rate) +{ + int ret = 0; + struct cpu_clk_8953 *cpuclk = to_cpu_clk_8953(c); + + if (cpuclk->set_rate_done) + return ret; + + ret = clk_set_rate(c->parent, rate); + if (!ret) + cpuclk->set_rate_done = true; + return ret; +} + +static void __iomem *variable_pll_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct pll_clk *pll = to_pll_clk(c); + static struct clk_register_data data[] = { + {"MODE", 0x0}, + {"L", 0x8}, + {"ALPHA", 0x10}, + {"USER_CTL", 0x18}, + {"CONFIG_CTL_LO", 0x20}, + {"CONFIG_CTL_HI", 0x24}, + {"STATUS", 0x28}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return PLL_MODE(pll); +} + +static const struct clk_ops clk_ops_cpu = { + .set_rate = cpu_clk_8953_set_rate, + .round_rate = cpu_clk_8953_round_rate, + .handoff = cpu_clk_8953_handoff, +}; + +static const struct clk_ops clk_ops_cci = { + .set_rate = cpu_clk_cci_set_rate, + .round_rate = cpu_clk_8953_round_rate, + .handoff = cpu_clk_8953_handoff, +}; + +static struct cpu_clk_8953 a53_pwr_clk = { + .cpu_reg_mask = 0x3, + .cpu_latency_no_l2_pc_us = 280, + .c = { + .parent = &a53ssmux_pwr.c, + .ops = &clk_ops_cpu, + .vdd_class = &vdd_pwrcl, + .dbg_name = "a53_pwr_clk", + CLK_INIT(a53_pwr_clk.c), + }, +}; + +static struct cpu_clk_8953 a53_perf_clk = { + .cpu_reg_mask = 0x103, + .cpu_latency_no_l2_pc_us = 280, + .c = { + .parent = &a53ssmux_perf.c, + .ops = &clk_ops_cpu, + .vdd_class = &vdd_pwrcl, + .dbg_name = "a53_perf_clk", + CLK_INIT(a53_perf_clk.c), + }, +}; + +static struct cpu_clk_8953 cci_clk = { + .c = { + .parent = &ccissmux.c, + .ops = &clk_ops_cci, + .vdd_class = &vdd_pwrcl, + .dbg_name = "cci_clk", + CLK_INIT(cci_clk.c), + }, +}; + +static struct measure_clk apc0_m_clk = { + .c = { + .ops = &clk_ops_empty, + .dbg_name = "apc0_m_clk", + CLK_INIT(apc0_m_clk.c), + }, +}; + +static struct measure_clk apc1_m_clk = { + .c = { + .ops = &clk_ops_empty, + .dbg_name = "apc1_m_clk", + CLK_INIT(apc1_m_clk.c), + }, +}; + +static struct measure_clk cci_m_clk = { + .c = { + .ops = &clk_ops_empty, + .dbg_name = "cci_m_clk", + CLK_INIT(cci_m_clk.c), + }, +}; + +static struct mux_clk cpu_debug_ter_mux = { + .ops = &mux_reg_ops, + .mask = 0x3, + .shift = 8, + MUX_SRC_LIST( + { &apc0_m_clk.c, 0}, + { &apc1_m_clk.c, 1}, + { &cci_m_clk.c, 2}, + ), + .base = &virt_bases[APCS0_DBG_BASE], + .c = { + .dbg_name = "cpu_debug_ter_mux", + .ops = &clk_ops_gen_mux, + CLK_INIT(cpu_debug_ter_mux.c), + }, +}; + +static struct mux_clk cpu_debug_sec_mux = { + .ops = &mux_reg_ops, + .mask = 0x7, + .shift = 12, + MUX_SRC_LIST( + { &cpu_debug_ter_mux.c, 0}, + ), + MUX_REC_SRC_LIST( + &cpu_debug_ter_mux.c, + ), + .base = &virt_bases[APCS0_DBG_BASE], + .c = { + .dbg_name = "cpu_debug_sec_mux", + .ops = &clk_ops_gen_mux, + CLK_INIT(cpu_debug_sec_mux.c), + }, +}; + +static struct mux_clk cpu_debug_pri_mux = { + .ops = &mux_reg_ops, + .mask = 0x3, + .shift = 16, + MUX_SRC_LIST( + { &cpu_debug_sec_mux.c, 0}, + ), + MUX_REC_SRC_LIST( + &cpu_debug_sec_mux.c, + ), + .base = &virt_bases[APCS0_DBG_BASE], + .c = { + .dbg_name = "cpu_debug_pri_mux", + .ops = &clk_ops_gen_mux, + CLK_INIT(cpu_debug_pri_mux.c), + }, +}; + +static struct clk_lookup cpu_clocks_8953[] = { + /* PLL */ + CLK_LIST(apcs_hf_pll), + + /* Muxes */ + CLK_LIST(a53ssmux_perf), + CLK_LIST(a53ssmux_pwr), + CLK_LIST(ccissmux), + + /* CPU clocks */ + CLK_LIST(a53_perf_clk), + CLK_LIST(a53_pwr_clk), + CLK_LIST(cci_clk), + + /* debug clocks */ + CLK_LIST(apc0_m_clk), + CLK_LIST(apc1_m_clk), + CLK_LIST(cci_m_clk), + CLK_LIST(cpu_debug_pri_mux), +}; + +static struct mux_div_clk *cpussmux[] = { &a53ssmux_pwr, &a53ssmux_perf, + &ccissmux }; +static struct cpu_clk_8953 *cpuclk[] = { &a53_pwr_clk, &a53_perf_clk, + &cci_clk}; + +static struct clk *logical_cpu_to_clk(int cpu) +{ + struct device_node *cpu_node = of_get_cpu_node(cpu, NULL); + u32 reg; + + if (cpu_node && !of_property_read_u32(cpu_node, "reg", ®)) { + if ((reg | a53_pwr_clk.cpu_reg_mask) == + a53_pwr_clk.cpu_reg_mask) + return &a53_pwr_clk.c; + if ((reg | a53_perf_clk.cpu_reg_mask) == + a53_perf_clk.cpu_reg_mask) + return &a53_perf_clk.c; + } + + return NULL; +} + +static int add_opp(struct clk *c, struct device *dev, unsigned long max_rate) +{ + unsigned long rate = 0; + int level; + int uv; + long ret; + bool first = true; + int j = 1; + + while (1) { + rate = c->fmax[j++]; + level = find_vdd_level(c, rate); + if (level <= 0) { + pr_warn("clock-cpu: no corner for %lu.\n", rate); + return -EINVAL; + } + + uv = c->vdd_class->vdd_uv[level]; + if (uv < 0) { + pr_warn("clock-cpu: no uv for %lu.\n", rate); + return -EINVAL; + } + + ret = dev_pm_opp_add(dev, rate, uv); + if (ret) { + pr_warn("clock-cpu: failed to add OPP for %lu\n", rate); + return ret; + } + + /* + * The OPP pair for the lowest and highest frequency for + * each device that we're populating. This is important since + * this information will be used by thermal mitigation and the + * scheduler. + */ + if ((rate >= max_rate) || first) { + if (first) + first = false; + else + break; + } + } + + return 0; +} + +static void print_opp_table(int a53_pwr_cpu, int a53_perf_cpu) +{ + struct dev_pm_opp *oppfmax, *oppfmin; + unsigned long apc0_fmax = + a53_pwr_clk.c.fmax[a53_pwr_clk.c.num_fmax - 1]; + unsigned long apc0_fmin = a53_pwr_clk.c.fmax[1]; + + rcu_read_lock(); + + oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_pwr_cpu), + apc0_fmax, true); + oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_pwr_cpu), + apc0_fmin, true); + /* + * One time information during boot. Important to know that this looks + * sane since it can eventually make its way to the scheduler. + */ + pr_info("clock_cpu: a53 C0: OPP voltage for %lu: %ld\n", apc0_fmin, + dev_pm_opp_get_voltage(oppfmin)); + pr_info("clock_cpu: a53 C0: OPP voltage for %lu: %ld\n", apc0_fmax, + dev_pm_opp_get_voltage(oppfmax)); + + oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_perf_cpu), + apc0_fmax, true); + oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_perf_cpu), + apc0_fmin, true); + pr_info("clock_cpu: a53 C1: OPP voltage for %lu: %lu\n", apc0_fmin, + dev_pm_opp_get_voltage(oppfmin)); + pr_info("clock_cpu: a53 C2: OPP voltage for %lu: %lu\n", apc0_fmax, + dev_pm_opp_get_voltage(oppfmax)); + + rcu_read_unlock(); +} + +static void populate_opp_table(struct platform_device *pdev) +{ + unsigned long apc0_fmax; + int cpu, a53_pwr_cpu = 0, a53_perf_cpu = 0; + + apc0_fmax = a53_pwr_clk.c.fmax[a53_pwr_clk.c.num_fmax - 1]; + + for_each_possible_cpu(cpu) { + if (logical_cpu_to_clk(cpu) == &a53_pwr_clk.c) { + a53_pwr_cpu = cpu; + WARN(add_opp(&a53_pwr_clk.c, get_cpu_device(cpu), + apc0_fmax), + "Failed to add OPP levels for %d\n", cpu); + } + if (logical_cpu_to_clk(cpu) == &a53_perf_clk.c) { + a53_perf_cpu = cpu; + WARN(add_opp(&a53_perf_clk.c, get_cpu_device(cpu), + apc0_fmax), + "Failed to add OPP levels for %d\n", cpu); + } + } + + /* One time print during bootup */ + pr_info("clock-cpu-8953: OPP tables populated (cpu %d and %d)\n", + a53_pwr_cpu, a53_perf_cpu); + + print_opp_table(a53_pwr_cpu, a53_perf_cpu); +} + +static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c, + char *prop_name) +{ + struct device_node *of = pdev->dev.of_node; + int prop_len, i; + struct clk_vdd_class *vdd = c->vdd_class; + u32 *array; + + if (!of_find_property(of, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % 2) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + prop_len /= 2; + vdd->level_votes = devm_kzalloc(&pdev->dev, + prop_len * sizeof(*vdd->level_votes), + GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; + + vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int), + GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; + + c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long), + GFP_KERNEL); + if (!c->fmax) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, + prop_len * sizeof(u32) * 2, GFP_KERNEL); + if (!array) + return -ENOMEM; + + of_property_read_u32_array(of, prop_name, array, prop_len * 2); + for (i = 0; i < prop_len; i++) { + c->fmax[i] = array[2 * i]; + vdd->vdd_uv[i] = array[2 * i + 1]; + } + + devm_kfree(&pdev->dev, array); + vdd->num_levels = prop_len; + vdd->cur_level = prop_len; + vdd->use_max_uV = true; + c->num_fmax = prop_len; + + return 0; +} + +static void get_speed_bin(struct platform_device *pdev, int *bin, + int *version) +{ + struct resource *res; + void __iomem *base; + u32 pte_efuse; + + *bin = 0; + *version = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse"); + if (!res) { + dev_info(&pdev->dev, + "No speed/PVS binning available. Defaulting to 0!\n"); + return; + } + + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!base) { + dev_warn(&pdev->dev, + "Unable to read efuse data. Defaulting to 0!\n"); + return; + } + + pte_efuse = readl_relaxed(base); + devm_iounmap(&pdev->dev, base); + + *bin = (pte_efuse >> 8) & 0x7; + + dev_info(&pdev->dev, "Speed bin: %d PVS Version: %d\n", *bin, + *version); +} + +static int cpu_parse_devicetree(struct platform_device *pdev) +{ + struct resource *res; + int mux_id = 0; + char rcg_name[] = "xxx-mux"; + char pll_name[] = "xxx-pll"; + struct clk *c; + + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "c0-pll"); + if (!res) { + dev_err(&pdev->dev, "missing %s\n", pll_name); + return -EINVAL; + } + + virt_bases[APCS_C0_PLL_BASE] = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!virt_bases[APCS_C0_PLL_BASE]) { + dev_err(&pdev->dev, "ioremap failed for %s\n", + pll_name); + return -ENOMEM; + } + + for (mux_id = 0; mux_id < A53SS_MUX_NUM; mux_id++) { + snprintf(rcg_name, ARRAY_SIZE(rcg_name), "%s-mux", + mux_names[mux_id]); + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, rcg_name); + if (!res) { + dev_err(&pdev->dev, "missing %s\n", rcg_name); + return -EINVAL; + } + + cpussmux[mux_id]->base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!cpussmux[mux_id]->base) { + dev_err(&pdev->dev, "ioremap failed for %s\n", + rcg_name); + return -ENOMEM; + } + } + + /* PLL core logic */ + vdd_pll.regulator[0] = devm_regulator_get(&pdev->dev, + "vdd-mx"); + if (IS_ERR(vdd_pll.regulator[0])) { + dev_err(&pdev->dev, "Get vdd-mx regulator!!!\n"); + if (PTR_ERR(vdd_pll.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Unable to get vdd-mx regulator!!!\n"); + return PTR_ERR(vdd_pll.regulator[0]); + } + + vdd_pwrcl.regulator[0] = devm_regulator_get(&pdev->dev, + "vdd-cl"); + if (IS_ERR(vdd_pwrcl.regulator[0])) { + dev_err(&pdev->dev, "Get vdd-pwrcl regulator!!!\n"); + if (PTR_ERR(vdd_pwrcl.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get the cluster vreg\n"); + return PTR_ERR(vdd_pwrcl.regulator[0]); + } + + /* Sources of the PLL */ + c = devm_clk_get(&pdev->dev, "xo_a"); + if (IS_ERR(c)) { + if (PTR_ERR(c) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get xo (rc = %ld)!\n", + PTR_ERR(c)); + return PTR_ERR(c); + } + xo_a_clk.c.parent = c; + + return 0; +} + +/** + * clock_panic_callback() - panic notification callback function. + * This function is invoked when a kernel panic occurs. + * @nfb: Notifier block pointer + * @event: Value passed unmodified to notifier function + * @data: Pointer passed unmodified to notifier function + * + * Return: NOTIFY_OK + */ +static int clock_panic_callback(struct notifier_block *nfb, + unsigned long event, void *data) +{ + unsigned long rate; + + rate = (a53_perf_clk.c.count) ? a53_perf_clk.c.rate : 0; + pr_err("%s frequency: %10lu Hz\n", a53_perf_clk.c.dbg_name, rate); + + rate = (a53_pwr_clk.c.count) ? a53_pwr_clk.c.rate : 0; + pr_err("%s frequency: %10lu Hz\n", a53_pwr_clk.c.dbg_name, rate); + + return NOTIFY_OK; +} + +static struct notifier_block clock_panic_notifier = { + .notifier_call = clock_panic_callback, + .priority = 1, +}; + +static int clock_cpu_probe(struct platform_device *pdev) +{ + int speed_bin, version, rc, cpu, mux_id; + char prop_name[] = "qcom,speedX-bin-vX-XXX"; + unsigned long ccirate, pwrcl_boot_rate = 883200000; + + get_speed_bin(pdev, &speed_bin, &version); + + rc = cpu_parse_devicetree(pdev); + if (rc) + return rc; + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d-cl", + speed_bin, version); + for (mux_id = 0; mux_id < A53SS_MUX_CCI; mux_id++) { + rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c, + prop_name); + if (rc) { + dev_err(&pdev->dev, "Loading safe voltage plan %s!\n", + prop_name); + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed0-bin-v0-cl"); + rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c, + prop_name); + if (rc) { + dev_err(&pdev->dev, "safe voltage plan load failed for clusters\n"); + return rc; + } + } + } + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d-cci", speed_bin, version); + rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c, prop_name); + if (rc) { + dev_err(&pdev->dev, "Loading safe voltage plan %s!\n", + prop_name); + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed0-bin-v0-cci"); + rc = of_get_fmax_vdd_class(pdev, &cpuclk[mux_id]->c, + prop_name); + if (rc) { + dev_err(&pdev->dev, "safe voltage plan load failed for CCI\n"); + return rc; + } + } + + /* Debug Mux */ + virt_bases[APCS0_DBG_BASE] = devm_ioremap(&pdev->dev, GLB_DIAG, SZ_8); + if (!virt_bases[APCS0_DBG_BASE]) { + dev_err(&pdev->dev, "Failed to ioremap GLB_DIAG registers\n"); + return -ENOMEM; + } + + rc = of_msm_clock_register(pdev->dev.of_node, + cpu_clocks_8953, ARRAY_SIZE(cpu_clocks_8953)); + if (rc) { + dev_err(&pdev->dev, "msm_clock_register failed\n"); + return rc; + } + + rc = clock_rcgwr_init(pdev); + if (rc) + dev_err(&pdev->dev, "Failed to init RCGwR\n"); + + /* + * We don't want the CPU clocks to be turned off at late init + * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the + * refcount of these clocks. Any cpufreq/hotplug manager can assume + * that the clocks have already been prepared and enabled by the time + * they take over. + */ + + get_online_cpus(); + + for_each_online_cpu(cpu) { + WARN(clk_prepare_enable(&cci_clk.c), + "Unable to Turn on CCI clock"); + WARN(clk_prepare_enable(&a53_pwr_clk.c), + "Unable to turn on CPU clock for %d\n", cpu); + } + + /* ccirate = HFPLL_rate/(2.5) */ + ccirate = CCI_RATE(apcs_hf_pll.c.rate); + rc = clk_set_rate(&cci_clk.c, ccirate); + if (rc) + dev_err(&pdev->dev, "Can't set safe rate for CCI\n"); + + rc = clk_set_rate(&a53_pwr_clk.c, apcs_hf_pll.c.rate); + if (rc) + dev_err(&pdev->dev, "Can't set pwr safe rate\n"); + + rc = clk_set_rate(&a53_perf_clk.c, apcs_hf_pll.c.rate); + if (rc) + dev_err(&pdev->dev, "Can't set perf safe rate\n"); + + /* Move to higher boot frequency */ + rc = clk_set_rate(&a53_pwr_clk.c, pwrcl_boot_rate); + if (rc) + dev_err(&pdev->dev, "Can't set pwr rate %ld\n", + pwrcl_boot_rate); + put_online_cpus(); + + populate_opp_table(pdev); + + rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (rc) + return rc; + + for_each_possible_cpu(cpu) { + if (logical_cpu_to_clk(cpu) == &a53_pwr_clk.c) + cpumask_set_cpu(cpu, &a53_pwr_clk.cpumask); + if (logical_cpu_to_clk(cpu) == &a53_perf_clk.c) + cpumask_set_cpu(cpu, &a53_perf_clk.cpumask); + } + + if (of_property_read_bool(pdev->dev.of_node, "qcom,enable-qos")) { + a53_pwr_clk.hw_low_power_ctrl = true; + a53_perf_clk.hw_low_power_ctrl = true; + } + + atomic_notifier_chain_register(&panic_notifier_list, + &clock_panic_notifier); + + return 0; +} + +static const struct of_device_id clock_cpu_match_table[] = { + {.compatible = "qcom,cpu-clock-8953"}, + {} +}; + +static struct platform_driver clock_cpu_driver = { + .probe = clock_cpu_probe, + .driver = { + .name = "cpu-clock-8953", + .of_match_table = clock_cpu_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init clock_cpu_init(void) +{ + return platform_driver_register(&clock_cpu_driver); +} +arch_initcall(clock_cpu_init); + +#define APCS_HF_PLL_BASE 0xb116000 +#define APCS_ALIAS1_CMD_RCGR 0xb011050 +#define APCS_ALIAS1_CFG_OFF 0x4 +#define APCS_ALIAS1_CORE_CBCR_OFF 0x8 +#define SRC_SEL 0x5 +#define SRC_DIV 0x1 + +/* Configure PLL at Low frequency */ +unsigned long pwrcl_early_boot_rate = 652800000; + +static int __init cpu_clock_pwr_init(void) +{ + void __iomem *base; + int regval = 0; + struct device_node *ofnode = of_find_compatible_node(NULL, NULL, + "qcom,cpu-clock-8953"); + if (!ofnode) + return 0; + + /* Initialize the PLLs */ + virt_bases[APCS_C0_PLL_BASE] = ioremap_nocache(APCS_HF_PLL_BASE, SZ_1K); + clk_ops_variable_rate = clk_ops_variable_rate_pll_hwfsm; + clk_ops_variable_rate.list_registers = variable_pll_list_registers; + + __variable_rate_pll_init(&apcs_hf_pll.c); + apcs_hf_pll.c.ops->set_rate(&apcs_hf_pll.c, pwrcl_early_boot_rate); + clk_ops_variable_rate_pll.enable(&apcs_hf_pll.c); + + base = ioremap_nocache(APCS_ALIAS1_CMD_RCGR, SZ_8); + regval = readl_relaxed(base); + + /* Source GPLL0 and at the rate of GPLL0 */ + regval = (SRC_SEL << 8) | SRC_DIV; /* 0x501 */ + writel_relaxed(regval, base + APCS_ALIAS1_CFG_OFF); + /* Make sure src sel and src div is set before update bit */ + mb(); + + /* update bit */ + regval = readl_relaxed(base); + regval |= BIT(0); + writel_relaxed(regval, base); + /* Make sure src sel and src div is set before update bit */ + mb(); + + /* Enable the branch */ + regval = readl_relaxed(base + APCS_ALIAS1_CORE_CBCR_OFF); + regval |= BIT(0); + writel_relaxed(regval, base + APCS_ALIAS1_CORE_CBCR_OFF); + /* Branch enable should be complete */ + mb(); + iounmap(base); + + pr_info("Power clocks configured\n"); + + return 0; +} +early_initcall(cpu_clock_pwr_init); diff --git a/drivers/clk/msm/clock-debug.c b/drivers/clk/msm/clock-debug.c new file mode 100644 index 0000000000000000000000000000000000000000..f182fe10c03dd737f2de55090226468ece4493d0 --- /dev/null +++ b/drivers/clk/msm/clock-debug.c @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2014, 2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "clock.h" + +static LIST_HEAD(clk_list); +static DEFINE_MUTEX(clk_list_lock); + +static struct dentry *debugfs_base; +static u32 debug_suspend; + +static int clock_debug_rate_set(void *data, u64 val) +{ + struct clk *clock = data; + int ret; + + /* Only increases to max rate will succeed, but that's actually good + * for debugging purposes so we don't check for error. + */ + if (clock->flags & CLKFLAG_MAX) + clk_set_max_rate(clock, val); + ret = clk_set_rate(clock, val); + if (ret) + pr_err("clk_set_rate(%s, %lu) failed (%d)\n", clock->dbg_name, + (unsigned long)val, ret); + + return ret; +} + +static int clock_debug_rate_get(void *data, u64 *val) +{ + struct clk *clock = data; + *val = clk_get_rate(clock); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get, + clock_debug_rate_set, "%llu\n"); + +static struct clk *measure; + +static int clock_debug_measure_get(void *data, u64 *val) +{ + struct clk *clock = data, *par; + int ret, is_hw_gated; + unsigned long meas_rate, sw_rate; + + /* Check to see if the clock is in hardware gating mode */ + if (clock->ops->in_hwcg_mode) + is_hw_gated = clock->ops->in_hwcg_mode(clock); + else + is_hw_gated = 0; + + ret = clk_set_parent(measure, clock); + if (!ret) { + /* + * Disable hw gating to get accurate rate measurements. Only do + * this if the clock is explicitly enabled by software. This + * allows us to detect errors where clocks are on even though + * software is not requesting them to be on due to broken + * hardware gating signals. + */ + if (is_hw_gated && clock->count) + clock->ops->disable_hwcg(clock); + par = measure; + while (par && par != clock) { + if (par->ops->enable) + par->ops->enable(par); + par = par->parent; + } + *val = clk_get_rate(measure); + /* Reenable hwgating if it was disabled */ + if (is_hw_gated && clock->count) + clock->ops->enable_hwcg(clock); + } + + /* + * If there's a divider on the path from the clock output to the + * measurement circuitry, account for it by dividing the original clock + * rate with the rate set on the parent of the measure clock. + */ + meas_rate = clk_get_rate(clock); + sw_rate = clk_get_rate(measure->parent); + if (sw_rate && meas_rate >= (sw_rate * 2)) + *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); + + return ret; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_measure_fops, clock_debug_measure_get, + NULL, "%lld\n"); + +static int clock_debug_enable_set(void *data, u64 val) +{ + struct clk *clock = data; + int rc = 0; + + if (val) + rc = clk_prepare_enable(clock); + else + clk_disable_unprepare(clock); + + return rc; +} + +static int clock_debug_enable_get(void *data, u64 *val) +{ + struct clk *clock = data; + int enabled; + + if (clock->ops->is_enabled) + enabled = clock->ops->is_enabled(clock); + else + enabled = !!(clock->count); + + *val = enabled; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get, + clock_debug_enable_set, "%lld\n"); + +static int clock_debug_local_get(void *data, u64 *val) +{ + struct clk *clock = data; + + if (!clock->ops->is_local) + *val = true; + else + *val = clock->ops->is_local(clock); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get, + NULL, "%llu\n"); + +static int clock_debug_hwcg_get(void *data, u64 *val) +{ + struct clk *clock = data; + + if (clock->ops->in_hwcg_mode) + *val = !!clock->ops->in_hwcg_mode(clock); + else + *val = 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_hwcg_fops, clock_debug_hwcg_get, + NULL, "%llu\n"); + +static void clock_print_fmax_by_level(struct seq_file *m, int level) +{ + struct clk *clock = m->private; + struct clk_vdd_class *vdd_class = clock->vdd_class; + int off, i, vdd_level, nregs = vdd_class->num_regulators; + + vdd_level = find_vdd_level(clock, clock->rate); + + seq_printf(m, "%2s%10lu", vdd_level == level ? "[" : "", + clock->fmax[level]); + for (i = 0; i < nregs; i++) { + off = nregs*level + i; + if (vdd_class->vdd_uv) + seq_printf(m, "%10u", vdd_class->vdd_uv[off]); + if (vdd_class->vdd_ua) + seq_printf(m, "%10u", vdd_class->vdd_ua[off]); + } + + if (vdd_level == level) + seq_puts(m, "]"); + seq_puts(m, "\n"); +} + +static int fmax_rates_show(struct seq_file *m, void *unused) +{ + struct clk *clock = m->private; + struct clk_vdd_class *vdd_class = clock->vdd_class; + int level = 0, i, nregs = vdd_class->num_regulators; + char reg_name[10]; + + int vdd_level = find_vdd_level(clock, clock->rate); + + if (vdd_level < 0) { + seq_printf(m, "could not find_vdd_level for %s, %ld\n", + clock->dbg_name, clock->rate); + return 0; + } + + seq_printf(m, "%12s", ""); + for (i = 0; i < nregs; i++) { + snprintf(reg_name, ARRAY_SIZE(reg_name), "reg %d", i); + seq_printf(m, "%10s", reg_name); + if (vdd_class->vdd_ua) + seq_printf(m, "%10s", ""); + } + + seq_printf(m, "\n%12s", "freq"); + for (i = 0; i < nregs; i++) { + seq_printf(m, "%10s", "uV"); + if (vdd_class->vdd_ua) + seq_printf(m, "%10s", "uA"); + } + seq_puts(m, "\n"); + + for (level = 0; level < clock->num_fmax; level++) + clock_print_fmax_by_level(m, level); + + return 0; +} + +static int fmax_rates_open(struct inode *inode, struct file *file) +{ + return single_open(file, fmax_rates_show, inode->i_private); +} + +static const struct file_operations fmax_rates_fops = { + .open = fmax_rates_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int orphan_list_show(struct seq_file *m, void *unused) +{ + struct clk *c, *safe; + + list_for_each_entry_safe(c, safe, &orphan_clk_list, list) + seq_printf(m, "%s\n", c->dbg_name); + + return 0; +} + +static int orphan_list_open(struct inode *inode, struct file *file) +{ + return single_open(file, orphan_list_show, inode->i_private); +} + +static const struct file_operations orphan_list_fops = { + .open = orphan_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#define clock_debug_output(m, c, fmt, ...) \ +do { \ + if (m) \ + seq_printf(m, fmt, ##__VA_ARGS__); \ + else if (c) \ + pr_cont(fmt, ##__VA_ARGS__); \ + else \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + +/* + * clock_debug_print_enabled_debug_suspend() - Print names of enabled clocks + * during suspend. + */ +static void clock_debug_print_enabled_debug_suspend(struct seq_file *s) +{ + struct clk *c; + int cnt = 0; + + if (!mutex_trylock(&clk_list_lock)) + return; + + clock_debug_output(s, 0, "Enabled clocks:\n"); + + list_for_each_entry(c, &clk_list, list) { + if (!c || !c->prepare_count) + continue; + if (c->vdd_class) + clock_debug_output(s, 0, " %s:%lu:%lu [%ld, %d]", + c->dbg_name, c->prepare_count, + c->count, c->rate, + find_vdd_level(c, c->rate)); + else + clock_debug_output(s, 0, " %s:%lu:%lu [%ld]", + c->dbg_name, c->prepare_count, + c->count, c->rate); + cnt++; + } + + mutex_unlock(&clk_list_lock); + + if (cnt) + clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt); + else + clock_debug_output(s, 0, "No clocks enabled.\n"); +} + +static int clock_debug_print_clock(struct clk *c, struct seq_file *m) +{ + char *start = ""; + + if (!c || !c->prepare_count) + return 0; + + clock_debug_output(m, 0, "\t"); + do { + if (c->vdd_class) + clock_debug_output(m, 1, "%s%s:%lu:%lu [%ld, %d]", + start, c->dbg_name, c->prepare_count, c->count, + c->rate, find_vdd_level(c, c->rate)); + else + clock_debug_output(m, 1, "%s%s:%lu:%lu [%ld]", start, + c->dbg_name, c->prepare_count, c->count, + c->rate); + start = " -> "; + } while ((c = clk_get_parent(c))); + + clock_debug_output(m, 1, "\n"); + + return 1; +} + +/** + * clock_debug_print_enabled_clocks() - Print names of enabled clocks + * + */ +static void clock_debug_print_enabled_clocks(struct seq_file *m) +{ + struct clk *c; + int cnt = 0; + + if (!mutex_trylock(&clk_list_lock)) { + pr_err("clock-debug: Clocks are being registered. Cannot print clock state now.\n"); + return; + } + clock_debug_output(m, 0, "Enabled clocks:\n"); + list_for_each_entry(c, &clk_list, list) { + cnt += clock_debug_print_clock(c, m); + } + mutex_unlock(&clk_list_lock); + + if (cnt) + clock_debug_output(m, 0, "Enabled clock count: %d\n", cnt); + else + clock_debug_output(m, 0, "No clocks enabled.\n"); +} + +static int enabled_clocks_show(struct seq_file *m, void *unused) +{ + clock_debug_print_enabled_clocks(m); + return 0; +} + +static int enabled_clocks_open(struct inode *inode, struct file *file) +{ + return single_open(file, enabled_clocks_show, inode->i_private); +} + +static const struct file_operations enabled_clocks_fops = { + .open = enabled_clocks_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int trace_clocks_show(struct seq_file *m, void *unused) +{ + struct clk *c; + int total_cnt = 0; + + if (!mutex_trylock(&clk_list_lock)) { + pr_err("trace_clocks: Clocks are being registered. Cannot trace clock state now.\n"); + return 1; + } + list_for_each_entry(c, &clk_list, list) { + trace_clock_state(c->dbg_name, c->prepare_count, c->count, + c->rate); + total_cnt++; + } + mutex_unlock(&clk_list_lock); + clock_debug_output(m, 0, "Total clock count: %d\n", total_cnt); + + return 0; +} + +static int trace_clocks_open(struct inode *inode, struct file *file) +{ + return single_open(file, trace_clocks_show, inode->i_private); +} +static const struct file_operations trace_clocks_fops = { + .open = trace_clocks_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int list_rates_show(struct seq_file *m, void *unused) +{ + struct clk *clock = m->private; + int level, i = 0; + unsigned long rate, fmax = 0; + + /* Find max frequency supported within voltage constraints. */ + if (!clock->vdd_class) { + fmax = ULONG_MAX; + } else { + for (level = 0; level < clock->num_fmax; level++) + if (clock->fmax[level]) + fmax = clock->fmax[level]; + } + + /* + * List supported frequencies <= fmax. Higher frequencies may appear in + * the frequency table, but are not valid and should not be listed. + */ + while (!IS_ERR_VALUE(rate = clock->ops->list_rate(clock, i++))) { + if (rate <= fmax) + seq_printf(m, "%lu\n", rate); + } + + return 0; +} + +static int list_rates_open(struct inode *inode, struct file *file) +{ + return single_open(file, list_rates_show, inode->i_private); +} + +static const struct file_operations list_rates_fops = { + .open = list_rates_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static ssize_t clock_parent_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct clk *clock = filp->private_data; + struct clk *p = clock->parent; + char name[256] = {0}; + + snprintf(name, sizeof(name), "%s\n", p ? p->dbg_name : "None\n"); + + return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name)); +} + + +static ssize_t clock_parent_write(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + struct clk *clock = filp->private_data; + char buf[256]; + char *cmp; + int ret; + struct clk *parent = NULL; + + cnt = min(cnt, sizeof(buf) - 1); + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = '\0'; + cmp = strstrip(buf); + + mutex_lock(&clk_list_lock); + list_for_each_entry(parent, &clk_list, list) { + if (!strcmp(cmp, parent->dbg_name)) + break; + } + + if (&parent->list == &clk_list) { + ret = -EINVAL; + goto err; + } + + mutex_unlock(&clk_list_lock); + ret = clk_set_parent(clock, parent); + if (ret) + return ret; + + return cnt; +err: + mutex_unlock(&clk_list_lock); + return ret; +} + + +static const struct file_operations clock_parent_fops = { + .open = simple_open, + .read = clock_parent_read, + .write = clock_parent_write, +}; + +void clk_debug_print_hw(struct clk *clk, struct seq_file *f) +{ + void __iomem *base; + struct clk_register_data *regs; + u32 i, j, size; + + if (IS_ERR_OR_NULL(clk)) + return; + + clk_debug_print_hw(clk->parent, f); + + clock_debug_output(f, false, "%s\n", clk->dbg_name); + + if (!clk->ops->list_registers) + return; + + j = 0; + base = clk->ops->list_registers(clk, j, ®s, &size); + while (!IS_ERR(base)) { + for (i = 0; i < size; i++) { + u32 val = readl_relaxed(base + regs[i].offset); + + clock_debug_output(f, false, "%20s: 0x%.8x\n", + regs[i].name, val); + } + j++; + base = clk->ops->list_registers(clk, j, ®s, &size); + } +} + +static int print_hw_show(struct seq_file *m, void *unused) +{ + struct clk *c = m->private; + + clk_debug_print_hw(c, m); + + return 0; +} + +static int print_hw_open(struct inode *inode, struct file *file) +{ + return single_open(file, print_hw_show, inode->i_private); +} + +static const struct file_operations clock_print_hw_fops = { + .open = print_hw_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + + +static void clock_measure_add(struct clk *clock) +{ + if (IS_ERR_OR_NULL(measure)) + return; + + if (clk_set_parent(measure, clock)) + return; + + debugfs_create_file("measure", 0444, clock->clk_dir, clock, + &clock_measure_fops); +} + +static int clock_debug_add(struct clk *clock) +{ + char temp[50], *ptr; + struct dentry *clk_dir; + + if (!debugfs_base) + return -ENOMEM; + + strlcpy(temp, clock->dbg_name, ARRAY_SIZE(temp)); + for (ptr = temp; *ptr; ptr++) + *ptr = tolower(*ptr); + + clk_dir = debugfs_create_dir(temp, debugfs_base); + if (!clk_dir) + return -ENOMEM; + + clock->clk_dir = clk_dir; + + if (!debugfs_create_file("rate", 0644, clk_dir, + clock, &clock_rate_fops)) + goto error; + + if (!debugfs_create_file("enable", 0644, clk_dir, + clock, &clock_enable_fops)) + goto error; + + if (!debugfs_create_file("is_local", 0444, clk_dir, clock, + &clock_local_fops)) + goto error; + + if (!debugfs_create_file("has_hw_gating", 0444, clk_dir, clock, + &clock_hwcg_fops)) + goto error; + + if (clock->ops->list_rate) + if (!debugfs_create_file("list_rates", + 0444, clk_dir, clock, &list_rates_fops)) + goto error; + + if (clock->vdd_class && !debugfs_create_file( + "fmax_rates", 0444, clk_dir, clock, &fmax_rates_fops)) + goto error; + + if (!debugfs_create_file("parent", 0444, clk_dir, clock, + &clock_parent_fops)) + goto error; + + if (!debugfs_create_file("print", 0444, clk_dir, clock, + &clock_print_hw_fops)) + goto error; + + clock_measure_add(clock); + + return 0; +error: + debugfs_remove_recursive(clk_dir); + return -ENOMEM; +} +static DEFINE_MUTEX(clk_debug_lock); +static int clk_debug_init_once; + +/** + * clock_debug_init() - Initialize clock debugfs + * Lock clk_debug_lock before invoking this function. + */ +static int clock_debug_init(void) +{ + if (clk_debug_init_once) + return 0; + + clk_debug_init_once = 1; + + debugfs_base = debugfs_create_dir("clk", NULL); + if (!debugfs_base) + return -ENOMEM; + + if (!debugfs_create_u32("debug_suspend", 0644, + debugfs_base, &debug_suspend)) { + debugfs_remove_recursive(debugfs_base); + return -ENOMEM; + } + + if (!debugfs_create_file("enabled_clocks", 0444, debugfs_base, NULL, + &enabled_clocks_fops)) + return -ENOMEM; + + if (!debugfs_create_file("orphan_list", 0444, debugfs_base, NULL, + &orphan_list_fops)) + return -ENOMEM; + + if (!debugfs_create_file("trace_clocks", 0444, debugfs_base, NULL, + &trace_clocks_fops)) + return -ENOMEM; + + return 0; +} + +/** + * clock_debug_register() - Add additional clocks to clock debugfs hierarchy + * @list: List of clocks to create debugfs nodes for + */ +int clock_debug_register(struct clk *clk) +{ + int ret = 0; + struct clk *c; + + mutex_lock(&clk_list_lock); + if (!list_empty(&clk->list)) + goto out; + + ret = clock_debug_init(); + if (ret) + goto out; + + if (IS_ERR_OR_NULL(measure)) { + if (clk->flags & CLKFLAG_MEASURE) + measure = clk; + if (!IS_ERR_OR_NULL(measure)) { + list_for_each_entry(c, &clk_list, list) + clock_measure_add(c); + } + } + + list_add_tail(&clk->list, &clk_list); + clock_debug_add(clk); +out: + mutex_unlock(&clk_list_lock); + return ret; +} + +/* + * Print the names of enabled clocks and their parents if debug_suspend is set + */ +void clock_debug_print_enabled(bool print_parent) +{ + if (likely(!debug_suspend)) + return; + if (print_parent) + clock_debug_print_enabled_clocks(NULL); + else + clock_debug_print_enabled_debug_suspend(NULL); + +} diff --git a/drivers/clk/msm/clock-dummy.c b/drivers/clk/msm/clock-dummy.c new file mode 100644 index 0000000000000000000000000000000000000000..ad6952a4ab18ac39ef4342cd16999a6b503f2690 --- /dev/null +++ b/drivers/clk/msm/clock-dummy.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2011,2013-2014 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +static int dummy_clk_reset(struct clk *clk, enum clk_reset_action action) +{ + return 0; +} + +static int dummy_clk_set_rate(struct clk *clk, unsigned long rate) +{ + clk->rate = rate; + return 0; +} + +static int dummy_clk_set_max_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} + +static int dummy_clk_set_flags(struct clk *clk, unsigned long flags) +{ + return 0; +} + +static unsigned long dummy_clk_get_rate(struct clk *clk) +{ + return clk->rate; +} + +static long dummy_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} + +const struct clk_ops clk_ops_dummy = { + .reset = dummy_clk_reset, + .set_rate = dummy_clk_set_rate, + .set_max_rate = dummy_clk_set_max_rate, + .set_flags = dummy_clk_set_flags, + .get_rate = dummy_clk_get_rate, + .round_rate = dummy_clk_round_rate, +}; + +struct clk dummy_clk = { + .dbg_name = "dummy_clk", + .ops = &clk_ops_dummy, + CLK_INIT(dummy_clk), +}; + +static void *dummy_clk_dt_parser(struct device *dev, struct device_node *np) +{ + struct clk *c; + + c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + c->ops = &clk_ops_dummy; + return msmclk_generic_clk_init(dev, np, c); +} +MSMCLK_PARSER(dummy_clk_dt_parser, "qcom,dummy-clk", 0); + +static struct clk *of_dummy_get(struct of_phandle_args *clkspec, + void *data) +{ + return &dummy_clk; +} + +static const struct of_device_id msm_clock_dummy_match_table[] = { + { .compatible = "qcom,dummycc" }, + {} +}; + +static int msm_clock_dummy_probe(struct platform_device *pdev) +{ + int ret; + + ret = of_clk_add_provider(pdev->dev.of_node, of_dummy_get, NULL); + if (ret) + return -ENOMEM; + + dev_info(&pdev->dev, "Registered DUMMY provider.\n"); + return ret; +} + +static struct platform_driver msm_clock_dummy_driver = { + .probe = msm_clock_dummy_probe, + .driver = { + .name = "clock-dummy", + .of_match_table = msm_clock_dummy_match_table, + .owner = THIS_MODULE, + }, +}; + +int __init msm_dummy_clk_init(void) +{ + return platform_driver_register(&msm_clock_dummy_driver); +} +arch_initcall(msm_dummy_clk_init); diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c new file mode 100644 index 0000000000000000000000000000000000000000..b2dc3d26376916133b7fd3381fc7e1b3d4670bc6 --- /dev/null +++ b/drivers/clk/msm/clock-gcc-8953.c @@ -0,0 +1,4150 @@ +/* + * Copyright (c) 2015-2018, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "clock.h" +#include "reset.h" + +enum { + GCC_BASE, + GFX_BASE, + MDSS_BASE, + N_BASES, +}; + +static void __iomem *virt_bases[N_BASES]; + +#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x)) + +DEFINE_CLK_RPM_SMD_BRANCH(xo_clk_src, xo_a_clk_src, + RPM_MISC_CLK_TYPE, XO_ID, 19200000); +DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL); +DEFINE_CLK_RPM_SMD(pcnoc_clk, pcnoc_a_clk, RPM_BUS_CLK_TYPE, PCNOC_ID, NULL); +DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL); +DEFINE_CLK_RPM_SMD(sysmmnoc_clk, sysmmnoc_a_clk, RPM_BUS_CLK_TYPE, + SYSMMNOC_ID, NULL); +DEFINE_CLK_RPM_SMD(ipa_clk, ipa_a_clk, RPM_IPA_CLK_TYPE, IPA_ID, NULL); +DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID); + +/* BIMC voter */ +static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(bimc_usb_clk, &bimc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(bimc_usb_a_clk, &bimc_a_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(bimc_wcnss_a_clk, &bimc_a_clk.c, LONG_MAX); + +/* PCNOC Voter */ +static DEFINE_CLK_VOTER(pcnoc_keepalive_a_clk, &pcnoc_a_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(pcnoc_msmbus_clk, &pcnoc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(pcnoc_msmbus_a_clk, &pcnoc_a_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(pcnoc_usb_clk, &pcnoc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(pcnoc_usb_a_clk, &pcnoc_a_clk.c, LONG_MAX); + +/* SNOC Voter */ +static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(snoc_usb_clk, &snoc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(snoc_usb_a_clk, &snoc_a_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(snoc_wcnss_a_clk, &snoc_a_clk.c, LONG_MAX); + +/* SYSMMNOC Voter */ +static DEFINE_CLK_VOTER(sysmmnoc_msmbus_clk, &sysmmnoc_clk.c, LONG_MAX); +static DEFINE_CLK_VOTER(sysmmnoc_msmbus_a_clk, &sysmmnoc_a_clk.c, LONG_MAX); + +/* XO Voter */ +static DEFINE_CLK_BRANCH_VOTER(xo_dwc3_clk, &xo_clk_src.c); +static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo_clk_src.c); +static DEFINE_CLK_BRANCH_VOTER(xo_pil_lpass_clk, &xo_clk_src.c); +static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo_clk_src.c); +static DEFINE_CLK_BRANCH_VOTER(xo_pil_pronto_clk, &xo_clk_src.c); +static DEFINE_CLK_BRANCH_VOTER(xo_wlan_clk, &xo_clk_src.c); + +/* SMD_XO_BUFFER */ +DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk3, rf_clk3_a, RF_CLK3_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk2, div_clk2_a, DIV_CLK2_ID); + +DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID); +DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID); + +DEFINE_CLK_DUMMY(wcnss_m_clk, 0); +DEFINE_EXT_CLK(debug_cpu_clk, NULL); + +static struct pll_vote_clk gpll0_clk_src = { + .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE, + .en_mask = BIT(0), + .status_reg = (void __iomem *)GPLL0_MODE, + .status_mask = BIT(30), + .base = &virt_bases[GCC_BASE], + .c = { + .rate = 800000000, + .parent = &xo_clk_src.c, + .dbg_name = "gpll0_clk_src", + .ops = &clk_ops_pll_vote, + CLK_INIT(gpll0_clk_src.c), + }, +}; + +static struct pll_vote_clk gpll2_clk_src = { + .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE, + .en_mask = BIT(2), + .status_reg = (void __iomem *)GPLL2_MODE, + .status_mask = BIT(30), + .base = &virt_bases[GCC_BASE], + .c = { + .rate = 930000000, + .parent = &xo_clk_src.c, + .dbg_name = "gpll2_clk_src", + .ops = &clk_ops_pll_vote, + CLK_INIT(gpll2_clk_src.c), + }, +}; + +static struct alpha_pll_masks gpll3_masks_p = { + .lock_mask = BIT(31), + .active_mask = BIT(30), + .vco_mask = BM(21, 20) >> 20, + .vco_shift = 20, + .alpha_en_mask = BIT(24), + .output_mask = 0xf, + .update_mask = BIT(22), + .post_div_mask = BM(11, 8), + .test_ctl_lo_mask = BM(31, 0), + .test_ctl_hi_mask = BM(31, 0), +}; + +static struct alpha_pll_vco_tbl gpll3_p_vco[] = { + VCO(0, 1000000000, 2000000000), +}; + +static struct alpha_pll_clk gpll3_clk_src = { + .masks = &gpll3_masks_p, + .base = &virt_bases[GCC_BASE], + .offset = GPLL3_MODE, + .vco_tbl = gpll3_p_vco, + .num_vco = ARRAY_SIZE(gpll3_p_vco), + .enable_config = 1, + .post_div_config = 1 << 8, + .slew = true, + .config_ctl_val = 0x4001055b, + .c = { + .rate = 1300000000, + .parent = &xo_clk_src.c, + .dbg_name = "gpll3_clk_src", + .ops = &clk_ops_dyna_alpha_pll, + VDD_DIG_FMAX_MAP1(SVS, 2000000000), + CLK_INIT(gpll3_clk_src.c), + }, +}; + +static struct pll_vote_clk gpll4_clk_src = { + .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE, + .en_mask = BIT(5), + .status_reg = (void __iomem *)GPLL4_MODE, + .status_mask = BIT(30), + .base = &virt_bases[GCC_BASE], + .c = { + .rate = 1152000000, + .parent = &xo_clk_src.c, + .dbg_name = "gpll4_clk_src", + .ops = &clk_ops_pll_vote, + CLK_INIT(gpll4_clk_src.c), + }, +}; + +/* Brammo PLL status BIT(2) PLL_LOCK_DET */ +static struct pll_vote_clk gpll6_clk_src = { + .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE, + .en_mask = BIT(7), + .status_reg = (void __iomem *)GPLL6_STATUS, + .status_mask = BIT(2), + .base = &virt_bases[GCC_BASE], + .c = { + .rate = 1080000000, + .parent = &xo_clk_src.c, + .dbg_name = "gpll6_clk_src", + .ops = &clk_ops_pll_vote, + CLK_INIT(gpll6_clk_src.c), + }, +}; + +DEFINE_EXT_CLK(xo_pipe_clk_src, &xo_clk_src.c); +DEFINE_EXT_CLK(gpll0_main_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll0_main_div2_cci_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll0_main_div2_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll0_main_div2_mm_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll0_main_div2_usb3_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll0_main_mock_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll2_out_main_clk_src, &gpll2_clk_src.c); +DEFINE_EXT_CLK(gpll2_vcodec_clk_src, &gpll2_clk_src.c); +DEFINE_EXT_CLK(gpll4_aux_clk_src, &gpll4_clk_src.c); +DEFINE_EXT_CLK(gpll4_out_aux_clk_src, &gpll4_clk_src.c); +DEFINE_EXT_CLK(gpll6_aux_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_main_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_main_div2_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_main_div2_gfx_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_main_gfx_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_main_div2_mock_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_out_aux_clk_src, &gpll6_clk_src.c); + +DEFINE_EXT_CLK(ext_pclk0_clk_src, NULL); +DEFINE_EXT_CLK(ext_byte0_clk_src, NULL); +DEFINE_EXT_CLK(ext_pclk1_clk_src, NULL); +DEFINE_EXT_CLK(ext_byte1_clk_src, NULL); + +static struct clk_freq_tbl ftbl_camss_top_ahb_clk_src[] = { + F( 40000000, gpll0_main_div2, 10, 0, 0), + F( 80000000, gpll0, 10, 0, 0), + F_END +}; + +static struct rcg_clk camss_top_ahb_clk_src = { + .cmd_rcgr_reg = CAMSS_TOP_AHB_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_camss_top_ahb_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "camss_top_ahb_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 40000000, SVS_PLUS, 80000000), + CLK_INIT(camss_top_ahb_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi0_clk_src[] = { + F( 100000000, gpll0_main_div2_mm, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 310000000, gpll2, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2, 2, 0, 0), + F_END +}; + +static struct rcg_clk csi0_clk_src = { + .cmd_rcgr_reg = CSI0_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi0_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 100000000, SVS, 200000000, SVS_PLUS, + 310000000, NOM, 400000000, NOM_PLUS, 465000000), + CLK_INIT(csi0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_apss_ahb_clk_src[] = { + F( 19200000, xo_a, 1, 0, 0), + F( 25000000, gpll0_main_div2, 16, 0, 0), + F( 50000000, gpll0, 16, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F_END +}; + +static struct rcg_clk apss_ahb_clk_src = { + .cmd_rcgr_reg = APSS_AHB_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_apss_ahb_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "apss_ahb_clk_src", + .ops = &clk_ops_rcg, + CLK_INIT(apss_ahb_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi1_clk_src[] = { + F( 100000000, gpll0_main_div2, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 310000000, gpll2_out_main, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2_out_main, 2, 0, 0), + F_END +}; + +static struct rcg_clk csi1_clk_src = { + .cmd_rcgr_reg = CSI1_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi1_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi1_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 100000000, SVS, 200000000, SVS_PLUS, + 310000000, NOM, 400000000, NOM_PLUS, 465000000), + CLK_INIT(csi1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi2_clk_src[] = { + F( 100000000, gpll0_main_div2, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 310000000, gpll2_out_main, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2_out_main, 2, 0, 0), + F_END +}; + +static struct rcg_clk csi2_clk_src = { + .cmd_rcgr_reg = CSI2_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi2_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi2_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 100000000, SVS, 200000000, SVS_PLUS, + 310000000, NOM, 400000000, NOM_PLUS, 465000000), + CLK_INIT(csi2_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_vfe0_clk_src[] = { + F( 50000000, gpll0_main_div2_mm, 8, 0, 0), + F( 100000000, gpll0_main_div2_mm, 4, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F( 160000000, gpll0, 5, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 310000000, gpll2, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2, 2, 0, 0), + F_END +}; + +static struct rcg_clk vfe0_clk_src = { + .cmd_rcgr_reg = VFE0_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_vfe0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "vfe0_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP4(LOW_SVS, 100000000, SVS, 200000000, SVS_PLUS, + 310000000, NOM, 465000000), + CLK_INIT(vfe0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_gfx3d_clk_src[] = { + F_MM( 19200000, FIXED_CLK_SRC, xo, 1, 0, 0), + F_MM( 50000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 8, 0, 0), + F_MM( 80000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 5, 0, 0), + F_MM( 100000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 4, 0, 0), + F_MM( 133330000, FIXED_CLK_SRC, gpll0_main_div2_mm, 3, 0, 0), + F_MM( 160000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2.5, 0, 0), + F_MM( 200000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2, 0, 0), + F_MM( 216000000, FIXED_CLK_SRC, gpll6_main_div2_gfx, 2.5, 0, 0), + F_MM( 266670000, FIXED_CLK_SRC, gpll0, 3, 0, 0), + F_MM( 320000000, FIXED_CLK_SRC, gpll0, 2.5, 0, 0), + F_MM( 400000000, FIXED_CLK_SRC, gpll0, 2, 0, 0), + F_MM( 460800000, FIXED_CLK_SRC, gpll4_out_aux, 2.5, 0, 0), + F_MM( 510000000, 1020000000, gpll3, 1, 0, 0), + F_MM( 560000000, 1120000000, gpll3, 1, 0, 0), + F_MM( 650000000, 1300000000, gpll3, 1, 0, 0), + + F_END +}; + +static struct clk_freq_tbl ftbl_gfx3d_clk_src_sdm450[] = { + F_MM( 19200000, FIXED_CLK_SRC, xo, 1, 0, 0), + F_MM( 50000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 8, 0, 0), + F_MM( 80000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 5, 0, 0), + F_MM( 100000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 4, 0, 0), + F_MM( 133330000, FIXED_CLK_SRC, gpll0_main_div2_mm, 3, 0, 0), + F_MM( 160000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2.5, 0, 0), + F_MM( 200000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2, 0, 0), + F_MM( 216000000, FIXED_CLK_SRC, gpll6_main_div2_gfx, 2.5, 0, 0), + F_MM( 266670000, FIXED_CLK_SRC, gpll0, 3, 0, 0), + F_MM( 320000000, FIXED_CLK_SRC, gpll0, 2.5, 0, 0), + F_MM( 400000000, FIXED_CLK_SRC, gpll0, 2, 0, 0), + F_MM( 460800000, FIXED_CLK_SRC, gpll4_out_aux, 2.5, 0, 0), + F_MM( 510000000, 1020000000, gpll3, 1, 0, 0), + F_MM( 560000000, 1120000000, gpll3, 1, 0, 0), + F_MM( 600000000, 1200000000, gpll3, 1, 0, 0), + F_END +}; + +static struct rcg_clk gfx3d_clk_src = { + .cmd_rcgr_reg = GFX3D_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_gfx3d_clk_src, + .current_freq = &rcg_dummy_freq, + .non_local_control_timeout = 1000, + .base = &virt_bases[GFX_BASE], + .c = { + .dbg_name = "gfx3d_clk_src", + .ops = &clk_ops_rcg, + CLK_INIT(gfx3d_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_vcodec0_clk_src[] = { + F( 114290000, gpll0_main_div2, 3.5, 0, 0), + F( 228570000, gpll0, 3.5, 0, 0), + F( 310000000, gpll2_vcodec, 3, 0, 0), + F( 360000000, gpll6, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2_vcodec, 2, 0, 0), + F_END +}; + +static struct clk_freq_tbl ftbl_vcodec0_clk_src_540MHz[] = { + F( 114290000, gpll0_main_div2, 3.5, 0, 0), + F( 228570000, gpll0, 3.5, 0, 0), + F( 310000000, gpll2_vcodec, 3, 0, 0), + F( 360000000, gpll6, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2_vcodec, 2, 0, 0), + F( 540000000, gpll6, 2, 0, 0), + F_END +}; + +static struct rcg_clk vcodec0_clk_src = { + .cmd_rcgr_reg = VCODEC0_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_vcodec0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "vcodec0_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP6(LOW_SVS, 114290000, SVS, 228570000, SVS_PLUS, + 310000000, NOM, 360000000, NOM_PLUS, 400000000, + HIGH, 465000000), + CLK_INIT(vcodec0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_cpp_clk_src[] = { + F( 100000000, gpll0_main_div2_mm, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 320000000, gpll0, 2.5, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2, 2, 0, 0), + F_END +}; + +static struct rcg_clk cpp_clk_src = { + .cmd_rcgr_reg = CPP_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_cpp_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "cpp_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 100000000, SVS, 200000000, SVS_PLUS, + 266670000, NOM, 400000000, NOM_PLUS, 465000000), + CLK_INIT(cpp_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_jpeg0_clk_src[] = { + F( 66670000, gpll0_main_div2, 6, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 310000000, gpll2_out_main, 3, 0, 0), + F( 320000000, gpll0, 2.5, 0, 0), + F_END +}; + +static struct rcg_clk jpeg0_clk_src = { + .cmd_rcgr_reg = JPEG0_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_jpeg0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "jpeg0_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP6(LOW_SVS, 66670000, SVS, 133330000, SVS_PLUS, + 200000000, NOM, 266670000, NOM_PLUS, 310000000, + HIGH, 320000000), + CLK_INIT(jpeg0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_mdp_clk_src[] = { + F( 50000000, gpll0_main_div2, 8, 0, 0), + F( 80000000, gpll0_main_div2, 5, 0, 0), + F( 160000000, gpll0_main_div2, 2.5, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 320000000, gpll0, 2.5, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F_END +}; + +static struct rcg_clk mdp_clk_src = { + .cmd_rcgr_reg = MDP_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_mdp_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "mdp_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP4(LOW_SVS, 160000000, SVS, 266670000, NOM, + 320000000, HIGH, 400000000), + CLK_INIT(mdp_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_pclk0_clk_src[] = { + { + .div_src_val = BVAL(10, 8, xo_src_val) + | BVAL(4, 0, 0), + .src_clk = &xo_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi0_phypll_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_pclk0_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi1_phypll_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_pclk1_clk_src.c, + .freq_hz = 0, + }, + F_END +}; + +static struct rcg_clk pclk0_clk_src = { + .cmd_rcgr_reg = PCLK0_CMD_RCGR, + .set_rate = set_rate_mnd, + .current_freq = ftbl_pclk0_clk_src, + .freq_tbl = ftbl_pclk0_clk_src, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "pclk0_clk_src", + .ops = &clk_ops_pixel_multiparent, + .flags = CLKFLAG_NO_RATE_CACHE, + VDD_DIG_FMAX_MAP3(LOW_SVS, 175000000, SVS, 280000000, NOM, + 350000000), + CLK_INIT(pclk0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_pclk1_clk_src[] = { + { + .div_src_val = BVAL(10, 8, xo_src_val) + | BVAL(4, 0, 0), + .src_clk = &xo_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi1_phypll_clk_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_pclk1_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi0_phypll_clk_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_pclk0_clk_src.c, + .freq_hz = 0, + }, + F_END +}; + +static struct rcg_clk pclk1_clk_src = { + .cmd_rcgr_reg = PCLK1_CMD_RCGR, + .set_rate = set_rate_mnd, + .current_freq = ftbl_pclk1_clk_src, + .freq_tbl = ftbl_pclk1_clk_src, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "pclk1_clk_src", + .ops = &clk_ops_pixel_multiparent, + .flags = CLKFLAG_NO_RATE_CACHE, + VDD_DIG_FMAX_MAP3(LOW_SVS, 175000000, SVS, 280000000, NOM, + 350000000), + CLK_INIT(pclk1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_usb30_master_clk_src[] = { + F( 80000000, gpll0_main_div2_usb3, 5, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F_END +}; + +static struct rcg_clk usb30_master_clk_src = { + .cmd_rcgr_reg = USB30_MASTER_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_usb30_master_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "usb30_master_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 80000000, NOM, 133330000), + CLK_INIT(usb30_master_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_vfe1_clk_src[] = { + F( 50000000, gpll0_main_div2_mm, 8, 0, 0), + F( 100000000, gpll0_main_div2_mm, 4, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F( 160000000, gpll0, 5, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 310000000, gpll2, 3, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 465000000, gpll2, 2, 0, 0), + F_END +}; + +static struct rcg_clk vfe1_clk_src = { + .cmd_rcgr_reg = VFE1_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_vfe1_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "vfe1_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP4(LOW_SVS, 100000000, SVS, 200000000, SVS_PLUS, + 310000000, NOM, 465000000), + CLK_INIT(vfe1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_apc0_droop_detector_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 576000000, gpll4, 2, 0, 0), + F_END +}; + +static struct rcg_clk apc0_droop_detector_clk_src = { + .cmd_rcgr_reg = APC0_VOLTAGE_DROOP_DETECTOR_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_apc0_droop_detector_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "apc0_droop_detector_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP3(LOW_SVS, 19200000, SVS, 400000000, NOM, + 600000000), + CLK_INIT(apc0_droop_detector_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_apc1_droop_detector_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F( 400000000, gpll0, 2, 0, 0), + F( 576000000, gpll4, 2, 0, 0), + F_END +}; + +static struct rcg_clk apc1_droop_detector_clk_src = { + .cmd_rcgr_reg = APC1_VOLTAGE_DROOP_DETECTOR_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_apc1_droop_detector_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "apc1_droop_detector_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP3(LOW_SVS, 19200000, SVS, 400000000, NOM, + 600000000), + CLK_INIT(apc1_droop_detector_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_blsp_i2c_apps_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F( 25000000, gpll0_main_div2, 16, 0, 0), + F( 50000000, gpll0, 16, 0, 0), + F_END +}; + +static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup1_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_blsp_spi_apps_clk_src[] = { + F( 960000, xo, 10, 1, 2), + F( 4800000, xo, 4, 0, 0), + F( 9600000, xo, 2, 0, 0), + F( 12500000, gpll0_main_div2, 16, 1, 2), + F( 16000000, gpll0, 10, 1, 5), + F( 19200000, xo, 1, 0, 0), + F( 25000000, gpll0, 16, 1, 2), + F( 50000000, gpll0, 16, 0, 0), + F_END +}; + +static struct rcg_clk blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup1_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp1_qup1_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup2_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup2_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp1_qup2_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup3_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup3_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp1_qup3_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup4_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_qup4_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp1_qup4_spi_apps_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = { + F( 3686400, gpll0_main_div2, 1, 144, 15625), + F( 7372800, gpll0_main_div2, 1, 288, 15625), + F( 14745600, gpll0_main_div2, 1, 576, 15625), + F( 16000000, gpll0_main_div2, 5, 1, 5), + F( 19200000, xo, 1, 0, 0), + F( 24000000, gpll0, 1, 3, 100), + F( 25000000, gpll0, 16, 1, 2), + F( 32000000, gpll0, 1, 1, 25), + F( 40000000, gpll0, 1, 1, 20), + F( 46400000, gpll0, 1, 29, 500), + F( 48000000, gpll0, 1, 3, 50), + F( 51200000, gpll0, 1, 8, 125), + F( 56000000, gpll0, 1, 7, 100), + F( 58982400, gpll0, 1, 1152, 15625), + F( 60000000, gpll0, 1, 3, 40), + F( 64000000, gpll0, 1, 2, 25), + F_END +}; + +static struct rcg_clk blsp1_uart1_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_uart1_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 16000000, SVS, 32000000, NOM, + 64000000), + CLK_INIT(blsp1_uart1_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp1_uart2_apps_clk_src = { + .cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp1_uart2_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 16000000, SVS, 32000000, NOM, + 64000000), + CLK_INIT(blsp1_uart2_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup1_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP1_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup1_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp2_qup1_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup1_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP1_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup1_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp2_qup1_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup2_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP2_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup2_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp2_qup2_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup2_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP2_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup2_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp2_qup2_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup3_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP3_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup3_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp2_qup3_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup3_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP3_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup3_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp2_qup3_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup4_i2c_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP4_I2C_APPS_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup4_i2c_apps_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 25000000, SVS, 50000000), + CLK_INIT(blsp2_qup4_i2c_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_qup4_spi_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_QUP4_SPI_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_qup4_spi_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 12500000, SVS, 25000000, NOM, + 50000000), + CLK_INIT(blsp2_qup4_spi_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_uart1_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_UART1_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_uart1_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 16000000, SVS, 32000000, NOM, + 64000000), + CLK_INIT(blsp2_uart1_apps_clk_src.c), + }, +}; + +static struct rcg_clk blsp2_uart2_apps_clk_src = { + .cmd_rcgr_reg = BLSP2_UART2_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "blsp2_uart2_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 16000000, SVS, 32000000, NOM, + 64000000), + CLK_INIT(blsp2_uart2_apps_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_cci_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F( 37500000, gpll0_main_div2_cci, 1, 3, 32), + F_END +}; + +static struct rcg_clk cci_clk_src = { + .cmd_rcgr_reg = CCI_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_cci_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "cci_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP1(LOW_SVS, 37500000), + CLK_INIT(cci_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi0p_clk_src[] = { + F( 66670000, gpll0_main_div2_mm, 6, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 310000000, gpll2, 3, 0, 0), + F_END +}; + +static struct rcg_clk csi0p_clk_src = { + .cmd_rcgr_reg = CSI0P_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi0p_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi0p_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 66670000, SVS, 133330000, SVS_PLUS, + 200000000, NOM, 266670000, NOM_PLUS, 310000000), + CLK_INIT(csi0p_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi1p_clk_src[] = { + F( 66670000, gpll0_main_div2_mm, 6, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 310000000, gpll2, 3, 0, 0), + F_END +}; + +static struct rcg_clk csi1p_clk_src = { + .cmd_rcgr_reg = CSI1P_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi1p_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi1p_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 66670000, SVS, 133330000, SVS_PLUS, + 200000000, NOM, 266670000, NOM_PLUS, 310000000), + CLK_INIT(csi1p_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi2p_clk_src[] = { + F( 66670000, gpll0_main_div2_mm, 6, 0, 0), + F( 133330000, gpll0, 6, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F( 310000000, gpll2, 3, 0, 0), + F_END +}; + +static struct rcg_clk csi2p_clk_src = { + .cmd_rcgr_reg = CSI2P_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi2p_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi2p_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP5(LOW_SVS, 66670000, SVS, 133330000, SVS_PLUS, + 200000000, NOM, 266670000, NOM_PLUS, 310000000), + CLK_INIT(csi2p_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_camss_gp0_clk_src[] = { + F( 50000000, gpll0_main_div2, 8, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F_END +}; + +static struct rcg_clk camss_gp0_clk_src = { + .cmd_rcgr_reg = CAMSS_GP0_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_camss_gp0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "camss_gp0_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP4(LOW_SVS, 50000000, SVS, 100000000, SVS_PLUS, + 200000000, NOM_PLUS, 266670000), + CLK_INIT(camss_gp0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_camss_gp1_clk_src[] = { + F( 50000000, gpll0_main_div2, 8, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F_END +}; + +static struct rcg_clk camss_gp1_clk_src = { + .cmd_rcgr_reg = CAMSS_GP1_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_camss_gp1_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "camss_gp1_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP4(LOW_SVS, 50000000, SVS, 100000000, SVS_PLUS, + 200000000, NOM_PLUS, 266670000), + CLK_INIT(camss_gp1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_mclk0_clk_src[] = { + F( 24000000, gpll6_main_div2, 1, 2, 45), + F( 33330000, gpll0_main_div2, 12, 0, 0), + F( 36610000, gpll6, 1, 2, 59), + F( 66667000, gpll0, 12, 0, 0), + F_END +}; + +static struct rcg_clk mclk0_clk_src = { + .cmd_rcgr_reg = MCLK0_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_mclk0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "mclk0_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 33330000, SVS, 66670000), + CLK_INIT(mclk0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_mclk1_clk_src[] = { + F( 24000000, gpll6_main_div2, 1, 2, 45), + F( 33330000, gpll0_main_div2, 12, 0, 0), + F( 36610000, gpll6, 1, 2, 59), + F( 66667000, gpll0, 12, 0, 0), + F_END +}; + +static struct rcg_clk mclk1_clk_src = { + .cmd_rcgr_reg = MCLK1_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_mclk1_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "mclk1_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 33330000, SVS, 66670000), + CLK_INIT(mclk1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_mclk2_clk_src[] = { + F( 24000000, gpll6_main_div2, 1, 2, 45), + F( 33330000, gpll0_main_div2, 12, 0, 0), + F( 36610000, gpll6, 1, 2, 59), + F( 66667000, gpll0, 12, 0, 0), + F_END +}; + +static struct rcg_clk mclk2_clk_src = { + .cmd_rcgr_reg = MCLK2_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_mclk2_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "mclk2_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 33330000, SVS, 66670000), + CLK_INIT(mclk2_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_mclk3_clk_src[] = { + F( 24000000, gpll6_main_div2, 1, 2, 45), + F( 33330000, gpll0_main_div2, 12, 0, 0), + F( 36610000, gpll6, 1, 2, 59), + F( 66667000, gpll0, 12, 0, 0), + F_END +}; + +static struct rcg_clk mclk3_clk_src = { + .cmd_rcgr_reg = MCLK3_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_mclk3_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "mclk3_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 33330000, SVS, 66670000), + CLK_INIT(mclk3_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi0phytimer_clk_src[] = { + F( 100000000, gpll0_main_div2, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F_END +}; + +static struct rcg_clk csi0phytimer_clk_src = { + .cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi0phytimer_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi0phytimer_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP3(LOW_SVS, 100000000, SVS_PLUS, 200000000, + NOM_PLUS, 266670000), + CLK_INIT(csi0phytimer_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi1phytimer_clk_src[] = { + F( 100000000, gpll0_main_div2, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F_END +}; + +static struct rcg_clk csi1phytimer_clk_src = { + .cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi1phytimer_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi1phytimer_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP3(LOW_SVS, 100000000, SVS_PLUS, 200000000, + NOM_PLUS, 266670000), + CLK_INIT(csi1phytimer_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_csi2phytimer_clk_src[] = { + F( 100000000, gpll0_main_div2, 4, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F( 266670000, gpll0, 3, 0, 0), + F_END +}; + +static struct rcg_clk csi2phytimer_clk_src = { + .cmd_rcgr_reg = CSI2PHYTIMER_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_csi2phytimer_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "csi2phytimer_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP3(LOW_SVS, 100000000, SVS_PLUS, 200000000, + NOM_PLUS, 266670000), + CLK_INIT(csi2phytimer_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_crypto_clk_src[] = { + F( 40000000, gpll0_main_div2, 10, 0, 0), + F( 80000000, gpll0, 10, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 160000000, gpll0, 5, 0, 0), + F_END +}; + +static struct rcg_clk crypto_clk_src = { + .cmd_rcgr_reg = CRYPTO_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_crypto_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "crypto_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP3(LOW_SVS, 40000000, SVS, 80000000, NOM, + 160000000), + CLK_INIT(crypto_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_gp1_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk gp1_clk_src = { + .cmd_rcgr_reg = GP1_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_gp1_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gp1_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP4(LOW_SVS, 50000000, SVS, 100000000, NOM, + 200000000, NOM_PLUS, 266670000), + CLK_INIT(gp1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_gp2_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk gp2_clk_src = { + .cmd_rcgr_reg = GP2_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_gp2_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gp2_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP4(LOW_SVS, 50000000, SVS, 100000000, NOM, + 200000000, NOM_PLUS, 266670000), + CLK_INIT(gp2_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_gp3_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk gp3_clk_src = { + .cmd_rcgr_reg = GP3_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_gp3_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gp3_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP4(LOW_SVS, 50000000, SVS, 100000000, NOM, + 200000000, NOM_PLUS, 266670000), + CLK_INIT(gp3_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_byte0_clk_src[] = { + { + .div_src_val = BVAL(10, 8, xo_src_val) + | BVAL(4, 0, 0), + .src_clk = &xo_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi0_phypll_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_byte0_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi1_phypll_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_byte1_clk_src.c, + .freq_hz = 0, + }, + F_END +}; + +static struct rcg_clk byte0_clk_src = { + .cmd_rcgr_reg = BYTE0_CMD_RCGR, + .set_rate = set_rate_hid, + .current_freq = ftbl_byte0_clk_src, + .freq_tbl = ftbl_byte0_clk_src, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "byte0_clk_src", + .ops = &clk_ops_byte_multiparent, + .flags = CLKFLAG_NO_RATE_CACHE, + VDD_DIG_FMAX_MAP3(LOW_SVS, 131250000, SVS, 210000000, NOM, + 262500000), + CLK_INIT(byte0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_byte1_clk_src[] = { + { + .div_src_val = BVAL(10, 8, xo_src_val) + | BVAL(4, 0, 0), + .src_clk = &xo_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi1_phypll_clk_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_byte1_clk_src.c, + .freq_hz = 0, + }, + { + .div_src_val = BVAL(10, 8, dsi0_phypll_clk_mm_src_val) + | BVAL(4, 0, 0), + .src_clk = &ext_byte0_clk_src.c, + .freq_hz = 0, + }, + F_END +}; + +static struct rcg_clk byte1_clk_src = { + .cmd_rcgr_reg = BYTE1_CMD_RCGR, + .set_rate = set_rate_hid, + .current_freq = ftbl_byte1_clk_src, + .freq_tbl = ftbl_byte1_clk_src, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "byte1_clk_src", + .ops = &clk_ops_byte_multiparent, + .flags = CLKFLAG_NO_RATE_CACHE, + VDD_DIG_FMAX_MAP3(LOW_SVS, 131250000, SVS, 210000000, NOM, + 262500000), + CLK_INIT(byte1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_esc0_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk esc0_clk_src = { + .cmd_rcgr_reg = ESC0_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_esc0_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "esc0_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP1(LOW_SVS, 19200000), + CLK_INIT(esc0_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_esc1_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk esc1_clk_src = { + .cmd_rcgr_reg = ESC1_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_esc1_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "esc1_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP1(LOW_SVS, 19200000), + CLK_INIT(esc1_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_vsync_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk vsync_clk_src = { + .cmd_rcgr_reg = VSYNC_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_vsync_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "vsync_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP1(LOW_SVS, 19200000), + CLK_INIT(vsync_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_pdm2_clk_src[] = { + F( 32000000, gpll0_main_div2, 12.5, 0, 0), + F( 64000000, gpll0, 12.5, 0, 0), + F_END +}; + +static struct rcg_clk pdm2_clk_src = { + .cmd_rcgr_reg = PDM2_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_pdm2_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "pdm2_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 32000000, SVS, 64000000), + CLK_INIT(pdm2_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_rbcpr_gfx_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F( 50000000, gpll0, 16, 0, 0), + F_END +}; + +static struct rcg_clk rbcpr_gfx_clk_src = { + .cmd_rcgr_reg = RBCPR_GFX_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_rbcpr_gfx_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "rbcpr_gfx_clk_src", + .ops = &clk_ops_rcg, + VDD_DIG_FMAX_MAP2(LOW_SVS, 19200000, SVS, 50000000), + CLK_INIT(rbcpr_gfx_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_sdcc1_apps_clk_src[] = { + F( 144000, xo, 16, 3, 25), + F( 400000, xo, 12, 1, 4), + F( 20000000, gpll0_main_div2, 5, 1, 4), + F( 25000000, gpll0_main_div2, 16, 0, 0), + F( 50000000, gpll0, 16, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 177770000, gpll0, 4.5, 0, 0), + F( 192000000, gpll4, 6, 0, 0), + F( 384000000, gpll4, 3, 0, 0), + F_END +}; + +static struct rcg_clk sdcc1_apps_clk_src = { + .cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_sdcc1_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "sdcc1_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 25000000, SVS, 100000000, NOM, + 400000000), + CLK_INIT(sdcc1_apps_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_sdcc1_ice_core_clk_src[] = { + F( 80000000, gpll0_main_div2, 5, 0, 0), + F( 160000000, gpll0, 5, 0, 0), + F( 270000000, gpll6, 4, 0, 0), + F_END +}; + +static struct rcg_clk sdcc1_ice_core_clk_src = { + .cmd_rcgr_reg = SDCC1_ICE_CORE_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_sdcc1_ice_core_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "sdcc1_ice_core_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 80000000, SVS, 160000000, NOM, + 270000000), + CLK_INIT(sdcc1_ice_core_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_sdcc2_apps_clk_src[] = { + F( 144000, xo, 16, 3, 25), + F( 400000, xo, 12, 1, 4), + F( 20000000, gpll0_main_div2, 5, 1, 4), + F( 25000000, gpll0_main_div2, 16, 0, 0), + F( 50000000, gpll0, 16, 0, 0), + F( 100000000, gpll0, 8, 0, 0), + F( 177770000, gpll0, 4.5, 0, 0), + F( 192000000, gpll4_aux, 6, 0, 0), + F( 200000000, gpll0, 4, 0, 0), + F_END +}; + +static struct rcg_clk sdcc2_apps_clk_src = { + .cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_sdcc2_apps_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "sdcc2_apps_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOW_SVS, 25000000, SVS, 100000000, NOM, + 200000000), + CLK_INIT(sdcc2_apps_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_usb30_mock_utmi_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F( 60000000, gpll6_main_div2_mock, 9, 1, 1), + F_END +}; + +static struct rcg_clk usb30_mock_utmi_clk_src = { + .cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_usb30_mock_utmi_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "usb30_mock_utmi_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP2(LOW_SVS, 19200000, SVS, 60000000), + CLK_INIT(usb30_mock_utmi_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_usb3_aux_clk_src[] = { + F( 19200000, xo, 1, 0, 0), + F_END +}; + +static struct rcg_clk usb3_aux_clk_src = { + .cmd_rcgr_reg = USB3_AUX_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_usb3_aux_clk_src, + .current_freq = &rcg_dummy_freq, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "usb3_aux_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP1(LOW_SVS, 19200000), + CLK_INIT(usb3_aux_clk_src.c), + }, +}; + +static struct branch_clk gcc_apc0_droop_detector_gpll0_clk = { + .cbcr_reg = APC0_VOLTAGE_DROOP_DETECTOR_GPLL0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_apc0_droop_detector_gpll0_clk", + .parent = &apc0_droop_detector_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_apc0_droop_detector_gpll0_clk.c), + }, +}; + +static struct branch_clk gcc_apc1_droop_detector_gpll0_clk = { + .cbcr_reg = APC1_VOLTAGE_DROOP_DETECTOR_GPLL0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_apc1_droop_detector_gpll0_clk", + .parent = &apc1_droop_detector_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_apc1_droop_detector_gpll0_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = { + .cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent = &blsp1_qup1_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = { + .cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup1_spi_apps_clk", + .parent = &blsp1_qup1_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = { + .cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent = &blsp1_qup2_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = { + .cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup2_spi_apps_clk", + .parent = &blsp1_qup2_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = { + .cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent = &blsp1_qup3_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = { + .cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup3_spi_apps_clk", + .parent = &blsp1_qup3_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = { + .cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent = &blsp1_qup4_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = { + .cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_qup4_spi_apps_clk", + .parent = &blsp1_qup4_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_uart1_apps_clk = { + .cbcr_reg = BLSP1_UART1_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_uart1_apps_clk", + .parent = &blsp1_uart1_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_uart1_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp1_uart2_apps_clk = { + .cbcr_reg = BLSP1_UART2_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_uart2_apps_clk", + .parent = &blsp1_uart2_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp1_uart2_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup1_i2c_apps_clk = { + .cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup1_i2c_apps_clk", + .parent = &blsp2_qup1_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup1_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = { + .cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup1_spi_apps_clk", + .parent = &blsp2_qup1_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup1_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup2_i2c_apps_clk = { + .cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup2_i2c_apps_clk", + .parent = &blsp2_qup2_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup2_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = { + .cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup2_spi_apps_clk", + .parent = &blsp2_qup2_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup2_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup3_i2c_apps_clk = { + .cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup3_i2c_apps_clk", + .parent = &blsp2_qup3_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup3_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = { + .cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup3_spi_apps_clk", + .parent = &blsp2_qup3_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup3_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = { + .cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup4_i2c_apps_clk", + .parent = &blsp2_qup4_i2c_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup4_i2c_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = { + .cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_qup4_spi_apps_clk", + .parent = &blsp2_qup4_spi_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_qup4_spi_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_uart1_apps_clk = { + .cbcr_reg = BLSP2_UART1_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_uart1_apps_clk", + .parent = &blsp2_uart1_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_uart1_apps_clk.c), + }, +}; + +static struct branch_clk gcc_blsp2_uart2_apps_clk = { + .cbcr_reg = BLSP2_UART2_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_uart2_apps_clk", + .parent = &blsp2_uart2_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_blsp2_uart2_apps_clk.c), + }, +}; + +static struct branch_clk gcc_bimc_gpu_clk = { + .cbcr_reg = BIMC_GPU_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_bimc_gpu_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_bimc_gpu_clk.c), + }, +}; + +static struct branch_clk gcc_camss_cci_ahb_clk = { + .cbcr_reg = CAMSS_CCI_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_cci_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_cci_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_cci_clk = { + .cbcr_reg = CAMSS_CCI_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_cci_clk", + .parent = &cci_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_cci_clk.c), + }, +}; + +static struct branch_clk gcc_camss_cpp_ahb_clk = { + .cbcr_reg = CAMSS_CPP_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_cpp_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_cpp_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_cpp_axi_clk = { + .cbcr_reg = CAMSS_CPP_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_cpp_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_cpp_axi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_cpp_clk = { + .cbcr_reg = CAMSS_CPP_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_cpp_clk", + .parent = &cpp_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_cpp_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0_ahb_clk = { + .cbcr_reg = CAMSS_CSI0_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0_clk = { + .cbcr_reg = CAMSS_CSI0_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0_clk", + .parent = &csi0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0_csiphy_3p_clk = { + .cbcr_reg = CAMSS_CSI0_CSIPHY_3P_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0_csiphy_3p_clk", + .parent = &csi0p_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0_csiphy_3p_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0phy_clk = { + .cbcr_reg = CAMSS_CSI0PHY_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0phy_clk", + .parent = &csi0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0phy_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0pix_clk = { + .cbcr_reg = CAMSS_CSI0PIX_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0pix_clk", + .parent = &csi0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0pix_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0rdi_clk = { + .cbcr_reg = CAMSS_CSI0RDI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0rdi_clk", + .parent = &csi0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0rdi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1_ahb_clk = { + .cbcr_reg = CAMSS_CSI1_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1_clk = { + .cbcr_reg = CAMSS_CSI1_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1_clk", + .parent = &csi1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1_csiphy_3p_clk = { + .cbcr_reg = CAMSS_CSI1_CSIPHY_3P_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1_csiphy_3p_clk", + .parent = &csi1p_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1_csiphy_3p_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1phy_clk = { + .cbcr_reg = CAMSS_CSI1PHY_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1phy_clk", + .parent = &csi1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1phy_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1pix_clk = { + .cbcr_reg = CAMSS_CSI1PIX_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1pix_clk", + .parent = &csi1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1pix_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1rdi_clk = { + .cbcr_reg = CAMSS_CSI1RDI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1rdi_clk", + .parent = &csi1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1rdi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2_ahb_clk = { + .cbcr_reg = CAMSS_CSI2_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2_clk = { + .cbcr_reg = CAMSS_CSI2_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2_clk", + .parent = &csi2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2_csiphy_3p_clk = { + .cbcr_reg = CAMSS_CSI2_CSIPHY_3P_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2_csiphy_3p_clk", + .parent = &csi2p_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2_csiphy_3p_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2phy_clk = { + .cbcr_reg = CAMSS_CSI2PHY_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2phy_clk", + .parent = &csi2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2phy_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2pix_clk = { + .cbcr_reg = CAMSS_CSI2PIX_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2pix_clk", + .parent = &csi2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2pix_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2rdi_clk = { + .cbcr_reg = CAMSS_CSI2RDI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2rdi_clk", + .parent = &csi2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2rdi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi_vfe0_clk = { + .cbcr_reg = CAMSS_CSI_VFE0_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi_vfe0_clk", + .parent = &vfe0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi_vfe0_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi_vfe1_clk = { + .cbcr_reg = CAMSS_CSI_VFE1_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi_vfe1_clk", + .parent = &vfe1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi_vfe1_clk.c), + }, +}; + +static struct branch_clk gcc_camss_gp0_clk = { + .cbcr_reg = CAMSS_GP0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_gp0_clk", + .parent = &camss_gp0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_gp0_clk.c), + }, +}; + +static struct branch_clk gcc_camss_gp1_clk = { + .cbcr_reg = CAMSS_GP1_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_gp1_clk", + .parent = &camss_gp1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_gp1_clk.c), + }, +}; + +static struct branch_clk gcc_camss_ispif_ahb_clk = { + .cbcr_reg = CAMSS_ISPIF_AHB_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_ispif_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_ispif_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_jpeg0_clk = { + .cbcr_reg = CAMSS_JPEG0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_jpeg0_clk", + .parent = &jpeg0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_jpeg0_clk.c), + }, +}; + +static struct branch_clk gcc_camss_jpeg_ahb_clk = { + .cbcr_reg = CAMSS_JPEG_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_jpeg_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_jpeg_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_jpeg_axi_clk = { + .cbcr_reg = CAMSS_JPEG_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_jpeg_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_jpeg_axi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_mclk0_clk = { + .cbcr_reg = CAMSS_MCLK0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_mclk0_clk", + .parent = &mclk0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_mclk0_clk.c), + }, +}; + +static struct branch_clk gcc_camss_mclk1_clk = { + .cbcr_reg = CAMSS_MCLK1_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_mclk1_clk", + .parent = &mclk1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_mclk1_clk.c), + }, +}; + +static struct branch_clk gcc_camss_mclk2_clk = { + .cbcr_reg = CAMSS_MCLK2_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_mclk2_clk", + .parent = &mclk2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_mclk2_clk.c), + }, +}; + +static struct branch_clk gcc_camss_mclk3_clk = { + .cbcr_reg = CAMSS_MCLK3_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_mclk3_clk", + .parent = &mclk3_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_mclk3_clk.c), + }, +}; + +static struct branch_clk gcc_camss_micro_ahb_clk = { + .cbcr_reg = CAMSS_MICRO_AHB_CBCR, + .bcr_reg = CAMSS_MICRO_BCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_micro_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_micro_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi0phytimer_clk = { + .cbcr_reg = CAMSS_CSI0PHYTIMER_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi0phytimer_clk", + .parent = &csi0phytimer_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi0phytimer_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi1phytimer_clk = { + .cbcr_reg = CAMSS_CSI1PHYTIMER_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi1phytimer_clk", + .parent = &csi1phytimer_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi1phytimer_clk.c), + }, +}; + +static struct branch_clk gcc_camss_csi2phytimer_clk = { + .cbcr_reg = CAMSS_CSI2PHYTIMER_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_csi2phytimer_clk", + .parent = &csi2phytimer_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_csi2phytimer_clk.c), + }, +}; + +static struct branch_clk gcc_camss_ahb_clk = { + .cbcr_reg = CAMSS_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_top_ahb_clk = { + .cbcr_reg = CAMSS_TOP_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_top_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_top_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_vfe0_clk = { + .cbcr_reg = CAMSS_VFE0_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_vfe0_clk", + .parent = &vfe0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_vfe0_clk.c), + }, +}; + +static struct branch_clk gcc_camss_vfe_ahb_clk = { + .cbcr_reg = CAMSS_VFE_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_vfe_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_vfe_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_vfe_axi_clk = { + .cbcr_reg = CAMSS_VFE_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_vfe_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_vfe_axi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_vfe1_ahb_clk = { + .cbcr_reg = CAMSS_VFE1_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_vfe1_ahb_clk", + .parent = &camss_top_ahb_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_vfe1_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_camss_vfe1_axi_clk = { + .cbcr_reg = CAMSS_VFE1_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_vfe1_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_vfe1_axi_clk.c), + }, +}; + +static struct branch_clk gcc_camss_vfe1_clk = { + .cbcr_reg = CAMSS_VFE1_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_camss_vfe1_clk", + .parent = &vfe1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_camss_vfe1_clk.c), + }, +}; + +static struct branch_clk gcc_dcc_clk = { + .cbcr_reg = DCC_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_dcc_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_dcc_clk.c), + }, +}; + +static struct branch_clk gcc_gp1_clk = { + .cbcr_reg = GP1_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_gp1_clk", + .parent = &gp1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_gp1_clk.c), + }, +}; + +static struct branch_clk gcc_gp2_clk = { + .cbcr_reg = GP2_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_gp2_clk", + .parent = &gp2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_gp2_clk.c), + }, +}; + +static struct branch_clk gcc_gp3_clk = { + .cbcr_reg = GP3_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_gp3_clk", + .parent = &gp3_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_gp3_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_ahb_clk = { + .cbcr_reg = MDSS_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdss_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_mdss_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_axi_clk = { + .cbcr_reg = MDSS_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdss_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_mdss_axi_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_byte0_clk = { + .cbcr_reg = MDSS_BYTE0_CBCR, + .has_sibling = 0, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "gcc_mdss_byte0_clk", + .parent = &byte0_clk_src.c, + .ops = &clk_ops_branch, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(gcc_mdss_byte0_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_byte1_clk = { + .cbcr_reg = MDSS_BYTE1_CBCR, + .has_sibling = 0, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "gcc_mdss_byte1_clk", + .parent = &byte1_clk_src.c, + .ops = &clk_ops_branch, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(gcc_mdss_byte1_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_esc0_clk = { + .cbcr_reg = MDSS_ESC0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdss_esc0_clk", + .parent = &esc0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_mdss_esc0_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_esc1_clk = { + .cbcr_reg = MDSS_ESC1_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdss_esc1_clk", + .parent = &esc1_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_mdss_esc1_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_mdp_clk = { + .cbcr_reg = MDSS_MDP_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdss_mdp_clk", + .parent = &mdp_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_mdss_mdp_clk.c), + }, +}; + +static DEFINE_CLK_VOTER(mdss_mdp_vote_clk, &gcc_mdss_mdp_clk.c, 0); +static DEFINE_CLK_VOTER(mdss_rotator_vote_clk, &gcc_mdss_mdp_clk.c, 0); + +static struct branch_clk gcc_mdss_pclk0_clk = { + .cbcr_reg = MDSS_PCLK0_CBCR, + .has_sibling = 0, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "gcc_mdss_pclk0_clk", + .parent = &pclk0_clk_src.c, + .ops = &clk_ops_branch, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(gcc_mdss_pclk0_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_pclk1_clk = { + .cbcr_reg = MDSS_PCLK1_CBCR, + .has_sibling = 0, + .base = &virt_bases[MDSS_BASE], + .c = { + .dbg_name = "gcc_mdss_pclk1_clk", + .parent = &pclk1_clk_src.c, + .ops = &clk_ops_branch, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(gcc_mdss_pclk1_clk.c), + }, +}; + +static struct branch_clk gcc_mdss_vsync_clk = { + .cbcr_reg = MDSS_VSYNC_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdss_vsync_clk", + .parent = &vsync_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_mdss_vsync_clk.c), + }, +}; + +static struct branch_clk gcc_mss_cfg_ahb_clk = { + .cbcr_reg = MSS_CFG_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mss_cfg_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_mss_cfg_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_mss_q6_bimc_axi_clk = { + .cbcr_reg = MSS_Q6_BIMC_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mss_q6_bimc_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_mss_q6_bimc_axi_clk.c), + }, +}; + +static struct branch_clk gcc_bimc_gfx_clk = { + .cbcr_reg = BIMC_GFX_CBCR, + .has_sibling = 1, + .base = &virt_bases[GFX_BASE], + .c = { + .dbg_name = "gcc_bimc_gfx_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_bimc_gfx_clk.c), + }, +}; + +static struct branch_clk gcc_oxili_ahb_clk = { + .cbcr_reg = OXILI_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GFX_BASE], + .c = { + .dbg_name = "gcc_oxili_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_oxili_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_oxili_aon_clk = { + .cbcr_reg = OXILI_AON_CBCR, + .has_sibling = 1, + .base = &virt_bases[GFX_BASE], + .c = { + .dbg_name = "gcc_oxili_aon_clk", + .parent = &gfx3d_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_oxili_aon_clk.c), + }, +}; + +static struct branch_clk gcc_oxili_gfx3d_clk = { + .cbcr_reg = OXILI_GFX3D_CBCR, + .has_sibling = 0, + .base = &virt_bases[GFX_BASE], + .c = { + .dbg_name = "gcc_oxili_gfx3d_clk", + .parent = &gfx3d_clk_src.c, + .vdd_class = &vdd_gfx, + .ops = &clk_ops_branch, + CLK_INIT(gcc_oxili_gfx3d_clk.c), + }, +}; + +static struct branch_clk gcc_oxili_timer_clk = { + .cbcr_reg = OXILI_TIMER_CBCR, + .has_sibling = 0, + .base = &virt_bases[GFX_BASE], + .c = { + .dbg_name = "gcc_oxili_timer_clk", + .parent = &xo_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_oxili_timer_clk.c), + }, +}; + +static struct branch_clk gcc_pcnoc_usb3_axi_clk = { + .cbcr_reg = PCNOC_USB3_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_pcnoc_usb3_axi_clk", + .parent = &usb30_master_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_pcnoc_usb3_axi_clk.c), + }, +}; + +static struct branch_clk gcc_pdm2_clk = { + .cbcr_reg = PDM2_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_pdm2_clk", + .parent = &pdm2_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_pdm2_clk.c), + }, +}; + +static struct branch_clk gcc_pdm_ahb_clk = { + .cbcr_reg = PDM_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_pdm_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_pdm_ahb_clk.c), + }, +}; + + +static struct branch_clk gcc_rbcpr_gfx_clk = { + .cbcr_reg = RBCPR_GFX_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_rbcpr_gfx_clk", + .parent = &rbcpr_gfx_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_rbcpr_gfx_clk.c), + }, +}; + +static struct branch_clk gcc_sdcc1_ahb_clk = { + .cbcr_reg = SDCC1_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_sdcc1_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_sdcc1_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_sdcc1_apps_clk = { + .cbcr_reg = SDCC1_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_sdcc1_apps_clk", + .parent = &sdcc1_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_sdcc1_apps_clk.c), + }, +}; + +static struct branch_clk gcc_sdcc1_ice_core_clk = { + .cbcr_reg = SDCC1_ICE_CORE_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_sdcc1_ice_core_clk", + .parent = &sdcc1_ice_core_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_sdcc1_ice_core_clk.c), + }, +}; + +static struct branch_clk gcc_sdcc2_ahb_clk = { + .cbcr_reg = SDCC2_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_sdcc2_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_sdcc2_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_sdcc2_apps_clk = { + .cbcr_reg = SDCC2_APPS_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_sdcc2_apps_clk", + .parent = &sdcc2_apps_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_sdcc2_apps_clk.c), + }, +}; + +static struct branch_clk gcc_usb30_master_clk = { + .cbcr_reg = USB30_MASTER_CBCR, + .bcr_reg = USB_30_BCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb30_master_clk", + .parent = &usb30_master_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_usb30_master_clk.c), + }, +}; + +static struct branch_clk gcc_usb30_mock_utmi_clk = { + .cbcr_reg = USB30_MOCK_UTMI_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb30_mock_utmi_clk", + .parent = &usb30_mock_utmi_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_usb30_mock_utmi_clk.c), + }, +}; + +static struct branch_clk gcc_usb30_sleep_clk = { + .cbcr_reg = USB30_SLEEP_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb30_sleep_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_usb30_sleep_clk.c), + }, +}; + +static struct branch_clk gcc_usb3_aux_clk = { + .cbcr_reg = USB3_AUX_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb3_aux_clk", + .parent = &usb3_aux_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_usb3_aux_clk.c), + }, +}; + +static struct branch_clk gcc_usb_phy_cfg_ahb_clk = { + .cbcr_reg = USB_PHY_CFG_AHB_CBCR, + .has_sibling = 1, + .no_halt_check_on_disable = true, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb_phy_cfg_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_usb_phy_cfg_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_venus0_ahb_clk = { + .cbcr_reg = VENUS0_AHB_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_venus0_ahb_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_venus0_ahb_clk.c), + }, +}; + +static struct branch_clk gcc_venus0_axi_clk = { + .cbcr_reg = VENUS0_AXI_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_venus0_axi_clk", + .ops = &clk_ops_branch, + CLK_INIT(gcc_venus0_axi_clk.c), + }, +}; + +static struct branch_clk gcc_venus0_core0_vcodec0_clk = { + .cbcr_reg = VENUS0_CORE0_VCODEC0_CBCR, + .has_sibling = 1, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_venus0_core0_vcodec0_clk", + .parent = &vcodec0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_venus0_core0_vcodec0_clk.c), + }, +}; + +static struct branch_clk gcc_venus0_vcodec0_clk = { + .cbcr_reg = VENUS0_VCODEC0_CBCR, + .has_sibling = 0, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_venus0_vcodec0_clk", + .parent = &vcodec0_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(gcc_venus0_vcodec0_clk.c), + }, +}; + +static struct gate_clk gcc_qusb_ref_clk = { + .en_reg = QUSB_REF_CLK_EN, + .en_mask = BIT(0), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_qusb_ref_clk", + .ops = &clk_ops_gate, + CLK_INIT(gcc_qusb_ref_clk.c), + }, +}; + +static struct gate_clk gcc_usb_ss_ref_clk = { + .en_reg = USB_SS_REF_CLK_EN, + .en_mask = BIT(0), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb_ss_ref_clk", + .ops = &clk_ops_gate, + CLK_INIT(gcc_usb_ss_ref_clk.c), + }, +}; + +static struct gate_clk gcc_usb3_pipe_clk = { + .en_reg = USB3_PIPE_CBCR, + .en_mask = BIT(0), + .delay_us = 50, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb3_pipe_clk", + .ops = &clk_ops_gate, + CLK_INIT(gcc_usb3_pipe_clk.c), + }, +}; + +static struct reset_clk gcc_qusb2_phy_reset = { + .reset_reg = QUSB2_PHY_BCR, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_qusb2_phy_reset", + .ops = &clk_ops_rst, + CLK_INIT(gcc_qusb2_phy_reset.c), + }, +}; + +static struct reset_clk gcc_usb3_phy_reset = { + .reset_reg = USB3_PHY_BCR, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb3_phy_reset", + .ops = &clk_ops_rst, + CLK_INIT(gcc_usb3_phy_reset.c), + }, +}; + +static struct reset_clk gcc_usb3phy_phy_reset = { + .reset_reg = USB3PHY_PHY_BCR, + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_usb3phy_phy_reset", + .ops = &clk_ops_rst, + CLK_INIT(gcc_usb3phy_phy_reset.c), + }, +}; + +static struct local_vote_clk gcc_apss_ahb_clk = { + .cbcr_reg = APSS_AHB_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(14), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_apss_ahb_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_apss_ahb_clk.c), + }, +}; + +static struct local_vote_clk gcc_apss_axi_clk = { + .cbcr_reg = APSS_AXI_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(13), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_apss_axi_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_apss_axi_clk.c), + }, +}; + +static struct local_vote_clk gcc_blsp1_ahb_clk = { + .cbcr_reg = BLSP1_AHB_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(10), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp1_ahb_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_blsp1_ahb_clk.c), + }, +}; + + +static struct local_vote_clk gcc_blsp2_ahb_clk = { + .cbcr_reg = BLSP2_AHB_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(20), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_blsp2_ahb_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_blsp2_ahb_clk.c), + }, +}; + + +static struct local_vote_clk gcc_boot_rom_ahb_clk = { + .cbcr_reg = BOOT_ROM_AHB_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(7), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_boot_rom_ahb_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_boot_rom_ahb_clk.c), + }, +}; + + +static struct local_vote_clk gcc_crypto_ahb_clk = { + .cbcr_reg = CRYPTO_AHB_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(0), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_crypto_ahb_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_crypto_ahb_clk.c), + }, +}; + +static struct local_vote_clk gcc_crypto_axi_clk = { + .cbcr_reg = CRYPTO_AXI_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(1), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_crypto_axi_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_crypto_axi_clk.c), + }, +}; + +static struct local_vote_clk gcc_crypto_clk = { + .cbcr_reg = CRYPTO_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(2), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_crypto_clk", + .parent = &crypto_clk_src.c, + .ops = &clk_ops_vote, + CLK_INIT(gcc_crypto_clk.c), + }, +}; + +static struct local_vote_clk gcc_qdss_dap_clk = { + .cbcr_reg = QDSS_DAP_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(11), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_qdss_dap_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_qdss_dap_clk.c), + }, +}; + +static struct local_vote_clk gcc_prng_ahb_clk = { + .cbcr_reg = PRNG_AHB_CBCR, + .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(8), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_prng_ahb_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_prng_ahb_clk.c), + }, +}; + +static struct local_vote_clk gcc_apss_tcu_async_clk = { + .cbcr_reg = APSS_TCU_ASYNC_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(1), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_apss_tcu_async_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_apss_tcu_async_clk.c), + }, +}; + +static struct local_vote_clk gcc_cpp_tbu_clk = { + .cbcr_reg = CPP_TBU_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(14), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_cpp_tbu_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_cpp_tbu_clk.c), + }, +}; + +static struct local_vote_clk gcc_jpeg_tbu_clk = { + .cbcr_reg = JPEG_TBU_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(10), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_jpeg_tbu_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_jpeg_tbu_clk.c), + }, +}; + +static struct local_vote_clk gcc_mdp_tbu_clk = { + .cbcr_reg = MDP_TBU_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(4), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_mdp_tbu_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_mdp_tbu_clk.c), + }, +}; + +static struct local_vote_clk gcc_smmu_cfg_clk = { + .cbcr_reg = SMMU_CFG_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(12), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_smmu_cfg_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_smmu_cfg_clk.c), + }, +}; + +static struct local_vote_clk gcc_venus_tbu_clk = { + .cbcr_reg = VENUS_TBU_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(5), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_venus_tbu_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_venus_tbu_clk.c), + }, +}; + +static struct local_vote_clk gcc_vfe1_tbu_clk = { + .cbcr_reg = VFE1_TBU_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(17), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_vfe1_tbu_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_vfe1_tbu_clk.c), + }, +}; + +static struct local_vote_clk gcc_vfe_tbu_clk = { + .cbcr_reg = VFE_TBU_CBCR, + .vote_reg = APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, + .en_mask = BIT(9), + .base = &virt_bases[GCC_BASE], + .c = { + .dbg_name = "gcc_vfe_tbu_clk", + .ops = &clk_ops_vote, + CLK_INIT(gcc_vfe_tbu_clk.c), + }, +}; + + +static struct clk_ops clk_ops_debug_mux; + +static struct measure_clk_data debug_mux_priv = { + .cxo = &xo_clk_src.c, + .plltest_reg = PLLTEST_PAD_CFG, + .plltest_val = 0x51A00, + .xo_div4_cbcr = GCC_XO_DIV4_CBCR, + .ctl_reg = CLOCK_FRQ_MEASURE_CTL, + .status_reg = CLOCK_FRQ_MEASURE_STATUS, + .base = &virt_bases[GCC_BASE], +}; + +static struct mux_clk gcc_debug_mux = { + .priv = &debug_mux_priv, + .ops = &mux_reg_ops, + .offset = GCC_DEBUG_CLK_CTL, + .mask = 0x1FF, + .en_offset = GCC_DEBUG_CLK_CTL, + .en_mask = BIT(16), + .base = &virt_bases[GCC_BASE], + MUX_REC_SRC_LIST( + &debug_cpu_clk.c, + ), + MUX_SRC_LIST( + { &debug_cpu_clk.c, 0x016A }, + { &snoc_clk.c, 0x0000 }, + { &sysmmnoc_clk.c, 0x0001 }, + { &pcnoc_clk.c, 0x0008 }, + { &bimc_clk.c, 0x15A }, + { &ipa_clk.c, 0x1b0 }, + { &gcc_dcc_clk.c, 0x000d }, + { &gcc_pcnoc_usb3_axi_clk.c, 0x000e }, + { &gcc_gp1_clk.c, 0x0010 }, + { &gcc_gp2_clk.c, 0x0011 }, + { &gcc_gp3_clk.c, 0x0012 }, + { &gcc_apc0_droop_detector_gpll0_clk.c, 0x001c }, + { &gcc_camss_csi2phytimer_clk.c, 0x001d }, + { &gcc_apc1_droop_detector_gpll0_clk.c, 0x001f }, + { &gcc_bimc_gfx_clk.c, 0x002d }, + { &gcc_mss_cfg_ahb_clk.c, 0x0030 }, + { &gcc_mss_q6_bimc_axi_clk.c, 0x0031 }, + { &gcc_qdss_dap_clk.c, 0x0049 }, + { &gcc_apss_tcu_async_clk.c, 0x0050 }, + { &gcc_mdp_tbu_clk.c, 0x0051 }, + { &gcc_venus_tbu_clk.c, 0x0054 }, + { &gcc_vfe_tbu_clk.c, 0x005a }, + { &gcc_smmu_cfg_clk.c, 0x005b }, + { &gcc_jpeg_tbu_clk.c, 0x005c }, + { &gcc_usb30_master_clk.c, 0x0060 }, + { &gcc_usb30_sleep_clk.c, 0x0061 }, + { &gcc_usb30_mock_utmi_clk.c, 0x0062 }, + { &gcc_usb_phy_cfg_ahb_clk.c, 0x0063 }, + { &gcc_usb3_pipe_clk.c, 0x0066 }, + { &gcc_usb3_aux_clk.c, 0x0067 }, + { &gcc_sdcc1_apps_clk.c, 0x0068 }, + { &gcc_sdcc1_ahb_clk.c, 0x0069 }, + { &gcc_sdcc1_ice_core_clk.c, 0x006a }, + { &gcc_sdcc2_apps_clk.c, 0x0070 }, + { &gcc_sdcc2_ahb_clk.c, 0x0071 }, + { &gcc_blsp1_ahb_clk.c, 0x0088 }, + { &gcc_blsp1_qup1_spi_apps_clk.c, 0x008a }, + { &gcc_blsp1_qup1_i2c_apps_clk.c, 0x008b }, + { &gcc_blsp1_uart1_apps_clk.c, 0x008c }, + { &gcc_blsp1_qup2_spi_apps_clk.c, 0x008e }, + { &gcc_blsp1_qup2_i2c_apps_clk.c, 0x0090 }, + { &gcc_blsp1_uart2_apps_clk.c, 0x0091 }, + { &gcc_blsp1_qup3_spi_apps_clk.c, 0x0093 }, + { &gcc_blsp1_qup3_i2c_apps_clk.c, 0x0094 }, + { &gcc_blsp1_qup4_spi_apps_clk.c, 0x0095 }, + { &gcc_blsp1_qup4_i2c_apps_clk.c, 0x0096 }, + { &gcc_blsp2_ahb_clk.c, 0x0098 }, + { &gcc_blsp2_qup1_spi_apps_clk.c, 0x009a }, + { &gcc_blsp2_qup1_i2c_apps_clk.c, 0x009b }, + { &gcc_blsp2_uart1_apps_clk.c, 0x009c }, + { &gcc_blsp2_qup2_spi_apps_clk.c, 0x009e }, + { &gcc_blsp2_qup2_i2c_apps_clk.c, 0x00a0 }, + { &gcc_blsp2_uart2_apps_clk.c, 0x00a1 }, + { &gcc_blsp2_qup3_spi_apps_clk.c, 0x00a3 }, + { &gcc_blsp2_qup3_i2c_apps_clk.c, 0x00a4 }, + { &gcc_blsp2_qup4_spi_apps_clk.c, 0x00a5 }, + { &gcc_blsp2_qup4_i2c_apps_clk.c, 0x00a6 }, + { &gcc_camss_ahb_clk.c, 0x00a8 }, + { &gcc_camss_top_ahb_clk.c, 0x00a9 }, + { &gcc_camss_micro_ahb_clk.c, 0x00aa }, + { &gcc_camss_gp0_clk.c, 0x00ab }, + { &gcc_camss_gp1_clk.c, 0x00ac }, + { &gcc_camss_mclk0_clk.c, 0x00ad }, + { &gcc_camss_mclk1_clk.c, 0x00ae }, + { &gcc_camss_cci_clk.c, 0x00af }, + { &gcc_camss_cci_ahb_clk.c, 0x00b0 }, + { &gcc_camss_csi0phytimer_clk.c, 0x00b1 }, + { &gcc_camss_csi1phytimer_clk.c, 0x00b2 }, + { &gcc_camss_jpeg0_clk.c, 0x00b3 }, + { &gcc_camss_jpeg_ahb_clk.c, 0x00b4 }, + { &gcc_camss_jpeg_axi_clk.c, 0x00b5 }, + { &gcc_camss_vfe0_clk.c, 0x00b8 }, + { &gcc_camss_cpp_clk.c, 0x00b9 }, + { &gcc_camss_cpp_ahb_clk.c, 0x00ba }, + { &gcc_camss_vfe_ahb_clk.c, 0x00bb }, + { &gcc_camss_vfe_axi_clk.c, 0x00bc }, + { &gcc_camss_csi_vfe0_clk.c, 0x00bf }, + { &gcc_camss_csi0_clk.c, 0x00c0 }, + { &gcc_camss_csi0_ahb_clk.c, 0x00c1 }, + { &gcc_camss_csi0phy_clk.c, 0x00c2 }, + { &gcc_camss_csi0rdi_clk.c, 0x00c3 }, + { &gcc_camss_csi0pix_clk.c, 0x00c4 }, + { &gcc_camss_csi1_clk.c, 0x00c5 }, + { &gcc_camss_csi1_ahb_clk.c, 0x00c6 }, + { &gcc_camss_csi1phy_clk.c, 0x00c7 }, + { &gcc_pdm_ahb_clk.c, 0x00d0 }, + { &gcc_pdm2_clk.c, 0x00d2 }, + { &gcc_prng_ahb_clk.c, 0x00d8 }, + { &gcc_mdss_byte1_clk.c, 0x00da }, + { &gcc_mdss_esc1_clk.c, 0x00db }, + { &gcc_camss_csi0_csiphy_3p_clk.c, 0x00dc }, + { &gcc_camss_csi1_csiphy_3p_clk.c, 0x00dd }, + { &gcc_camss_csi2_csiphy_3p_clk.c, 0x00de }, + { &gcc_camss_csi1rdi_clk.c, 0x00e0 }, + { &gcc_camss_csi1pix_clk.c, 0x00e1 }, + { &gcc_camss_ispif_ahb_clk.c, 0x00e2 }, + { &gcc_camss_csi2_clk.c, 0x00e3 }, + { &gcc_camss_csi2_ahb_clk.c, 0x00e4 }, + { &gcc_camss_csi2phy_clk.c, 0x00e5 }, + { &gcc_camss_csi2rdi_clk.c, 0x00e6 }, + { &gcc_camss_csi2pix_clk.c, 0x00e7 }, + { &gcc_cpp_tbu_clk.c, 0x00e9 }, + { &gcc_rbcpr_gfx_clk.c, 0x00f0 }, + { &gcc_boot_rom_ahb_clk.c, 0x00f8 }, + { &gcc_crypto_clk.c, 0x0138 }, + { &gcc_crypto_axi_clk.c, 0x0139 }, + { &gcc_crypto_ahb_clk.c, 0x013a }, + { &gcc_bimc_gpu_clk.c, 0x0157 }, + { &gcc_apss_ahb_clk.c, 0x0168 }, + { &gcc_apss_axi_clk.c, 0x0169 }, + { &gcc_vfe1_tbu_clk.c, 0x0199 }, + { &gcc_camss_csi_vfe1_clk.c, 0x01a0 }, + { &gcc_camss_vfe1_clk.c, 0x01a1 }, + { &gcc_camss_vfe1_ahb_clk.c, 0x01a2 }, + { &gcc_camss_vfe1_axi_clk.c, 0x01a3 }, + { &gcc_camss_cpp_axi_clk.c, 0x01a4 }, + { &gcc_venus0_core0_vcodec0_clk.c, 0x01b8 }, + { &gcc_camss_mclk2_clk.c, 0x01bd }, + { &gcc_camss_mclk3_clk.c, 0x01bf }, + { &gcc_oxili_aon_clk.c, 0x01e8 }, + { &gcc_oxili_timer_clk.c, 0x01e9 }, + { &gcc_oxili_gfx3d_clk.c, 0x01ea }, + { &gcc_oxili_ahb_clk.c, 0x01eb }, + { &gcc_venus0_vcodec0_clk.c, 0x01f1 }, + { &gcc_venus0_axi_clk.c, 0x01f2 }, + { &gcc_venus0_ahb_clk.c, 0x01f3 }, + { &gcc_mdss_ahb_clk.c, 0x01f6 }, + { &gcc_mdss_axi_clk.c, 0x01f7 }, + { &gcc_mdss_pclk0_clk.c, 0x01f8 }, + { &gcc_mdss_mdp_clk.c, 0x01f9 }, + { &gcc_mdss_pclk1_clk.c, 0x01fa }, + { &gcc_mdss_vsync_clk.c, 0x01fb }, + { &gcc_mdss_byte0_clk.c, 0x01fc }, + { &gcc_mdss_esc0_clk.c, 0x01fd }, + { &wcnss_m_clk.c, 0x0ec }, + ), + .c = { + .dbg_name = "gcc_debug_mux", + .ops = &clk_ops_debug_mux, + .flags = CLKFLAG_NO_RATE_CACHE | CLKFLAG_MEASURE, + CLK_INIT(gcc_debug_mux.c), + }, +}; + + +static struct clk_lookup msm_clocks_lookup[] = { + CLK_LIST(xo_clk_src), + CLK_LIST(xo_a_clk_src), + CLK_LIST(bimc_clk), + CLK_LIST(bimc_a_clk), + CLK_LIST(pcnoc_clk), + CLK_LIST(pcnoc_a_clk), + CLK_LIST(snoc_clk), + CLK_LIST(snoc_a_clk), + CLK_LIST(sysmmnoc_clk), + CLK_LIST(sysmmnoc_a_clk), + CLK_LIST(ipa_clk), + CLK_LIST(ipa_a_clk), + CLK_LIST(qdss_clk), + CLK_LIST(qdss_a_clk), + CLK_LIST(bimc_msmbus_clk), + CLK_LIST(bimc_msmbus_a_clk), + CLK_LIST(bimc_usb_clk), + CLK_LIST(bimc_usb_a_clk), + CLK_LIST(bimc_wcnss_a_clk), + CLK_LIST(pcnoc_keepalive_a_clk), + CLK_LIST(pcnoc_msmbus_clk), + CLK_LIST(pcnoc_msmbus_a_clk), + CLK_LIST(pcnoc_usb_clk), + CLK_LIST(pcnoc_usb_a_clk), + CLK_LIST(snoc_msmbus_clk), + CLK_LIST(snoc_msmbus_a_clk), + CLK_LIST(snoc_usb_clk), + CLK_LIST(snoc_usb_a_clk), + CLK_LIST(snoc_wcnss_a_clk), + CLK_LIST(sysmmnoc_msmbus_clk), + CLK_LIST(sysmmnoc_msmbus_a_clk), + CLK_LIST(xo_dwc3_clk), + CLK_LIST(xo_lpm_clk), + CLK_LIST(xo_pil_lpass_clk), + CLK_LIST(xo_pil_mss_clk), + CLK_LIST(xo_pil_pronto_clk), + CLK_LIST(xo_wlan_clk), + CLK_LIST(wcnss_m_clk), + CLK_LIST(rf_clk2), + CLK_LIST(rf_clk2_a), + CLK_LIST(rf_clk3), + CLK_LIST(rf_clk3_a), + CLK_LIST(bb_clk1), + CLK_LIST(bb_clk1_a), + CLK_LIST(bb_clk1_pin), + CLK_LIST(bb_clk1_a_pin), + CLK_LIST(bb_clk2), + CLK_LIST(bb_clk2_a), + CLK_LIST(bb_clk2_pin), + CLK_LIST(bb_clk2_a_pin), + CLK_LIST(div_clk2), + CLK_LIST(div_clk2_a), + CLK_LIST(gpll0_clk_src), + CLK_LIST(gpll6_clk_src), + CLK_LIST(gpll2_clk_src), + CLK_LIST(gpll4_clk_src), + CLK_LIST(gpll3_clk_src), + CLK_LIST(gcc_apss_ahb_clk), + CLK_LIST(gcc_apss_axi_clk), + CLK_LIST(gcc_blsp1_ahb_clk), + CLK_LIST(gcc_blsp2_ahb_clk), + CLK_LIST(gcc_boot_rom_ahb_clk), + CLK_LIST(gcc_crypto_ahb_clk), + CLK_LIST(gcc_crypto_axi_clk), + CLK_LIST(gcc_crypto_clk), + CLK_LIST(gcc_prng_ahb_clk), + CLK_LIST(gcc_qdss_dap_clk), + CLK_LIST(gcc_apss_tcu_async_clk), + CLK_LIST(gcc_cpp_tbu_clk), + CLK_LIST(gcc_jpeg_tbu_clk), + CLK_LIST(gcc_mdp_tbu_clk), + CLK_LIST(gcc_smmu_cfg_clk), + CLK_LIST(gcc_venus_tbu_clk), + CLK_LIST(gcc_vfe1_tbu_clk), + CLK_LIST(gcc_vfe_tbu_clk), + CLK_LIST(camss_top_ahb_clk_src), + CLK_LIST(csi0_clk_src), + CLK_LIST(apss_ahb_clk_src), + CLK_LIST(csi1_clk_src), + CLK_LIST(csi2_clk_src), + CLK_LIST(vfe0_clk_src), + CLK_LIST(vcodec0_clk_src), + CLK_LIST(cpp_clk_src), + CLK_LIST(jpeg0_clk_src), + CLK_LIST(usb30_master_clk_src), + CLK_LIST(vfe1_clk_src), + CLK_LIST(apc0_droop_detector_clk_src), + CLK_LIST(apc1_droop_detector_clk_src), + CLK_LIST(blsp1_qup1_i2c_apps_clk_src), + CLK_LIST(blsp1_qup1_spi_apps_clk_src), + CLK_LIST(blsp1_qup2_i2c_apps_clk_src), + CLK_LIST(blsp1_qup2_spi_apps_clk_src), + CLK_LIST(blsp1_qup3_i2c_apps_clk_src), + CLK_LIST(blsp1_qup3_spi_apps_clk_src), + CLK_LIST(blsp1_qup4_i2c_apps_clk_src), + CLK_LIST(blsp1_qup4_spi_apps_clk_src), + CLK_LIST(blsp1_uart1_apps_clk_src), + CLK_LIST(blsp1_uart2_apps_clk_src), + CLK_LIST(blsp2_qup1_i2c_apps_clk_src), + CLK_LIST(blsp2_qup1_spi_apps_clk_src), + CLK_LIST(blsp2_qup2_i2c_apps_clk_src), + CLK_LIST(blsp2_qup2_spi_apps_clk_src), + CLK_LIST(blsp2_qup3_i2c_apps_clk_src), + CLK_LIST(blsp2_qup3_spi_apps_clk_src), + CLK_LIST(blsp2_qup4_i2c_apps_clk_src), + CLK_LIST(blsp2_qup4_spi_apps_clk_src), + CLK_LIST(blsp2_uart1_apps_clk_src), + CLK_LIST(blsp2_uart2_apps_clk_src), + CLK_LIST(cci_clk_src), + CLK_LIST(csi0p_clk_src), + CLK_LIST(csi1p_clk_src), + CLK_LIST(csi2p_clk_src), + CLK_LIST(camss_gp0_clk_src), + CLK_LIST(camss_gp1_clk_src), + CLK_LIST(mclk0_clk_src), + CLK_LIST(mclk1_clk_src), + CLK_LIST(mclk2_clk_src), + CLK_LIST(mclk3_clk_src), + CLK_LIST(csi0phytimer_clk_src), + CLK_LIST(csi1phytimer_clk_src), + CLK_LIST(csi2phytimer_clk_src), + CLK_LIST(crypto_clk_src), + CLK_LIST(gp1_clk_src), + CLK_LIST(gp2_clk_src), + CLK_LIST(gp3_clk_src), + CLK_LIST(pdm2_clk_src), + CLK_LIST(rbcpr_gfx_clk_src), + CLK_LIST(sdcc1_apps_clk_src), + CLK_LIST(sdcc1_ice_core_clk_src), + CLK_LIST(sdcc2_apps_clk_src), + CLK_LIST(usb30_mock_utmi_clk_src), + CLK_LIST(usb3_aux_clk_src), + CLK_LIST(gcc_apc0_droop_detector_gpll0_clk), + CLK_LIST(gcc_apc1_droop_detector_gpll0_clk), + CLK_LIST(gcc_blsp1_qup1_i2c_apps_clk), + CLK_LIST(gcc_blsp1_qup1_spi_apps_clk), + CLK_LIST(gcc_blsp1_qup2_i2c_apps_clk), + CLK_LIST(gcc_blsp1_qup2_spi_apps_clk), + CLK_LIST(gcc_blsp1_qup3_i2c_apps_clk), + CLK_LIST(gcc_blsp1_qup3_spi_apps_clk), + CLK_LIST(gcc_blsp1_qup4_i2c_apps_clk), + CLK_LIST(gcc_blsp1_qup4_spi_apps_clk), + CLK_LIST(gcc_blsp1_uart1_apps_clk), + CLK_LIST(gcc_blsp1_uart2_apps_clk), + CLK_LIST(gcc_blsp2_qup1_i2c_apps_clk), + CLK_LIST(gcc_blsp2_qup1_spi_apps_clk), + CLK_LIST(gcc_blsp2_qup2_i2c_apps_clk), + CLK_LIST(gcc_blsp2_qup2_spi_apps_clk), + CLK_LIST(gcc_blsp2_qup3_i2c_apps_clk), + CLK_LIST(gcc_blsp2_qup3_spi_apps_clk), + CLK_LIST(gcc_blsp2_qup4_i2c_apps_clk), + CLK_LIST(gcc_blsp2_qup4_spi_apps_clk), + CLK_LIST(gcc_blsp2_uart1_apps_clk), + CLK_LIST(gcc_blsp2_uart2_apps_clk), + CLK_LIST(gcc_camss_cci_ahb_clk), + CLK_LIST(gcc_camss_cci_clk), + CLK_LIST(gcc_camss_cpp_ahb_clk), + CLK_LIST(gcc_camss_cpp_axi_clk), + CLK_LIST(gcc_camss_cpp_clk), + CLK_LIST(gcc_camss_csi0_ahb_clk), + CLK_LIST(gcc_camss_csi0_clk), + CLK_LIST(gcc_camss_csi0_csiphy_3p_clk), + CLK_LIST(gcc_camss_csi0phy_clk), + CLK_LIST(gcc_camss_csi0pix_clk), + CLK_LIST(gcc_camss_csi0rdi_clk), + CLK_LIST(gcc_camss_csi1_ahb_clk), + CLK_LIST(gcc_camss_csi1_clk), + CLK_LIST(gcc_camss_csi1_csiphy_3p_clk), + CLK_LIST(gcc_camss_csi1phy_clk), + CLK_LIST(gcc_camss_csi1pix_clk), + CLK_LIST(gcc_camss_csi1rdi_clk), + CLK_LIST(gcc_camss_csi2_ahb_clk), + CLK_LIST(gcc_camss_csi2_clk), + CLK_LIST(gcc_camss_csi2_csiphy_3p_clk), + CLK_LIST(gcc_camss_csi2phy_clk), + CLK_LIST(gcc_camss_csi2pix_clk), + CLK_LIST(gcc_camss_csi2rdi_clk), + CLK_LIST(gcc_camss_csi_vfe0_clk), + CLK_LIST(gcc_camss_csi_vfe1_clk), + CLK_LIST(gcc_camss_gp0_clk), + CLK_LIST(gcc_camss_gp1_clk), + CLK_LIST(gcc_camss_ispif_ahb_clk), + CLK_LIST(gcc_camss_jpeg0_clk), + CLK_LIST(gcc_camss_jpeg_ahb_clk), + CLK_LIST(gcc_camss_jpeg_axi_clk), + CLK_LIST(gcc_camss_mclk0_clk), + CLK_LIST(gcc_camss_mclk1_clk), + CLK_LIST(gcc_camss_mclk2_clk), + CLK_LIST(gcc_camss_mclk3_clk), + CLK_LIST(gcc_camss_micro_ahb_clk), + CLK_LIST(gcc_camss_csi0phytimer_clk), + CLK_LIST(gcc_camss_csi1phytimer_clk), + CLK_LIST(gcc_camss_csi2phytimer_clk), + CLK_LIST(gcc_camss_ahb_clk), + CLK_LIST(gcc_camss_top_ahb_clk), + CLK_LIST(gcc_camss_vfe0_clk), + CLK_LIST(gcc_camss_vfe_ahb_clk), + CLK_LIST(gcc_camss_vfe_axi_clk), + CLK_LIST(gcc_camss_vfe1_ahb_clk), + CLK_LIST(gcc_camss_vfe1_axi_clk), + CLK_LIST(gcc_camss_vfe1_clk), + CLK_LIST(gcc_dcc_clk), + CLK_LIST(gcc_gp1_clk), + CLK_LIST(gcc_gp2_clk), + CLK_LIST(gcc_gp3_clk), + CLK_LIST(gcc_mss_cfg_ahb_clk), + CLK_LIST(gcc_mss_q6_bimc_axi_clk), + CLK_LIST(gcc_pcnoc_usb3_axi_clk), + CLK_LIST(gcc_pdm2_clk), + CLK_LIST(gcc_pdm_ahb_clk), + CLK_LIST(gcc_rbcpr_gfx_clk), + CLK_LIST(gcc_sdcc1_ahb_clk), + CLK_LIST(gcc_sdcc1_apps_clk), + CLK_LIST(gcc_sdcc1_ice_core_clk), + CLK_LIST(gcc_sdcc2_ahb_clk), + CLK_LIST(gcc_sdcc2_apps_clk), + CLK_LIST(gcc_usb30_master_clk), + CLK_LIST(gcc_usb30_mock_utmi_clk), + CLK_LIST(gcc_usb30_sleep_clk), + CLK_LIST(gcc_usb3_aux_clk), + CLK_LIST(gcc_usb_phy_cfg_ahb_clk), + CLK_LIST(gcc_venus0_ahb_clk), + CLK_LIST(gcc_venus0_axi_clk), + CLK_LIST(gcc_venus0_core0_vcodec0_clk), + CLK_LIST(gcc_venus0_vcodec0_clk), + CLK_LIST(gcc_qusb_ref_clk), + CLK_LIST(gcc_usb_ss_ref_clk), + CLK_LIST(gcc_usb3_pipe_clk), + CLK_LIST(gcc_qusb2_phy_reset), + CLK_LIST(gcc_usb3_phy_reset), + CLK_LIST(gcc_usb3phy_phy_reset), + + CLK_LIST(mdp_clk_src), + CLK_LIST(esc0_clk_src), + CLK_LIST(esc1_clk_src), + CLK_LIST(vsync_clk_src), + CLK_LIST(gcc_mdss_ahb_clk), + CLK_LIST(gcc_mdss_axi_clk), + CLK_LIST(gcc_mdss_esc0_clk), + CLK_LIST(gcc_mdss_esc1_clk), + CLK_LIST(gcc_mdss_mdp_clk), + CLK_LIST(gcc_mdss_vsync_clk), +}; + +static const struct msm_reset_map gcc_8953_resets[] = { + + [GCC_QUSB2_PHY_BCR] = { 0x4103C }, + [GCC_USB3_PHY_BCR] = { 0x3F034 }, + [GCC_USB3PHY_PHY_BCR] = { 0x3F03C }, + [GCC_USB_30_BCR] = { 0x3F070 }, + [GCC_CAMSS_MICRO_BCR] = {0x56008}, + +}; +#define SPEED_BIN 7 + +static void override_for_8953(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + u32 config_efuse, bin; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse"); + if (!res) + return; + + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!base) { + dev_warn(&pdev->dev, + "Unable to ioremap efuse reg address. Defaulting to 0.\n"); + return; + } + + config_efuse = readl_relaxed(base); + devm_iounmap(&pdev->dev, base); + + bin = (config_efuse >> 8) & 0x7; + + if (bin == SPEED_BIN) { + vcodec0_clk_src.freq_tbl = ftbl_vcodec0_clk_src_540MHz; + vcodec0_clk_src.c.fmax[VDD_DIG_HIGH] = 540000000; + } + + dev_info(&pdev->dev, "Venus speed bin: %u\n", bin); +} + +static int msm_gcc_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + u32 regval; + + ret = vote_bimc(&bimc_clk, INT_MAX); + if (ret < 0) + return ret; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base"); + if (!res) { + dev_err(&pdev->dev, "Register base not defined\n"); + return -ENOMEM; + } + + virt_bases[GCC_BASE] = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!virt_bases[GCC_BASE]) { + dev_err(&pdev->dev, "Failed to ioremap CC registers\n"); + return -ENOMEM; + } + + vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig"); + if (IS_ERR(vdd_dig.regulator[0])) { + if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_dig regulator!!!\n"); + return PTR_ERR(vdd_dig.regulator[0]); + } + + override_for_8953(pdev); + + /*Vote for GPLL0 to turn on. Needed by acpuclock. */ + regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE)); + regval |= BIT(0); + writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE)); + + ret = of_msm_clock_register(pdev->dev.of_node, + msm_clocks_lookup, + ARRAY_SIZE(msm_clocks_lookup)); + if (ret) + return ret; + + ret = enable_rpm_scaling(); + if (ret < 0) { + dev_err(&pdev->dev, "rpm scaling failed to enable %d\n", ret); + return ret; + } + + clk_set_rate(&apss_ahb_clk_src.c, 19200000); + clk_prepare_enable(&apss_ahb_clk_src.c); + + clk_prepare_enable(&gcc_blsp1_ahb_clk.c); + clk_prepare_enable(&gcc_usb30_master_clk.c); + clk_prepare_enable(&gcc_usb30_mock_utmi_clk.c); + clk_prepare_enable(&gcc_blsp1_uart1_apps_clk.c); + clk_prepare_enable(&gcc_apss_ahb_clk.c); + clk_prepare_enable(&gcc_crypto_ahb_clk.c); + clk_prepare_enable(&gcc_crypto_axi_clk.c); + /* + * Hold an active set vote for PCNOC AHB source. Sleep set + * vote is 0. + */ + clk_set_rate(&pcnoc_keepalive_a_clk.c, 19200000); + clk_prepare_enable(&pcnoc_keepalive_a_clk.c); + + clk_prepare_enable(&xo_a_clk_src.c); + msm_reset_controller_register(pdev, gcc_8953_resets, + ARRAY_SIZE(gcc_8953_resets), virt_bases[GCC_BASE]); + + dev_info(&pdev->dev, "Registered GCC clocks\n"); + + return 0; +} + +static const struct of_device_id msm_clock_gcc_match_table[] = { + { .compatible = "qcom,gcc-8953" }, + {}, +}; + +static struct platform_driver msm_clock_gcc_driver = { + .probe = msm_gcc_probe, + .driver = { + .name = "qcom,gcc-8953", + .of_match_table = msm_clock_gcc_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_gcc_init(void) +{ + return platform_driver_register(&msm_clock_gcc_driver); +} +arch_initcall(msm_gcc_init); + +static struct clk_lookup msm_clocks_measure[] = { + CLK_LOOKUP_OF("measure", gcc_debug_mux, "debug"), + CLK_LIST(debug_cpu_clk), +}; + +static int msm_clock_debug_probe(struct platform_device *pdev) +{ + int ret; + + clk_ops_debug_mux = clk_ops_gen_mux; + clk_ops_debug_mux.get_rate = measure_get_rate; + + debug_cpu_clk.c.parent = devm_clk_get(&pdev->dev, "debug_cpu_clk"); + if (IS_ERR(debug_cpu_clk.c.parent)) { + dev_err(&pdev->dev, "Failed to get CPU debug Mux\n"); + return PTR_ERR(debug_cpu_clk.c.parent); + } + + ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_measure, + ARRAY_SIZE(msm_clocks_measure)); + if (ret) { + dev_err(&pdev->dev, "Failed to register debug Mux\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Debug Mux successfully\n"); + return ret; +} + +static const struct of_device_id msm_clock_debug_match_table[] = { + { .compatible = "qcom,cc-debug-8953" }, + {} +}; + +static struct platform_driver msm_clock_debug_driver = { + .probe = msm_clock_debug_probe, + .driver = { + .name = "qcom,cc-debug-8953", + .of_match_table = msm_clock_debug_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_clock_debug_init(void) +{ + return platform_driver_register(&msm_clock_debug_driver); +} +late_initcall(msm_clock_debug_init); + +/* MDSS DSI_PHY_PLL */ +static struct clk_lookup msm_clocks_gcc_mdss[] = { + CLK_LIST(ext_pclk0_clk_src), + CLK_LIST(ext_pclk1_clk_src), + CLK_LIST(ext_byte0_clk_src), + CLK_LIST(ext_byte1_clk_src), + CLK_LIST(pclk0_clk_src), + CLK_LIST(pclk1_clk_src), + CLK_LIST(byte0_clk_src), + CLK_LIST(byte1_clk_src), + CLK_LIST(gcc_mdss_pclk0_clk), + CLK_LIST(gcc_mdss_pclk1_clk), + CLK_LIST(gcc_mdss_byte0_clk), + CLK_LIST(gcc_mdss_byte1_clk), + CLK_LIST(mdss_mdp_vote_clk), + CLK_LIST(mdss_rotator_vote_clk), +}; + +static int msm_gcc_mdss_probe(struct platform_device *pdev) +{ + int ret = 0; + struct clk *curr_p; + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base"); + if (!res) { + dev_err(&pdev->dev, "Register base not defined\n"); + return -ENOMEM; + } + + virt_bases[MDSS_BASE] = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!virt_bases[MDSS_BASE]) { + dev_err(&pdev->dev, "Failed to ioremap CC registers\n"); + return -ENOMEM; + } + + curr_p = ext_pclk0_clk_src.c.parent = devm_clk_get(&pdev->dev, + "pclk0_src"); + if (IS_ERR(curr_p)) { + dev_err(&pdev->dev, "Failed to get pclk0 source.\n"); + return PTR_ERR(curr_p); + } + + curr_p = ext_pclk1_clk_src.c.parent = devm_clk_get(&pdev->dev, + "pclk1_src"); + if (IS_ERR(curr_p)) { + dev_err(&pdev->dev, "Failed to get pclk1 source.\n"); + ret = PTR_ERR(curr_p); + goto pclk1_fail; + } + + curr_p = ext_byte0_clk_src.c.parent = devm_clk_get(&pdev->dev, + "byte0_src"); + if (IS_ERR(curr_p)) { + dev_err(&pdev->dev, "Failed to get byte0 source.\n"); + ret = PTR_ERR(curr_p); + goto byte0_fail; + } + + curr_p = ext_byte1_clk_src.c.parent = devm_clk_get(&pdev->dev, + "byte1_src"); + if (IS_ERR(curr_p)) { + dev_err(&pdev->dev, "Failed to get byte1 source.\n"); + ret = PTR_ERR(curr_p); + goto byte1_fail; + } + + ext_pclk0_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE; + ext_pclk1_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE; + ext_byte0_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE; + ext_byte1_clk_src.c.flags = CLKFLAG_NO_RATE_CACHE; + + ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_gcc_mdss, + ARRAY_SIZE(msm_clocks_gcc_mdss)); + if (ret) + goto fail; + + dev_info(&pdev->dev, "Registered GCC MDSS clocks.\n"); + + return ret; +fail: + devm_clk_put(&pdev->dev, ext_byte1_clk_src.c.parent); +byte1_fail: + devm_clk_put(&pdev->dev, ext_byte0_clk_src.c.parent); +byte0_fail: + devm_clk_put(&pdev->dev, ext_pclk1_clk_src.c.parent); +pclk1_fail: + devm_clk_put(&pdev->dev, ext_pclk0_clk_src.c.parent); + return ret; +} + +static const struct of_device_id msm_clock_mdss_match_table[] = { + { .compatible = "qcom,gcc-mdss-8953" }, + {} +}; + +static struct platform_driver msm_clock_gcc_mdss_driver = { + .probe = msm_gcc_mdss_probe, + .driver = { + .name = "gcc-mdss-8953", + .of_match_table = msm_clock_mdss_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_gcc_mdss_init(void) +{ + return platform_driver_register(&msm_clock_gcc_mdss_driver); +} +fs_initcall_sync(msm_gcc_mdss_init); + +/* GFX Clocks */ +static struct clk_lookup msm_clocks_gcc_gfx[] = { + CLK_LIST(gfx3d_clk_src), + CLK_LIST(gcc_oxili_ahb_clk), + CLK_LIST(gcc_oxili_aon_clk), + CLK_LIST(gcc_oxili_gfx3d_clk), + CLK_LIST(gcc_oxili_timer_clk), + CLK_LIST(gcc_bimc_gfx_clk), + CLK_LIST(gcc_bimc_gpu_clk), +}; + +static int of_get_fmax_vdd_class(struct platform_device *pdev, struct clk *c, + char *prop_name) +{ + struct device_node *of = pdev->dev.of_node; + int prop_len, i; + struct clk_vdd_class *vdd = c->vdd_class; + u32 *array; + + if (!of_find_property(of, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % 2) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + prop_len /= 2; + vdd->level_votes = devm_kzalloc(&pdev->dev, + prop_len * sizeof(*vdd->level_votes), + GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; + + vdd->vdd_uv = devm_kzalloc(&pdev->dev, prop_len * sizeof(int), + GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; + + c->fmax = devm_kzalloc(&pdev->dev, prop_len * sizeof(unsigned long), + GFP_KERNEL); + if (!c->fmax) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, + prop_len * sizeof(u32) * 2, GFP_KERNEL); + if (!array) + return -ENOMEM; + + of_property_read_u32_array(of, prop_name, array, prop_len * 2); + for (i = 0; i < prop_len; i++) { + c->fmax[i] = array[2 * i]; + vdd->vdd_uv[i] = array[2 * i + 1]; + } + + devm_kfree(&pdev->dev, array); + vdd->num_levels = prop_len; + vdd->cur_level = prop_len; + c->num_fmax = prop_len; + + return 0; +} + +static int msm_gcc_gfx_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + u32 regval; + struct clk *xo_clk; + bool compat_bin = false; + + /* Require the GCC-RPM-XO clock to be registered first */ + xo_clk = devm_clk_get(&pdev->dev, "xo"); + if (IS_ERR(xo_clk)) { + if (PTR_ERR(xo_clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get xo clock\n"); + return PTR_ERR(xo_clk); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base"); + if (!res) { + dev_err(&pdev->dev, "Register base not defined\n"); + return -ENOMEM; + } + + virt_bases[GFX_BASE] = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!virt_bases[GFX_BASE]) { + dev_err(&pdev->dev, "Failed to ioremap CC registers\n"); + return -ENOMEM; + } + + vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx"); + if (IS_ERR(vdd_gfx.regulator[0])) { + if (PTR_ERR(vdd_gfx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get vdd_gfx regulator!"); + return PTR_ERR(vdd_gfx.regulator[0]); + } + + compat_bin = of_device_is_compatible(pdev->dev.of_node, + "qcom,gcc-gfx-sdm450"); + if (compat_bin) + gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm450; + + ret = of_get_fmax_vdd_class(pdev, &gcc_oxili_gfx3d_clk.c, + "qcom,gfxfreq-corner"); + if (ret) { + dev_err(&pdev->dev, "Unable to get gfx freq-corner mapping info\n"); + return ret; + } + + ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_gcc_gfx, + ARRAY_SIZE(msm_clocks_gcc_gfx)); + + /* Oxili Ocmem in GX rail: OXILI_GMEM_CLAMP_IO */ + regval = readl_relaxed(GCC_REG_BASE(GX_DOMAIN_MISC)); + regval &= ~BIT(0); + writel_relaxed(regval, GCC_REG_BASE(GX_DOMAIN_MISC)); + + dev_info(&pdev->dev, "Registered GCC GFX clocks.\n"); + + return ret; +} + +static const struct of_device_id msm_clock_gfx_match_table[] = { + { .compatible = "qcom,gcc-gfx-8953" }, + { .compatible = "qcom,gcc-gfx-sdm450" }, + {} +}; + +static struct platform_driver msm_clock_gcc_gfx_driver = { + .probe = msm_gcc_gfx_probe, + .driver = { + .name = "gcc-gfx-8953", + .of_match_table = msm_clock_gfx_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_gcc_gfx_init(void) +{ + return platform_driver_register(&msm_clock_gcc_gfx_driver); +} +arch_initcall_sync(msm_gcc_gfx_init); diff --git a/drivers/clk/msm/clock-generic.c b/drivers/clk/msm/clock-generic.c new file mode 100644 index 0000000000000000000000000000000000000000..b4e6bdd2172c44d0a8d5d04ca164cb15793d3ef2 --- /dev/null +++ b/drivers/clk/msm/clock-generic.c @@ -0,0 +1,921 @@ +/* + * Copyright (c) 2013-2017, 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 +#include +#include +#include +#include +#include +#include +#include + +/* ==================== Mux clock ==================== */ + +static int mux_parent_to_src_sel(struct mux_clk *mux, struct clk *p) +{ + return parent_to_src_sel(mux->parents, mux->num_parents, p); +} + +static int mux_set_parent(struct clk *c, struct clk *p) +{ + struct mux_clk *mux = to_mux_clk(c); + int sel = mux_parent_to_src_sel(mux, p); + struct clk *old_parent; + int rc = 0, i; + unsigned long flags; + + if (sel < 0 && mux->rec_parents) { + for (i = 0; i < mux->num_rec_parents; i++) { + rc = clk_set_parent(mux->rec_parents[i], p); + if (!rc) { + /* + * This is necessary to ensure prepare/enable + * counts get propagated correctly. + */ + p = mux->rec_parents[i]; + sel = mux_parent_to_src_sel(mux, p); + break; + } + } + } + + if (sel < 0) + return sel; + + rc = __clk_pre_reparent(c, p, &flags); + if (rc) + goto out; + + rc = mux->ops->set_mux_sel(mux, sel); + if (rc) + goto set_fail; + + old_parent = c->parent; + c->parent = p; + c->rate = clk_get_rate(p); + __clk_post_reparent(c, old_parent, &flags); + + return 0; + +set_fail: + __clk_post_reparent(c, p, &flags); +out: + return rc; +} + +static long mux_round_rate(struct clk *c, unsigned long rate) +{ + struct mux_clk *mux = to_mux_clk(c); + int i; + unsigned long prate, rrate = 0; + + for (i = 0; i < mux->num_parents; i++) { + prate = clk_round_rate(mux->parents[i].src, rate); + if (is_better_rate(rate, rrate, prate)) + rrate = prate; + } + if (!rrate) + return -EINVAL; + + return rrate; +} + +static int mux_set_rate(struct clk *c, unsigned long rate) +{ + struct mux_clk *mux = to_mux_clk(c); + struct clk *new_parent = NULL; + int rc = 0, i; + unsigned long new_par_curr_rate; + unsigned long flags; + + /* + * Check if one of the possible parents is already at the requested + * rate. + */ + for (i = 0; i < mux->num_parents && mux->try_get_rate; i++) { + struct clk *p = mux->parents[i].src; + + if (p->rate == rate && clk_round_rate(p, rate) == rate) { + new_parent = mux->parents[i].src; + break; + } + } + + for (i = 0; i < mux->num_parents && !(!i && new_parent); i++) { + if (clk_round_rate(mux->parents[i].src, rate) == rate) { + new_parent = mux->parents[i].src; + if (!mux->try_new_parent) + break; + if (mux->try_new_parent && new_parent != c->parent) + break; + } + } + + if (new_parent == NULL) + return -EINVAL; + + /* + * Switch to safe parent since the old and new parent might be the + * same and the parent might temporarily turn off while switching + * rates. If the mux can switch between distinct sources safely + * (indicated by try_new_parent), and the new source is not the current + * parent, do not switch to the safe parent. + */ + if (mux->safe_sel >= 0 && + !(mux->try_new_parent && (new_parent != c->parent))) { + /* + * The safe parent might be a clock with multiple sources; + * to select the "safe" source, set a safe frequency. + */ + if (mux->safe_freq) { + rc = clk_set_rate(mux->safe_parent, mux->safe_freq); + if (rc) { + pr_err("Failed to set safe rate on %s\n", + clk_name(mux->safe_parent)); + return rc; + } + } + + /* + * Some mux implementations might switch to/from a low power + * parent as part of their disable/enable ops. Grab the + * enable lock to avoid racing with these implementations. + */ + spin_lock_irqsave(&c->lock, flags); + rc = mux->ops->set_mux_sel(mux, mux->safe_sel); + spin_unlock_irqrestore(&c->lock, flags); + if (rc) + return rc; + + } + + new_par_curr_rate = clk_get_rate(new_parent); + rc = clk_set_rate(new_parent, rate); + if (rc) + goto set_rate_fail; + + rc = mux_set_parent(c, new_parent); + if (rc) + goto set_par_fail; + + return 0; + +set_par_fail: + clk_set_rate(new_parent, new_par_curr_rate); +set_rate_fail: + WARN(mux->ops->set_mux_sel(mux, + mux_parent_to_src_sel(mux, c->parent)), + "Set rate failed for %s. Also in bad state!\n", c->dbg_name); + return rc; +} + +static int mux_enable(struct clk *c) +{ + struct mux_clk *mux = to_mux_clk(c); + + if (mux->ops->enable) + return mux->ops->enable(mux); + return 0; +} + +static void mux_disable(struct clk *c) +{ + struct mux_clk *mux = to_mux_clk(c); + + if (mux->ops->disable) + return mux->ops->disable(mux); +} + +static struct clk *mux_get_parent(struct clk *c) +{ + struct mux_clk *mux = to_mux_clk(c); + int sel = mux->ops->get_mux_sel(mux); + int i; + + for (i = 0; i < mux->num_parents; i++) { + if (mux->parents[i].sel == sel) + return mux->parents[i].src; + } + + /* Unfamiliar parent. */ + return NULL; +} + +static enum handoff mux_handoff(struct clk *c) +{ + struct mux_clk *mux = to_mux_clk(c); + + c->rate = clk_get_rate(c->parent); + mux->safe_sel = mux_parent_to_src_sel(mux, mux->safe_parent); + + if (mux->en_mask && mux->ops && mux->ops->is_enabled) + return mux->ops->is_enabled(mux) + ? HANDOFF_ENABLED_CLK + : HANDOFF_DISABLED_CLK; + + /* + * If this function returns 'enabled' even when the clock downstream + * of this clock is disabled, then handoff code will unnecessarily + * enable the current parent of this clock. If this function always + * returns 'disabled' and a clock downstream is on, the clock handoff + * code will bump up the ref count for this clock and its current + * parent as necessary. So, clocks without an actual HW gate can + * always return disabled. + */ + return HANDOFF_DISABLED_CLK; +} + +static void __iomem *mux_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct mux_clk *mux = to_mux_clk(c); + + if (mux->ops && mux->ops->list_registers) + return mux->ops->list_registers(mux, n, regs, size); + + return ERR_PTR(-EINVAL); +} + +const struct clk_ops clk_ops_gen_mux = { + .enable = mux_enable, + .disable = mux_disable, + .set_parent = mux_set_parent, + .round_rate = mux_round_rate, + .set_rate = mux_set_rate, + .handoff = mux_handoff, + .get_parent = mux_get_parent, + .list_registers = mux_clk_list_registers, +}; + +/* ==================== Divider clock ==================== */ + +static long __div_round_rate(struct div_data *data, unsigned long rate, + struct clk *parent, unsigned int *best_div, unsigned long *best_prate) +{ + unsigned int div, min_div, max_div, _best_div = 1; + unsigned long prate, _best_prate = 0, rrate = 0, req_prate, actual_rate; + unsigned int numer; + + rate = max(rate, 1UL); + + min_div = max(data->min_div, 1U); + max_div = min(data->max_div, (unsigned int) (ULONG_MAX)); + + /* + * div values are doubled for half dividers. + * Adjust for that by picking a numer of 2. + */ + numer = data->is_half_divider ? 2 : 1; + + for (div = min_div; div <= max_div; div++) { + if (data->skip_odd_div && (div & 1)) + if (!(data->allow_div_one && (div == 1))) + continue; + if (data->skip_even_div && !(div & 1)) + continue; + req_prate = mult_frac(rate, div, numer); + prate = clk_round_rate(parent, req_prate); + if (IS_ERR_VALUE(prate)) + break; + + actual_rate = mult_frac(prate, numer, div); + if (is_better_rate(rate, rrate, actual_rate)) { + rrate = actual_rate; + _best_div = div; + _best_prate = prate; + } + + /* + * Trying higher dividers is only going to ask the parent for + * a higher rate. If it can't even output a rate higher than + * the one we request for this divider, the parent is not + * going to be able to output an even higher rate required + * for a higher divider. So, stop trying higher dividers. + */ + if (actual_rate < rate) + break; + + if (rrate <= rate + data->rate_margin) + break; + } + + if (!rrate) + return -EINVAL; + if (best_div) + *best_div = _best_div; + if (best_prate) + *best_prate = _best_prate; + + return rrate; +} + +static long div_round_rate(struct clk *c, unsigned long rate) +{ + struct div_clk *d = to_div_clk(c); + + return __div_round_rate(&d->data, rate, c->parent, NULL, NULL); +} + +static int _find_safe_div(struct clk *c, unsigned long rate) +{ + struct div_clk *d = to_div_clk(c); + struct div_data *data = &d->data; + unsigned long fast = max(rate, c->rate); + unsigned int numer = data->is_half_divider ? 2 : 1; + int i, safe_div = 0; + + if (!d->safe_freq) + return 0; + + /* Find the max safe freq that is lesser than fast */ + for (i = data->max_div; i >= data->min_div; i--) + if (mult_frac(d->safe_freq, numer, i) <= fast) + safe_div = i; + + return safe_div ?: -EINVAL; +} + +static int div_set_rate(struct clk *c, unsigned long rate) +{ + struct div_clk *d = to_div_clk(c); + int safe_div, div, rc = 0; + long rrate, old_prate, new_prate; + struct div_data *data = &d->data; + + rrate = __div_round_rate(data, rate, c->parent, &div, &new_prate); + if (rrate < rate || rrate > rate + data->rate_margin) + return -EINVAL; + + /* + * For fixed divider clock we don't want to return an error if the + * requested rate matches the achievable rate. So, don't check for + * !d->ops and return an error. __div_round_rate() ensures div == + * d->div if !d->ops. + */ + + safe_div = _find_safe_div(c, rate); + if (d->safe_freq && safe_div < 0) { + pr_err("No safe div on %s for transitioning from %lu to %lu\n", + c->dbg_name, c->rate, rate); + return -EINVAL; + } + + safe_div = max(safe_div, div); + + if (safe_div > data->div) { + rc = d->ops->set_div(d, safe_div); + if (rc) { + pr_err("Failed to set div %d on %s\n", safe_div, + c->dbg_name); + return rc; + } + } + + old_prate = clk_get_rate(c->parent); + rc = clk_set_rate(c->parent, new_prate); + if (rc) + goto set_rate_fail; + + if (div < data->div) + rc = d->ops->set_div(d, div); + else if (div < safe_div) + rc = d->ops->set_div(d, div); + if (rc) + goto div_dec_fail; + + data->div = div; + + return 0; + +div_dec_fail: + WARN(clk_set_rate(c->parent, old_prate), + "Set rate failed for %s. Also in bad state!\n", c->dbg_name); +set_rate_fail: + if (safe_div > data->div) + WARN(d->ops->set_div(d, data->div), + "Set rate failed for %s. Also in bad state!\n", + c->dbg_name); + return rc; +} + +static int div_enable(struct clk *c) +{ + struct div_clk *d = to_div_clk(c); + + if (d->ops && d->ops->enable) + return d->ops->enable(d); + return 0; +} + +static void div_disable(struct clk *c) +{ + struct div_clk *d = to_div_clk(c); + + if (d->ops && d->ops->disable) + return d->ops->disable(d); +} + +static enum handoff div_handoff(struct clk *c) +{ + struct div_clk *d = to_div_clk(c); + unsigned int div = d->data.div; + + if (d->ops && d->ops->get_div) + div = max(d->ops->get_div(d), 1); + div = max(div, 1U); + c->rate = clk_get_rate(c->parent) / div; + + if (!d->ops || !d->ops->set_div) + d->data.min_div = d->data.max_div = div; + d->data.div = div; + + if (d->en_mask && d->ops && d->ops->is_enabled) + return d->ops->is_enabled(d) + ? HANDOFF_ENABLED_CLK + : HANDOFF_DISABLED_CLK; + + /* + * If this function returns 'enabled' even when the clock downstream + * of this clock is disabled, then handoff code will unnecessarily + * enable the current parent of this clock. If this function always + * returns 'disabled' and a clock downstream is on, the clock handoff + * code will bump up the ref count for this clock and its current + * parent as necessary. So, clocks without an actual HW gate can + * always return disabled. + */ + return HANDOFF_DISABLED_CLK; +} + +static void __iomem *div_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct div_clk *d = to_div_clk(c); + + if (d->ops && d->ops->list_registers) + return d->ops->list_registers(d, n, regs, size); + + return ERR_PTR(-EINVAL); +} + +const struct clk_ops clk_ops_div = { + .enable = div_enable, + .disable = div_disable, + .round_rate = div_round_rate, + .set_rate = div_set_rate, + .handoff = div_handoff, + .list_registers = div_clk_list_registers, +}; + +static long __slave_div_round_rate(struct clk *c, unsigned long rate, + int *best_div) +{ + struct div_clk *d = to_div_clk(c); + unsigned int div, min_div, max_div; + long p_rate; + + rate = max(rate, 1UL); + + min_div = d->data.min_div; + max_div = d->data.max_div; + + p_rate = clk_get_rate(c->parent); + div = DIV_ROUND_CLOSEST(p_rate, rate); + div = max(div, min_div); + div = min(div, max_div); + if (best_div) + *best_div = div; + + return p_rate / div; +} + +static long slave_div_round_rate(struct clk *c, unsigned long rate) +{ + return __slave_div_round_rate(c, rate, NULL); +} + +static int slave_div_set_rate(struct clk *c, unsigned long rate) +{ + struct div_clk *d = to_div_clk(c); + int div, rc = 0; + long rrate; + + rrate = __slave_div_round_rate(c, rate, &div); + if (rrate != rate) + return -EINVAL; + + if (div == d->data.div) + return 0; + + /* + * For fixed divider clock we don't want to return an error if the + * requested rate matches the achievable rate. So, don't check for + * !d->ops and return an error. __slave_div_round_rate() ensures + * div == d->data.div if !d->ops. + */ + rc = d->ops->set_div(d, div); + if (rc) + return rc; + + d->data.div = div; + + return 0; +} + +static unsigned long slave_div_get_rate(struct clk *c) +{ + struct div_clk *d = to_div_clk(c); + + if (!d->data.div) + return 0; + return clk_get_rate(c->parent) / d->data.div; +} + +const struct clk_ops clk_ops_slave_div = { + .enable = div_enable, + .disable = div_disable, + .round_rate = slave_div_round_rate, + .set_rate = slave_div_set_rate, + .get_rate = slave_div_get_rate, + .handoff = div_handoff, + .list_registers = div_clk_list_registers, +}; + + +/** + * External clock + * Some clock controllers have input clock signal that come from outside the + * clock controller. That input clock signal might then be used as a source for + * several clocks inside the clock controller. This external clock + * implementation models this input clock signal by just passing on the requests + * to the clock's parent, the original external clock source. The driver for the + * clock controller should clk_get() the original external clock in the probe + * function and set is as a parent to this external clock.. + */ + +long parent_round_rate(struct clk *c, unsigned long rate) +{ + return clk_round_rate(c->parent, rate); +} + +int parent_set_rate(struct clk *c, unsigned long rate) +{ + return clk_set_rate(c->parent, rate); +} + +unsigned long parent_get_rate(struct clk *c) +{ + return clk_get_rate(c->parent); +} + +static int ext_set_parent(struct clk *c, struct clk *p) +{ + return clk_set_parent(c->parent, p); +} + +static struct clk *ext_get_parent(struct clk *c) +{ + struct ext_clk *ext = to_ext_clk(c); + + if (!IS_ERR_OR_NULL(c->parent)) + return c->parent; + return clk_get(ext->dev, ext->clk_id); +} + +static enum handoff ext_handoff(struct clk *c) +{ + c->rate = clk_get_rate(c->parent); + /* Similar reasoning applied in div_handoff, see comment there. */ + return HANDOFF_DISABLED_CLK; +} + +const struct clk_ops clk_ops_ext = { + .handoff = ext_handoff, + .round_rate = parent_round_rate, + .set_rate = parent_set_rate, + .get_rate = parent_get_rate, + .set_parent = ext_set_parent, + .get_parent = ext_get_parent, +}; + +static void *ext_clk_dt_parser(struct device *dev, struct device_node *np) +{ + struct ext_clk *ext; + const char *str; + int rc; + + ext = devm_kzalloc(dev, sizeof(*ext), GFP_KERNEL); + if (!ext) + return ERR_PTR(-ENOMEM); + + ext->dev = dev; + rc = of_property_read_string(np, "qcom,clock-names", &str); + if (!rc) + ext->clk_id = (void *)str; + + ext->c.ops = &clk_ops_ext; + return msmclk_generic_clk_init(dev, np, &ext->c); +} +MSMCLK_PARSER(ext_clk_dt_parser, "qcom,ext-clk", 0); + +/* ==================== Mux_div clock ==================== */ + +static int mux_div_clk_enable(struct clk *c) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + + if (md->ops->enable) + return md->ops->enable(md); + return 0; +} + +static void mux_div_clk_disable(struct clk *c) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + + if (md->ops->disable) + return md->ops->disable(md); +} + +static long __mux_div_round_rate(struct clk *c, unsigned long rate, + struct clk **best_parent, int *best_div, unsigned long *best_prate) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + unsigned int i; + unsigned long rrate, best = 0, _best_div = 0, _best_prate = 0; + struct clk *_best_parent = 0; + + if (md->try_get_rate) { + for (i = 0; i < md->num_parents; i++) { + int divider; + unsigned long p_rate; + + rrate = __div_round_rate(&md->data, rate, + md->parents[i].src, + ÷r, &p_rate); + /* + * Check if one of the possible parents is already at + * the requested rate. + */ + if (p_rate == clk_get_rate(md->parents[i].src) + && rrate == rate) { + best = rrate; + _best_div = divider; + _best_prate = p_rate; + _best_parent = md->parents[i].src; + goto end; + } + } + } + + for (i = 0; i < md->num_parents; i++) { + int div; + unsigned long prate; + + rrate = __div_round_rate(&md->data, rate, md->parents[i].src, + &div, &prate); + + if (is_better_rate(rate, best, rrate)) { + best = rrate; + _best_div = div; + _best_prate = prate; + _best_parent = md->parents[i].src; + } + + if (rate <= rrate && rrate <= rate + md->data.rate_margin) + break; + } +end: + if (best_div) + *best_div = _best_div; + if (best_prate) + *best_prate = _best_prate; + if (best_parent) + *best_parent = _best_parent; + + if (best) + return best; + return -EINVAL; +} + +static long mux_div_clk_round_rate(struct clk *c, unsigned long rate) +{ + return __mux_div_round_rate(c, rate, NULL, NULL, NULL); +} + +/* requires enable lock to be held */ +static int __set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div) +{ + u32 rc = 0, src_sel; + + src_sel = parent_to_src_sel(md->parents, md->num_parents, parent); + /* + * If the clock is disabled, don't change to the new settings until + * the clock is reenabled + */ + if (md->c.count) + rc = md->ops->set_src_div(md, src_sel, div); + if (!rc) { + md->data.div = div; + md->src_sel = src_sel; + } + + return rc; +} + +static int set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div) +{ + unsigned long flags; + u32 rc; + + spin_lock_irqsave(&md->c.lock, flags); + rc = __set_src_div(md, parent, div); + spin_unlock_irqrestore(&md->c.lock, flags); + + return rc; +} + +/* Must be called after handoff to ensure parent clock rates are initialized */ +static int safe_parent_init_once(struct clk *c) +{ + unsigned long rrate; + u32 best_div; + struct clk *best_parent; + struct mux_div_clk *md = to_mux_div_clk(c); + + if (IS_ERR(md->safe_parent)) + return -EINVAL; + if (!md->safe_freq || md->safe_parent) + return 0; + + rrate = __mux_div_round_rate(c, md->safe_freq, &best_parent, + &best_div, NULL); + + if (rrate == md->safe_freq) { + md->safe_div = best_div; + md->safe_parent = best_parent; + } else { + md->safe_parent = ERR_PTR(-EINVAL); + return -EINVAL; + } + return 0; +} + +static int mux_div_clk_set_rate(struct clk *c, unsigned long rate) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + unsigned long flags, rrate; + unsigned long new_prate, new_parent_orig_rate; + struct clk *old_parent, *new_parent; + u32 new_div, old_div; + int rc; + + rc = safe_parent_init_once(c); + if (rc) + return rc; + + rrate = __mux_div_round_rate(c, rate, &new_parent, &new_div, + &new_prate); + if (rrate < rate || rrate > rate + md->data.rate_margin) + return -EINVAL; + + old_parent = c->parent; + old_div = md->data.div; + + /* Refer to the description of safe_freq in clock-generic.h */ + if (md->safe_freq) + rc = set_src_div(md, md->safe_parent, md->safe_div); + + else if (new_parent == old_parent && new_div >= old_div) { + /* + * If both the parent_rate and divider changes, there may be an + * intermediate frequency generated. Ensure this intermediate + * frequency is less than both the new rate and previous rate. + */ + rc = set_src_div(md, old_parent, new_div); + } + if (rc) + return rc; + + new_parent_orig_rate = clk_get_rate(new_parent); + rc = clk_set_rate(new_parent, new_prate); + if (rc) { + pr_err("failed to set %s to %ld\n", + clk_name(new_parent), new_prate); + goto err_set_rate; + } + + rc = __clk_pre_reparent(c, new_parent, &flags); + if (rc) + goto err_pre_reparent; + + /* Set divider and mux src atomically */ + rc = __set_src_div(md, new_parent, new_div); + if (rc) + goto err_set_src_div; + + c->parent = new_parent; + + __clk_post_reparent(c, old_parent, &flags); + return 0; + +err_set_src_div: + /* Not switching to new_parent, so disable it */ + __clk_post_reparent(c, new_parent, &flags); +err_pre_reparent: + rc = clk_set_rate(new_parent, new_parent_orig_rate); + WARN(rc, "%s: error changing new_parent (%s) rate back to %ld\n", + clk_name(c), clk_name(new_parent), new_parent_orig_rate); +err_set_rate: + rc = set_src_div(md, old_parent, old_div); + WARN(rc, "%s: error changing back to original div (%d) and parent (%s)\n", + clk_name(c), old_div, clk_name(old_parent)); + + return rc; +} + +static struct clk *mux_div_clk_get_parent(struct clk *c) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + u32 i, div, src_sel; + + md->ops->get_src_div(md, &src_sel, &div); + + md->data.div = div; + md->src_sel = src_sel; + + for (i = 0; i < md->num_parents; i++) { + if (md->parents[i].sel == src_sel) + return md->parents[i].src; + } + + return NULL; +} + +static enum handoff mux_div_clk_handoff(struct clk *c) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + unsigned long parent_rate; + unsigned int numer; + + parent_rate = clk_get_rate(c->parent); + /* + * div values are doubled for half dividers. + * Adjust for that by picking a numer of 2. + */ + numer = md->data.is_half_divider ? 2 : 1; + + if (md->data.div) { + c->rate = mult_frac(parent_rate, numer, md->data.div); + } else { + c->rate = 0; + return HANDOFF_DISABLED_CLK; + } + + if (md->en_mask && md->ops && md->ops->is_enabled) + return md->ops->is_enabled(md) + ? HANDOFF_ENABLED_CLK + : HANDOFF_DISABLED_CLK; + + /* + * If this function returns 'enabled' even when the clock downstream + * of this clock is disabled, then handoff code will unnecessarily + * enable the current parent of this clock. If this function always + * returns 'disabled' and a clock downstream is on, the clock handoff + * code will bump up the ref count for this clock and its current + * parent as necessary. So, clocks without an actual HW gate can + * always return disabled. + */ + return HANDOFF_DISABLED_CLK; +} + +static void __iomem *mux_div_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct mux_div_clk *md = to_mux_div_clk(c); + + if (md->ops && md->ops->list_registers) + return md->ops->list_registers(md, n, regs, size); + + return ERR_PTR(-EINVAL); +} + +const struct clk_ops clk_ops_mux_div_clk = { + .enable = mux_div_clk_enable, + .disable = mux_div_clk_disable, + .set_rate = mux_div_clk_set_rate, + .round_rate = mux_div_clk_round_rate, + .get_parent = mux_div_clk_get_parent, + .handoff = mux_div_clk_handoff, + .list_registers = mux_div_clk_list_registers, +}; diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c new file mode 100644 index 0000000000000000000000000000000000000000..f200d0bc99ea1148a401849eb3bd9cb8a6601935 --- /dev/null +++ b/drivers/clk/msm/clock-local2.c @@ -0,0 +1,2907 @@ +/* Copyright (c) 2012-2017, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * When enabling/disabling a clock, check the halt bit up to this number + * number of times (with a 1 us delay in between) before continuing. + */ +#define HALT_CHECK_MAX_LOOPS 500 +/* For clock without halt checking, wait this long after enables/disables. */ +#define HALT_CHECK_DELAY_US 500 + +#define RCG_FORCE_DISABLE_DELAY_US 100 + +/* + * When updating an RCG configuration, check the update bit up to this number + * number of times (with a 1 us delay in between) before continuing. + */ +#define UPDATE_CHECK_MAX_LOOPS 500 + +DEFINE_SPINLOCK(local_clock_reg_lock); +struct clk_freq_tbl rcg_dummy_freq = F_END; + +#define CMD_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg) +#define CFG_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x4) +#define M_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x8) +#define N_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0xC) +#define D_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x10) +#define CBCR_REG(x) (*(x)->base + (x)->cbcr_reg) +#define BCR_REG(x) (*(x)->base + (x)->bcr_reg) +#define RST_REG(x) (*(x)->base + (x)->reset_reg) +#define VOTE_REG(x) (*(x)->base + (x)->vote_reg) +#define GATE_EN_REG(x) (*(x)->base + (x)->en_reg) +#define DIV_REG(x) (*(x)->base + (x)->offset) +#define MUX_REG(x) (*(x)->base + (x)->offset) + +/* + * Important clock bit positions and masks + */ +#define CMD_RCGR_ROOT_ENABLE_BIT BIT(1) +#define CBCR_BRANCH_ENABLE_BIT BIT(0) +#define CBCR_BRANCH_OFF_BIT BIT(31) +#define CMD_RCGR_CONFIG_UPDATE_BIT BIT(0) +#define CMD_RCGR_ROOT_STATUS_BIT BIT(31) +#define BCR_BLK_ARES_BIT BIT(0) +#define CBCR_HW_CTL_BIT BIT(1) +#define CFG_RCGR_DIV_MASK BM(4, 0) +#define CFG_RCGR_SRC_SEL_MASK BM(10, 8) +#define MND_MODE_MASK BM(13, 12) +#define MND_DUAL_EDGE_MODE_BVAL BVAL(13, 12, 0x2) +#define CMD_RCGR_CONFIG_DIRTY_MASK BM(7, 4) +#define CBCR_CDIV_LSB 16 +#define CBCR_CDIV_MSB 19 + +enum branch_state { + BRANCH_ON, + BRANCH_OFF, +}; + +static struct clk_freq_tbl cxo_f = { + .freq_hz = 19200000, + .m_val = 0, + .n_val = 0, + .d_val = 0, + .div_src_val = 0, +}; + +struct div_map { + u32 mask; + int div; +}; + +/* + * RCG functions + */ + +/* + * Update an RCG with a new configuration. This may include a new M, N, or D + * value, source selection or pre-divider value. + * + */ +static void rcg_update_config(struct rcg_clk *rcg) +{ + u32 cmd_rcgr_regval; + int count = UPDATE_CHECK_MAX_LOOPS; + + if (rcg->non_local_control_timeout) + count = rcg->non_local_control_timeout; + + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + cmd_rcgr_regval |= CMD_RCGR_CONFIG_UPDATE_BIT; + writel_relaxed(cmd_rcgr_regval, CMD_RCGR_REG(rcg)); + + /* Wait for update to take effect */ + for (; count > 0; count--) { + if (!(readl_relaxed(CMD_RCGR_REG(rcg)) & + CMD_RCGR_CONFIG_UPDATE_BIT)) + return; + udelay(1); + } + + CLK_WARN(&rcg->c, count == 0, "rcg didn't update its configuration."); +} + +static void rcg_on_check(struct rcg_clk *rcg) +{ + int count = UPDATE_CHECK_MAX_LOOPS; + + if (rcg->non_local_control_timeout) + count = rcg->non_local_control_timeout; + + /* Wait for RCG to turn on */ + for (; count > 0; count--) { + if (!(readl_relaxed(CMD_RCGR_REG(rcg)) & + CMD_RCGR_ROOT_STATUS_BIT)) + return; + udelay(1); + } + CLK_WARN(&rcg->c, count == 0, "rcg didn't turn on."); +} + +/* RCG set rate function for clocks with Half Integer Dividers. */ +static void __set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf) +{ + u32 cfg_regval; + + cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg)); + cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK); + cfg_regval |= nf->div_src_val; + writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg)); + + rcg_update_config(rcg); +} + +void set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf) +{ + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + __set_rate_hid(rcg, nf); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +/* RCG set rate function for clocks with MND & Half Integer Dividers. */ +static void __set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf) +{ + u32 cfg_regval; + + cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg)); + writel_relaxed(nf->m_val, M_REG(rcg)); + writel_relaxed(nf->n_val, N_REG(rcg)); + writel_relaxed(nf->d_val, D_REG(rcg)); + + cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg)); + cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK); + cfg_regval |= nf->div_src_val; + + /* Activate or disable the M/N:D divider as necessary */ + cfg_regval &= ~MND_MODE_MASK; + if (nf->n_val != 0) + cfg_regval |= MND_DUAL_EDGE_MODE_BVAL; + writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg)); + + rcg_update_config(rcg); +} + +void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf) +{ + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + __set_rate_mnd(rcg, nf); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +static void rcg_set_force_enable(struct rcg_clk *rcg) +{ + u32 cmd_rcgr_regval; + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + cmd_rcgr_regval |= CMD_RCGR_ROOT_ENABLE_BIT; + writel_relaxed(cmd_rcgr_regval, CMD_RCGR_REG(rcg)); + rcg_on_check(rcg); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +static void rcg_clear_force_enable(struct rcg_clk *rcg) +{ + u32 cmd_rcgr_regval; + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + cmd_rcgr_regval &= ~CMD_RCGR_ROOT_ENABLE_BIT; + writel_relaxed(cmd_rcgr_regval, CMD_RCGR_REG(rcg)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + /* Add a delay of 100usecs to let the RCG disable */ + udelay(RCG_FORCE_DISABLE_DELAY_US); +} + +static int rcg_clk_enable(struct clk *c) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + + WARN(rcg->current_freq == &rcg_dummy_freq, + "Attempting to prepare %s before setting its rate." + , rcg->c.dbg_name); + + if (rcg->force_enable_rcgr) { + rcg_set_force_enable(rcg); + return 0; + } + + if (!rcg->non_local_children || rcg->current_freq == &rcg_dummy_freq) + return 0; + /* + * Switch from CXO to saved mux value. Force enable/disable while + * switching. The current parent is already prepared and enabled + * at this point, and the CXO source is always-on. Therefore the + * RCG can safely execute a dynamic switch. + */ + rcg_set_force_enable(rcg); + rcg->set_rate(rcg, rcg->current_freq); + rcg_clear_force_enable(rcg); + + return 0; +} + +static void rcg_clk_disable(struct clk *c) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + + if (rcg->force_enable_rcgr) { + rcg_clear_force_enable(rcg); + return; + } + + if (!rcg->non_local_children) + return; + + /* + * Save mux select and switch to CXO. Force enable/disable while + * switching. The current parent is still prepared and enabled at this + * point, and the CXO source is always-on. Therefore the RCG can safely + * execute a dynamic switch. + */ + rcg_set_force_enable(rcg); + rcg->set_rate(rcg, &cxo_f); + rcg_clear_force_enable(rcg); +} + +static int prepare_enable_rcg_srcs(struct clk *c, struct clk *curr, + struct clk *new, unsigned long *flags) +{ + int rc; + + rc = clk_prepare(curr); + if (rc) + return rc; + + if (c->prepare_count) { + rc = clk_prepare(new); + if (rc) + goto err_new_src_prepare; + } + + rc = clk_prepare(new); + if (rc) + goto err_new_src_prepare2; + + spin_lock_irqsave(&c->lock, *flags); + rc = clk_enable(curr); + if (rc) { + spin_unlock_irqrestore(&c->lock, *flags); + goto err_curr_src_enable; + } + + if (c->count) { + rc = clk_enable(new); + if (rc) { + spin_unlock_irqrestore(&c->lock, *flags); + goto err_new_src_enable; + } + } + + rc = clk_enable(new); + if (rc) { + spin_unlock_irqrestore(&c->lock, *flags); + goto err_new_src_enable2; + } + return 0; + +err_new_src_enable2: + if (c->count) + clk_disable(new); +err_new_src_enable: + clk_disable(curr); +err_curr_src_enable: + clk_unprepare(new); +err_new_src_prepare2: + if (c->prepare_count) + clk_unprepare(new); +err_new_src_prepare: + clk_unprepare(curr); + return rc; +} + +static void disable_unprepare_rcg_srcs(struct clk *c, struct clk *curr, + struct clk *new, unsigned long *flags) +{ + clk_disable(new); + clk_disable(curr); + if (c->count) + clk_disable(curr); + spin_unlock_irqrestore(&c->lock, *flags); + + clk_unprepare(new); + clk_unprepare(curr); + if (c->prepare_count) + clk_unprepare(curr); +} + +static int rcg_clk_set_duty_cycle(struct clk *c, u32 numerator, + u32 denominator) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + u32 notn_m_val, n_val, m_val, d_val, not2d_val; + u32 max_n_value; + + if (!numerator || numerator == denominator) + return -EINVAL; + + if (!rcg->mnd_reg_width) + rcg->mnd_reg_width = 8; + + max_n_value = 1 << (rcg->mnd_reg_width - 1); + + notn_m_val = readl_relaxed(N_REG(rcg)); + m_val = readl_relaxed(M_REG(rcg)); + n_val = ((~notn_m_val) + m_val) & BM((rcg->mnd_reg_width - 1), 0); + + if (n_val > max_n_value) { + pr_warn("%s duty-cycle cannot be set for required frequency %ld\n", + c->dbg_name, clk_get_rate(c)); + return -EINVAL; + } + + /* Calculate the 2d value */ + d_val = DIV_ROUND_CLOSEST((numerator * n_val * 2), denominator); + + /* Check BIT WIDTHS OF 2d. If D is too big reduce Duty cycle. */ + if (d_val > (BIT(rcg->mnd_reg_width) - 1)) { + d_val = (BIT(rcg->mnd_reg_width) - 1) / 2; + d_val *= 2; + } + + not2d_val = (~d_val) & BM((rcg->mnd_reg_width - 1), 0); + + writel_relaxed(not2d_val, D_REG(rcg)); + rcg_update_config(rcg); + + return 0; +} + +static int rcg_clk_set_rate(struct clk *c, unsigned long rate) +{ + struct clk_freq_tbl *cf, *nf; + struct rcg_clk *rcg = to_rcg_clk(c); + int rc; + unsigned long flags; + + for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END + && nf->freq_hz != rate; nf++) + ; + + if (nf->freq_hz == FREQ_END) + return -EINVAL; + + cf = rcg->current_freq; + if (nf->src_freq != FIXED_CLK_SRC) { + rc = clk_set_rate(nf->src_clk, nf->src_freq); + if (rc) + return rc; + } + + if (rcg->non_local_control_timeout) { + /* + * __clk_pre_reparent only enables the RCG source if the SW + * count for the RCG is non-zero. We need to make sure that + * both PLL sources are ON before force turning on the RCG. + */ + rc = prepare_enable_rcg_srcs(c, cf->src_clk, nf->src_clk, + &flags); + } else + rc = __clk_pre_reparent(c, nf->src_clk, &flags); + + if (rc) + return rc; + + WARN_ON(!rcg->set_rate); + + /* Perform clock-specific frequency switch operations. */ + if ((rcg->non_local_children && c->count) || + rcg->non_local_control_timeout) { + /* + * Force enable the RCG before updating the RCG configuration + * since the downstream clock/s can be disabled at around the + * same time causing the feedback from the CBCR to turn off + * the RCG. + */ + rcg_set_force_enable(rcg); + rcg->set_rate(rcg, nf); + rcg_clear_force_enable(rcg); + } else if (!rcg->non_local_children) { + rcg->set_rate(rcg, nf); + } + + /* + * If non_local_children is set and the RCG is not enabled, + * the following operations switch parent in software and cache + * the frequency. The mux switch will occur when the RCG is enabled. + */ + rcg->current_freq = nf; + c->parent = nf->src_clk; + + if (rcg->non_local_control_timeout) + disable_unprepare_rcg_srcs(c, cf->src_clk, nf->src_clk, + &flags); + else + __clk_post_reparent(c, cf->src_clk, &flags); + + return 0; +} + +/* + * Return a supported rate that's at least the specified rate or + * the max supported rate if the specified rate is larger than the + * max supported rate. + */ +static long rcg_clk_round_rate(struct clk *c, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + struct clk_freq_tbl *f; + + for (f = rcg->freq_tbl; f->freq_hz != FREQ_END; f++) + if (f->freq_hz >= rate) + return f->freq_hz; + + f--; + return f->freq_hz; +} + +/* Return the nth supported frequency for a given clock. */ +static long rcg_clk_list_rate(struct clk *c, unsigned long n) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + + if (!rcg->freq_tbl || rcg->freq_tbl->freq_hz == FREQ_END) + return -ENXIO; + + return (rcg->freq_tbl + n)->freq_hz; +} + +static struct clk *_rcg_clk_get_parent(struct rcg_clk *rcg, bool has_mnd, + bool match_rate) +{ + u32 n_regval = 0, m_regval = 0, d_regval = 0; + u32 cfg_regval, div, div_regval; + struct clk_freq_tbl *freq; + u32 cmd_rcgr_regval; + + if (!rcg->freq_tbl) { + WARN(1, "No frequency table present for rcg %s\n", + rcg->c.dbg_name); + return NULL; + } + + /* Is there a pending configuration? */ + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK) { + WARN(1, "Pending transaction for rcg %s\n", rcg->c.dbg_name); + return NULL; + } + + /* Get values of m, n, d, div and src_sel registers. */ + if (has_mnd) { + m_regval = readl_relaxed(M_REG(rcg)); + n_regval = readl_relaxed(N_REG(rcg)); + d_regval = readl_relaxed(D_REG(rcg)); + + /* + * The n and d values stored in the frequency tables are sign + * extended to 32 bits. The n and d values in the registers are + * sign extended to 8 or 16 bits. Sign extend the values read + * from the registers so that they can be compared to the + * values in the frequency tables. + */ + n_regval |= (n_regval >> 8) ? BM(31, 16) : BM(31, 8); + d_regval |= (d_regval >> 8) ? BM(31, 16) : BM(31, 8); + } + + cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg)); + cfg_regval &= CFG_RCGR_SRC_SEL_MASK | CFG_RCGR_DIV_MASK + | MND_MODE_MASK; + + /* If mnd counter is present, check if it's in use. */ + has_mnd = (has_mnd) && + ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL); + + /* + * Clear out the mn counter mode bits since we now want to compare only + * the source mux selection and pre-divider values in the registers. + */ + cfg_regval &= ~MND_MODE_MASK; + + /* Figure out what rate the rcg is running at */ + for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) { + /* source select does not match */ + if ((freq->div_src_val & CFG_RCGR_SRC_SEL_MASK) + != (cfg_regval & CFG_RCGR_SRC_SEL_MASK)) + continue; + /* + * Stop if we found the required parent in the frequency table + * and only care if the source matches but dont care if the + * frequency matches + */ + if (!match_rate) + break; + /* divider does not match */ + div = freq->div_src_val & CFG_RCGR_DIV_MASK; + div_regval = cfg_regval & CFG_RCGR_DIV_MASK; + if (div != div_regval && (div > 1 || div_regval > 1)) + continue; + + if (has_mnd) { + if (freq->m_val != m_regval) + continue; + if (freq->n_val != n_regval) + continue; + if (freq->d_val != d_regval) + continue; + } else if (freq->n_val) { + continue; + } + break; + } + + /* No known frequency found */ + if (freq->freq_hz == FREQ_END) { + /* + * If we can't recognize the frequency and non_local_children is + * set, switch to safe frequency. It is assumed the current + * parent has been turned on by the bootchain if the RCG is on. + */ + if (rcg->non_local_children) { + rcg->set_rate(rcg, &cxo_f); + WARN(1, "don't recognize rcg frequency for %s\n", + rcg->c.dbg_name); + } + return NULL; + } + + rcg->current_freq = freq; + return freq->src_clk; +} + +static enum handoff _rcg_clk_handoff(struct rcg_clk *rcg) +{ + u32 cmd_rcgr_regval; + + if (rcg->current_freq && rcg->current_freq->freq_hz != FREQ_END) + rcg->c.rate = rcg->current_freq->freq_hz; + + /* Is the root enabled? */ + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + if ((cmd_rcgr_regval & CMD_RCGR_ROOT_STATUS_BIT)) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +static struct clk *display_clk_get_parent(struct clk *c) +{ + return _rcg_clk_get_parent(to_rcg_clk(c), false, false); +} + +static struct clk *rcg_mnd_clk_get_parent(struct clk *c) +{ + return _rcg_clk_get_parent(to_rcg_clk(c), true, true); +} + +static struct clk *rcg_clk_get_parent(struct clk *c) +{ + return _rcg_clk_get_parent(to_rcg_clk(c), false, true); +} + +static enum handoff rcg_mnd_clk_handoff(struct clk *c) +{ + return _rcg_clk_handoff(to_rcg_clk(c)); +} + +static enum handoff rcg_clk_handoff(struct clk *c) +{ + return _rcg_clk_handoff(to_rcg_clk(c)); +} + +static void __iomem *rcg_hid_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return CMD_RCGR_REG(rcg); +} + +static void __iomem *rcg_mnd_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + {"M_VAL", 0x8}, + {"N_VAL", 0xC}, + {"D_VAL", 0x10}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return CMD_RCGR_REG(rcg); +} + +#define BRANCH_CHECK_MASK BM(31, 28) +#define BRANCH_ON_VAL BVAL(31, 28, 0x0) +#define BRANCH_OFF_VAL BVAL(31, 28, 0x8) +#define BRANCH_NOC_FSM_ON_VAL BVAL(31, 28, 0x2) + +/* + * Branch clock functions + */ +static void branch_clk_halt_check(struct clk *c, u32 halt_check, + void __iomem *cbcr_reg, enum branch_state br_status) +{ + char *status_str = (br_status == BRANCH_ON) ? "off" : "on"; + + /* + * Use a memory barrier since some halt status registers are + * not within the same 1K segment as the branch/root enable + * registers. It's also needed in the udelay() case to ensure + * the delay starts after the branch disable. + */ + mb(); + + if (halt_check == DELAY || halt_check == HALT_VOTED) { + udelay(HALT_CHECK_DELAY_US); + } else if (halt_check == HALT) { + int count; + u32 val; + + for (count = HALT_CHECK_MAX_LOOPS; count > 0; count--) { + val = readl_relaxed(cbcr_reg); + val &= BRANCH_CHECK_MASK; + switch (br_status) { + case BRANCH_ON: + if (val == BRANCH_ON_VAL + || val == BRANCH_NOC_FSM_ON_VAL) + return; + break; + + case BRANCH_OFF: + if (val == BRANCH_OFF_VAL) + return; + break; + }; + udelay(1); + } + CLK_WARN(c, count == 0, "status stuck %s", status_str); + } +} + +static unsigned long branch_clk_aggregate_rate(const struct clk *parent) +{ + struct clk *clk; + unsigned long rate = 0; + + list_for_each_entry(clk, &parent->children, siblings) { + struct branch_clk *v = to_branch_clk(clk); + + if (v->is_prepared) + rate = max(clk->rate, rate); + } + return rate; +} + +static int cbcr_set_flags(void * __iomem regaddr, unsigned long flags) +{ + u32 cbcr_val; + unsigned long irq_flags; + int delay_us = 0, ret = 0; + + spin_lock_irqsave(&local_clock_reg_lock, irq_flags); + cbcr_val = readl_relaxed(regaddr); + switch (flags) { + case CLKFLAG_PERIPH_OFF_SET: + cbcr_val |= BIT(12); + delay_us = 1; + break; + case CLKFLAG_PERIPH_OFF_CLEAR: + cbcr_val &= ~BIT(12); + break; + case CLKFLAG_RETAIN_PERIPH: + cbcr_val |= BIT(13); + delay_us = 1; + break; + case CLKFLAG_NORETAIN_PERIPH: + cbcr_val &= ~BIT(13); + break; + case CLKFLAG_RETAIN_MEM: + cbcr_val |= BIT(14); + delay_us = 1; + break; + case CLKFLAG_NORETAIN_MEM: + cbcr_val &= ~BIT(14); + break; + default: + ret = -EINVAL; + } + writel_relaxed(cbcr_val, regaddr); + /* Make sure power is enabled before returning. */ + mb(); + udelay(delay_us); + + spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags); + + return ret; +} + +static int branch_clk_set_flags(struct clk *c, unsigned long flags) +{ + return cbcr_set_flags(CBCR_REG(to_branch_clk(c)), flags); +} + +static DEFINE_MUTEX(branch_clk_lock); + +static int branch_clk_prepare(struct clk *c) +{ + struct branch_clk *branch = to_branch_clk(c); + unsigned long curr_rate; + int ret = 0; + + if (!branch->aggr_sibling_rates) + return ret; + + mutex_lock(&branch_clk_lock); + branch->is_prepared = false; + curr_rate = branch_clk_aggregate_rate(c->parent); + if (c->rate > curr_rate) { + ret = clk_set_rate(c->parent, c->rate); + if (ret) + goto exit; + } + branch->is_prepared = true; +exit: + mutex_unlock(&branch_clk_lock); + return ret; +} + +static int branch_clk_enable(struct clk *c) +{ + unsigned long flags; + u32 cbcr_val; + struct branch_clk *branch = to_branch_clk(c); + + if (branch->toggle_memory) { + branch_clk_set_flags(c, CLKFLAG_RETAIN_MEM); + branch_clk_set_flags(c, CLKFLAG_RETAIN_PERIPH); + } + spin_lock_irqsave(&local_clock_reg_lock, flags); + cbcr_val = readl_relaxed(CBCR_REG(branch)); + cbcr_val |= CBCR_BRANCH_ENABLE_BIT; + writel_relaxed(cbcr_val, CBCR_REG(branch)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + /* + * For clocks controlled by other masters via voting registers, + * delay polling for the status bit to allow previous clk_disable + * by the GDS controller to go through. + */ + if (branch->no_halt_check_on_disable) + udelay(5); + + /* Wait for clock to enable before continuing. */ + branch_clk_halt_check(c, branch->halt_check, CBCR_REG(branch), + BRANCH_ON); + + return 0; +} + +static void branch_clk_unprepare(struct clk *c) +{ + struct branch_clk *branch = to_branch_clk(c); + unsigned long curr_rate, new_rate; + + if (!branch->aggr_sibling_rates) + return; + + mutex_lock(&branch_clk_lock); + branch->is_prepared = false; + new_rate = branch_clk_aggregate_rate(c->parent); + curr_rate = max(new_rate, c->rate); + if (new_rate < curr_rate) + clk_set_rate(c->parent, new_rate); + mutex_unlock(&branch_clk_lock); +} + +static void branch_clk_disable(struct clk *c) +{ + unsigned long flags; + struct branch_clk *branch = to_branch_clk(c); + u32 reg_val; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + reg_val = readl_relaxed(CBCR_REG(branch)); + reg_val &= ~CBCR_BRANCH_ENABLE_BIT; + writel_relaxed(reg_val, CBCR_REG(branch)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + /* Wait for clock to disable before continuing. */ + if (!branch->no_halt_check_on_disable) + branch_clk_halt_check(c, branch->halt_check, CBCR_REG(branch), + BRANCH_OFF); + + if (branch->toggle_memory) { + branch_clk_set_flags(c, CLKFLAG_NORETAIN_MEM); + branch_clk_set_flags(c, CLKFLAG_NORETAIN_PERIPH); + } +} + +static int branch_cdiv_set_rate(struct branch_clk *branch, unsigned long rate) +{ + unsigned long flags; + u32 regval; + + if (rate > branch->max_div) + return -EINVAL; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(CBCR_REG(branch)); + regval &= ~BM(CBCR_CDIV_MSB, CBCR_CDIV_LSB); + regval |= BVAL(CBCR_CDIV_MSB, CBCR_CDIV_LSB, rate); + writel_relaxed(regval, CBCR_REG(branch)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + return 0; +} + +static int branch_clk_set_rate(struct clk *c, unsigned long rate) +{ + struct branch_clk *clkh, *branch = to_branch_clk(c); + struct clk *clkp, *parent = c->parent; + unsigned long curr_rate, new_rate, other_rate = 0; + int ret = 0; + + if (branch->max_div) + return branch_cdiv_set_rate(branch, rate); + + if (branch->has_sibling) + return -EPERM; + + if (!branch->aggr_sibling_rates) + return clk_set_rate(c->parent, rate); + + mutex_lock(&branch_clk_lock); + if (!branch->is_prepared) { + c->rate = rate; + goto exit; + } + /* + * Get the aggregate rate without this clock's vote and update + * if the new rate is different than the current rate. + */ + list_for_each_entry(clkp, &parent->children, siblings) { + clkh = to_branch_clk(clkp); + if (clkh->is_prepared && clkh != branch) + other_rate = max(clkp->rate, other_rate); + } + curr_rate = max(other_rate, c->rate); + new_rate = max(other_rate, rate); + if (new_rate != curr_rate) { + ret = clk_set_rate(parent, new_rate); + if (!ret) + c->rate = rate; + } +exit: + mutex_unlock(&branch_clk_lock); + return ret; +} + +static long branch_clk_round_rate(struct clk *c, unsigned long rate) +{ + struct branch_clk *branch = to_branch_clk(c); + + if (branch->max_div) + return rate <= (branch->max_div) ? rate : -EPERM; + + if (!branch->has_sibling) + return clk_round_rate(c->parent, rate); + + return -EPERM; +} + +static unsigned long branch_clk_get_rate(struct clk *c) +{ + struct branch_clk *branch = to_branch_clk(c); + + if (branch->max_div) + return branch->c.rate; + + return clk_get_rate(c->parent); +} + +static long branch_clk_list_rate(struct clk *c, unsigned long n) +{ + int level; + unsigned long fmax = 0, rate; + struct branch_clk *branch = to_branch_clk(c); + struct clk *parent = c->parent; + + if (branch->has_sibling == 1) + return -ENXIO; + + if (!parent || !parent->ops->list_rate) + return -ENXIO; + + /* Find max frequency supported within voltage constraints. */ + if (!parent->vdd_class) { + fmax = ULONG_MAX; + } else { + for (level = 0; level < parent->num_fmax; level++) + if (parent->fmax[level]) + fmax = parent->fmax[level]; + } + + rate = parent->ops->list_rate(parent, n); + if (rate <= fmax) + return rate; + else + return -ENXIO; +} + +static enum handoff branch_clk_handoff(struct clk *c) +{ + struct branch_clk *branch = to_branch_clk(c); + u32 cbcr_regval; + + cbcr_regval = readl_relaxed(CBCR_REG(branch)); + + /* Set the cdiv to c->rate for fixed divider branch clock */ + if (c->rate && (c->rate < branch->max_div)) { + cbcr_regval &= ~BM(CBCR_CDIV_MSB, CBCR_CDIV_LSB); + cbcr_regval |= BVAL(CBCR_CDIV_MSB, CBCR_CDIV_LSB, c->rate); + writel_relaxed(cbcr_regval, CBCR_REG(branch)); + } + + if ((cbcr_regval & CBCR_BRANCH_OFF_BIT)) + return HANDOFF_DISABLED_CLK; + + if (!(cbcr_regval & CBCR_BRANCH_ENABLE_BIT)) { + if (!branch->check_enable_bit) { + pr_warn("%s clock is enabled in HW", c->dbg_name); + pr_warn("even though ENABLE_BIT is not set\n"); + } + return HANDOFF_DISABLED_CLK; + } + + if (branch->max_div) { + cbcr_regval &= BM(CBCR_CDIV_MSB, CBCR_CDIV_LSB); + cbcr_regval >>= CBCR_CDIV_LSB; + c->rate = cbcr_regval; + } else if (!branch->has_sibling) { + c->rate = clk_get_rate(c->parent); + } + + return HANDOFF_ENABLED_CLK; +} + +static int __branch_clk_reset(void __iomem *bcr_reg, + enum clk_reset_action action) +{ + int ret = 0; + unsigned long flags; + u32 reg_val; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + reg_val = readl_relaxed(bcr_reg); + switch (action) { + case CLK_RESET_ASSERT: + reg_val |= BCR_BLK_ARES_BIT; + break; + case CLK_RESET_DEASSERT: + reg_val &= ~BCR_BLK_ARES_BIT; + break; + default: + ret = -EINVAL; + } + writel_relaxed(reg_val, bcr_reg); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + /* Make sure write is issued before returning. */ + mb(); + + return ret; +} + +static int branch_clk_reset(struct clk *c, enum clk_reset_action action) +{ + struct branch_clk *branch = to_branch_clk(c); + + if (!branch->bcr_reg) + return -EPERM; + return __branch_clk_reset(BCR_REG(branch), action); +} + +static void __iomem *branch_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct branch_clk *branch = to_branch_clk(c); + static struct clk_register_data data[] = { + {"CBCR", 0x0}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return CBCR_REG(branch); +} + +/* + * Voteable clock functions + */ +static int local_vote_clk_reset(struct clk *c, enum clk_reset_action action) +{ + struct local_vote_clk *vclk = to_local_vote_clk(c); + + if (!vclk->bcr_reg) { + WARN("clk_reset called on an unsupported clock (%s)\n", + c->dbg_name); + return -EPERM; + } + return __branch_clk_reset(BCR_REG(vclk), action); +} + +static int local_vote_clk_enable(struct clk *c) +{ + unsigned long flags; + u32 ena; + struct local_vote_clk *vclk = to_local_vote_clk(c); + + spin_lock_irqsave(&local_clock_reg_lock, flags); + ena = readl_relaxed(VOTE_REG(vclk)); + ena |= vclk->en_mask; + writel_relaxed(ena, VOTE_REG(vclk)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + branch_clk_halt_check(c, vclk->halt_check, CBCR_REG(vclk), BRANCH_ON); + + return 0; +} + +static void local_vote_clk_disable(struct clk *c) +{ + unsigned long flags; + u32 ena; + struct local_vote_clk *vclk = to_local_vote_clk(c); + + spin_lock_irqsave(&local_clock_reg_lock, flags); + ena = readl_relaxed(VOTE_REG(vclk)); + ena &= ~vclk->en_mask; + writel_relaxed(ena, VOTE_REG(vclk)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +static enum handoff local_vote_clk_handoff(struct clk *c) +{ + struct local_vote_clk *vclk = to_local_vote_clk(c); + u32 vote_regval; + + /* Is the branch voted on by apps? */ + vote_regval = readl_relaxed(VOTE_REG(vclk)); + if (!(vote_regval & vclk->en_mask)) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +/* Sample clock for 'ticks' reference clock ticks. */ +static u32 run_measurement(unsigned long ticks, void __iomem *ctl_reg, + void __iomem *status_reg) +{ + /* Stop counters and set the XO4 counter start value. */ + writel_relaxed(ticks, ctl_reg); + + /* Wait for timer to become ready. */ + while ((readl_relaxed(status_reg) & BIT(25)) != 0) + cpu_relax(); + + /* Run measurement and wait for completion. */ + writel_relaxed(BIT(20)|ticks, ctl_reg); + while ((readl_relaxed(status_reg) & BIT(25)) == 0) + cpu_relax(); + + /* Return measured ticks. */ + return readl_relaxed(status_reg) & BM(24, 0); +} + +/* + * Perform a hardware rate measurement for a given clock. + * FOR DEBUG USE ONLY: Measurements take ~15 ms! + */ +unsigned long measure_get_rate(struct clk *c) +{ + unsigned long flags; + u32 gcc_xo4_reg, regval; + u64 raw_count_short, raw_count_full; + unsigned long ret; + u32 sample_ticks = 0x10000; + u32 multiplier = to_mux_clk(c)->post_div + 1; + struct measure_clk_data *data = to_mux_clk(c)->priv; + + regval = readl_relaxed(MUX_REG(to_mux_clk(c))); + /* clear and set post divider bits */ + regval &= ~BM(15, 12); + regval |= BVAL(15, 12, to_mux_clk(c)->post_div); + writel_relaxed(regval, MUX_REG(to_mux_clk(c))); + + ret = clk_prepare_enable(data->cxo); + if (ret) { + pr_warn("CXO clock failed to enable. Can't measure\n"); + ret = 0; + goto fail; + } + + spin_lock_irqsave(&local_clock_reg_lock, flags); + + /* Enable CXO/4 and RINGOSC branch. */ + gcc_xo4_reg = readl_relaxed(*data->base + data->xo_div4_cbcr); + gcc_xo4_reg |= CBCR_BRANCH_ENABLE_BIT; + writel_relaxed(gcc_xo4_reg, *data->base + data->xo_div4_cbcr); + + /* + * 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, *data->base + data->ctl_reg, + *data->base + data->status_reg); + /* Run a full measurement. (~14 ms) */ + raw_count_full = run_measurement(sample_ticks, + *data->base + data->ctl_reg, + *data->base + data->status_reg); + + gcc_xo4_reg &= ~CBCR_BRANCH_ENABLE_BIT; + writel_relaxed(gcc_xo4_reg, *data->base + data->xo_div4_cbcr); + + /* 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); + } + writel_relaxed(data->plltest_val, *data->base + data->plltest_reg); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + clk_disable_unprepare(data->cxo); + +fail: + regval = readl_relaxed(MUX_REG(to_mux_clk(c))); + /* clear post divider bits */ + regval &= ~BM(15, 12); + writel_relaxed(regval, MUX_REG(to_mux_clk(c))); + + return ret; +} + +struct frac_entry { + int num; + int den; +}; + +static void __iomem *local_vote_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct local_vote_clk *vclk = to_local_vote_clk(c); + static struct clk_register_data data1[] = { + {"CBCR", 0x0}, + }; + static struct clk_register_data data2[] = { + {"APPS_VOTE", 0x0}, + {"APPS_SLEEP_VOTE", 0x4}, + }; + switch (n) { + case 0: + *regs = data1; + *size = ARRAY_SIZE(data1); + return CBCR_REG(vclk); + case 1: + *regs = data2; + *size = ARRAY_SIZE(data2); + return VOTE_REG(vclk); + default: + return ERR_PTR(-EINVAL); + } +} + +static struct frac_entry frac_table_675m[] = { /* link rate of 270M */ + {52, 295}, /* 119 M */ + {11, 57}, /* 130.25 M */ + {63, 307}, /* 138.50 M */ + {11, 50}, /* 148.50 M */ + {47, 206}, /* 154 M */ + {31, 100}, /* 205.25 M */ + {107, 269}, /* 268.50 M */ + {0, 0}, +}; + +static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */ + {31, 211}, /* 119 M */ + {32, 199}, /* 130.25 M */ + {63, 307}, /* 138.50 M */ + {11, 60}, /* 148.50 M */ + {50, 263}, /* 154 M */ + {31, 120}, /* 205.25 M */ + {119, 359}, /* 268.50 M */ + {0, 0}, +}; + +static bool is_same_rcg_config(struct rcg_clk *rcg, struct clk_freq_tbl *freq, + bool has_mnd) +{ + u32 cfg; + + /* RCG update pending */ + if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_CONFIG_DIRTY_MASK) + return false; + if (has_mnd) + if (readl_relaxed(M_REG(rcg)) != freq->m_val || + readl_relaxed(N_REG(rcg)) != freq->n_val || + readl_relaxed(D_REG(rcg)) != freq->d_val) + return false; + /* + * Both 0 and 1 represent same divider value in HW. + * Always use 0 to simplify comparison. + */ + if ((freq->div_src_val & CFG_RCGR_DIV_MASK) == 1) + freq->div_src_val &= ~CFG_RCGR_DIV_MASK; + cfg = readl_relaxed(CFG_RCGR_REG(rcg)); + if ((cfg & CFG_RCGR_DIV_MASK) == 1) + cfg &= ~CFG_RCGR_DIV_MASK; + if (cfg != freq->div_src_val) + return false; + + return true; +} + +static int set_rate_edp_pixel(struct clk *clk, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + struct clk_freq_tbl *pixel_freq = rcg->current_freq; + struct frac_entry *frac; + int delta = 100000; + s64 request; + s64 src_rate; + unsigned long flags; + + src_rate = clk_get_rate(clk->parent); + + if (src_rate == 810000000) + frac = frac_table_810m; + else + frac = frac_table_675m; + + while (frac->num) { + request = rate; + request *= frac->den; + request = div_s64(request, frac->num); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) { + frac++; + continue; + } + + pixel_freq->div_src_val &= ~BM(4, 0); + if (frac->den == frac->num) { + pixel_freq->m_val = 0; + pixel_freq->n_val = 0; + } else { + pixel_freq->m_val = frac->num; + pixel_freq->n_val = ~(frac->den - frac->num); + pixel_freq->d_val = ~frac->den; + } + spin_lock_irqsave(&local_clock_reg_lock, flags); + if (!is_same_rcg_config(rcg, pixel_freq, true)) + __set_rate_mnd(rcg, pixel_freq); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + return 0; + } + return -EINVAL; +} + +enum handoff byte_rcg_handoff(struct clk *clk) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + u32 div_val; + unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent); + + /* If the pre-divider is used, find the rate after the division */ + div_val = readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_DIV_MASK; + if (div_val > 1) + pre_div_rate = parent_rate / ((div_val + 1) >> 1); + else + pre_div_rate = parent_rate; + + clk->rate = pre_div_rate; + + if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +static int set_rate_byte(struct clk *clk, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + struct clk *pll = clk->parent; + unsigned long source_rate, div, flags; + struct clk_freq_tbl *byte_freq = rcg->current_freq; + int rc; + + if (rate == 0) + return -EINVAL; + + rc = clk_set_rate(pll, rate); + if (rc) + return rc; + + source_rate = clk_round_rate(pll, rate); + if ((2 * source_rate) % rate) + return -EINVAL; + + div = ((2 * source_rate)/rate) - 1; + if (div > CFG_RCGR_DIV_MASK) + return -EINVAL; + + /* + * Both 0 and 1 represent same divider value in HW. + * Always use 0 to simplify comparison. + */ + div = (div == 1) ? 0 : div; + + byte_freq->div_src_val &= ~CFG_RCGR_DIV_MASK; + byte_freq->div_src_val |= BVAL(4, 0, div); + + spin_lock_irqsave(&local_clock_reg_lock, flags); + if (!is_same_rcg_config(rcg, byte_freq, false)) + __set_rate_hid(rcg, byte_freq); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + return 0; +} + +enum handoff pixel_rcg_handoff(struct clk *clk) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + u32 div_val = 0, mval = 0, nval = 0, cfg_regval; + unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent); + + cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg)); + + /* If the pre-divider is used, find the rate after the division */ + div_val = cfg_regval & CFG_RCGR_DIV_MASK; + if (div_val > 1) + pre_div_rate = parent_rate / ((div_val + 1) >> 1); + else + pre_div_rate = parent_rate; + + clk->rate = pre_div_rate; + + /* + * Pixel clocks have one frequency entry in their frequency table. + * Update that entry. + */ + if (rcg->current_freq) { + rcg->current_freq->div_src_val &= ~CFG_RCGR_DIV_MASK; + rcg->current_freq->div_src_val |= div_val; + } + + /* If MND is used, find the rate after the MND division */ + if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) { + mval = readl_relaxed(M_REG(rcg)); + nval = readl_relaxed(N_REG(rcg)); + if (!nval) + return HANDOFF_DISABLED_CLK; + nval = (~nval) + mval; + if (rcg->current_freq) { + rcg->current_freq->n_val = ~(nval - mval); + rcg->current_freq->m_val = mval; + rcg->current_freq->d_val = ~nval; + } + clk->rate = (pre_div_rate * mval) / nval; + } + + if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_ROOT_STATUS_BIT) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +static long round_rate_pixel(struct clk *clk, unsigned long rate) +{ + int frac_num[] = {3, 2, 4, 1}; + int frac_den[] = {8, 9, 9, 1}; + int delta = 100000; + int i; + + for (i = 0; i < ARRAY_SIZE(frac_num); i++) { + unsigned long request = (rate * frac_den[i]) / frac_num[i]; + unsigned long src_rate; + + src_rate = clk_round_rate(clk->parent, request); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + return (src_rate * frac_num[i]) / frac_den[i]; + } + + return -EINVAL; +} + + +static int set_rate_pixel(struct clk *clk, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + struct clk_freq_tbl *pixel_freq = rcg->current_freq; + int frac_num[] = {3, 2, 4, 1}; + int frac_den[] = {8, 9, 9, 1}; + int delta = 100000; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(frac_num); i++) { + unsigned long request = (rate * frac_den[i]) / frac_num[i]; + unsigned long src_rate; + + src_rate = clk_round_rate(clk->parent, request); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + rc = clk_set_rate(clk->parent, src_rate); + if (rc) + return rc; + + pixel_freq->div_src_val &= ~BM(4, 0); + if (frac_den[i] == frac_num[i]) { + pixel_freq->m_val = 0; + pixel_freq->n_val = 0; + } else { + pixel_freq->m_val = frac_num[i]; + pixel_freq->n_val = ~(frac_den[i] - frac_num[i]); + pixel_freq->d_val = ~frac_den[i]; + } + set_rate_mnd(rcg, pixel_freq); + return 0; + } + return -EINVAL; +} + +static int rcg_clk_set_parent(struct clk *clk, struct clk *parent_clk) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + struct clk *old_parent = clk->parent; + struct clk_freq_tbl *nf; + unsigned long flags; + int rc = 0; + unsigned int parent_rate, rate; + u32 m_val, n_val, d_val, div_val; + u32 cfg_regval; + + /* Find the source clock freq tbl for the requested parent */ + if (!rcg->freq_tbl) + return -ENXIO; + + for (nf = rcg->freq_tbl; parent_clk != nf->src_clk; nf++) { + if (nf->freq_hz == FREQ_END) + return -ENXIO; + } + + /* This implementation recommends that the RCG be unprepared + * when switching RCG source since the divider configuration + * remains unchanged. + */ + WARN(clk->prepare_count, + "Trying to switch RCG source while it is prepared!\n"); + + parent_rate = clk_get_rate(parent_clk); + + div_val = (rcg->current_freq->div_src_val & CFG_RCGR_DIV_MASK); + if (div_val) + parent_rate /= ((div_val + 1) >> 1); + + /* Update divisor. Source select bits should already be as expected */ + nf->div_src_val &= ~CFG_RCGR_DIV_MASK; + nf->div_src_val |= div_val; + + cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg)); + + if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) { + nf->m_val = m_val = readl_relaxed(M_REG(rcg)); + n_val = readl_relaxed(N_REG(rcg)); + d_val = readl_relaxed(D_REG(rcg)); + + /* Sign extend the n and d values as those in registers are not + * sign extended. + */ + n_val |= (n_val >> 8) ? BM(31, 16) : BM(31, 8); + d_val |= (d_val >> 8) ? BM(31, 16) : BM(31, 8); + + nf->n_val = n_val; + nf->d_val = d_val; + + n_val = ~(n_val) + m_val; + rate = parent_rate * m_val; + if (n_val) + rate /= n_val; + else + WARN(1, "n_val was 0!!"); + } else + rate = parent_rate; + + /* Warn if switching to the new parent with the current m, n ,d values + * violates the voltage constraints for the RCG. + */ + WARN(!is_rate_valid(clk, rate) && clk->prepare_count, + "Switch to new RCG parent violates voltage requirement!\n"); + + rc = __clk_pre_reparent(clk, nf->src_clk, &flags); + if (rc) + return rc; + + /* Switch RCG source */ + rcg->set_rate(rcg, nf); + + rcg->current_freq = nf; + clk->parent = parent_clk; + clk->rate = rate; + + __clk_post_reparent(clk, old_parent, &flags); + + return 0; +} + +/* + * Unlike other clocks, the HDMI rate is adjusted through PLL + * re-programming. It is also routed through an HID divider. + */ +static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + struct clk_freq_tbl *nf = rcg->freq_tbl; + int rc; + + rc = clk_set_rate(nf->src_clk, rate); + if (rc < 0) + goto out; + set_rate_hid(rcg, nf); + + rcg->current_freq = nf; +out: + return rc; +} + +static struct clk *rcg_hdmi_clk_get_parent(struct clk *c) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + struct clk_freq_tbl *freq = rcg->freq_tbl; + u32 cmd_rcgr_regval; + + /* Is there a pending configuration? */ + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK) + return NULL; + + rcg->current_freq->freq_hz = clk_get_rate(c->parent); + + return freq->src_clk; +} + +static int rcg_clk_set_rate_edp(struct clk *c, unsigned long rate) +{ + struct clk_freq_tbl *nf; + struct rcg_clk *rcg = to_rcg_clk(c); + int rc; + + for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++) + if (nf->freq_hz == FREQ_END) { + rc = -EINVAL; + goto out; + } + + rc = clk_set_rate(nf->src_clk, rate); + if (rc < 0) + goto out; + set_rate_hid(rcg, nf); + + rcg->current_freq = nf; + c->parent = nf->src_clk; +out: + return rc; +} + +static struct clk *edp_clk_get_parent(struct clk *c) +{ + struct rcg_clk *rcg = to_rcg_clk(c); + struct clk *clk; + struct clk_freq_tbl *freq; + unsigned long rate; + u32 cmd_rcgr_regval; + + /* Is there a pending configuration? */ + cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg)); + if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK) + return NULL; + + /* Figure out what rate the rcg is running at */ + for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) { + clk = freq->src_clk; + if (clk && clk->ops->get_rate) { + rate = clk->ops->get_rate(clk); + if (rate == freq->freq_hz) + break; + } + } + + /* No known frequency found */ + if (freq->freq_hz == FREQ_END) + return NULL; + + rcg->current_freq = freq; + return freq->src_clk; +} + +static int gate_clk_enable(struct clk *c) +{ + unsigned long flags; + u32 regval; + struct gate_clk *g = to_gate_clk(c); + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(GATE_EN_REG(g)); + regval |= g->en_mask; + writel_relaxed(regval, GATE_EN_REG(g)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + if (g->delay_us) + udelay(g->delay_us); + + return 0; +} + +static void gate_clk_disable(struct clk *c) +{ + unsigned long flags; + u32 regval; + struct gate_clk *g = to_gate_clk(c); + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(GATE_EN_REG(g)); + regval &= ~(g->en_mask); + writel_relaxed(regval, GATE_EN_REG(g)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + if (g->delay_us) + udelay(g->delay_us); +} + +static void __iomem *gate_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct gate_clk *g = to_gate_clk(c); + static struct clk_register_data data[] = { + {"EN_REG", 0x0}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return GATE_EN_REG(g); +} + +static enum handoff gate_clk_handoff(struct clk *c) +{ + struct gate_clk *g = to_gate_clk(c); + u32 regval; + + regval = readl_relaxed(GATE_EN_REG(g)); + if (regval & g->en_mask) + return HANDOFF_ENABLED_CLK; + + return HANDOFF_DISABLED_CLK; +} + +static int gate_clk_set_flags(struct clk *c, unsigned long flags) +{ + return cbcr_set_flags(GATE_EN_REG(to_gate_clk(c)), flags); +} + + +static int reset_clk_rst(struct clk *c, enum clk_reset_action action) +{ + struct reset_clk *rst = to_reset_clk(c); + + if (!rst->reset_reg) + return -EPERM; + + return __branch_clk_reset(RST_REG(rst), action); +} + +static void __iomem *reset_clk_list_registers(struct clk *clk, int n, + struct clk_register_data **regs, u32 *size) +{ + struct reset_clk *rst = to_reset_clk(clk); + static struct clk_register_data data[] = { + {"BCR", 0x0}, + }; + + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return RST_REG(rst); +} + +static DEFINE_SPINLOCK(mux_reg_lock); + +static int mux_reg_enable(struct mux_clk *clk) +{ + u32 regval; + unsigned long flags; + + if (!clk->en_mask) + return 0; + + spin_lock_irqsave(&mux_reg_lock, flags); + regval = readl_relaxed(*clk->base + clk->en_offset); + regval |= clk->en_mask; + writel_relaxed(regval, *clk->base + clk->en_offset); + /* Ensure enable request goes through before returning */ + mb(); + spin_unlock_irqrestore(&mux_reg_lock, flags); + + return 0; +} + +static void mux_reg_disable(struct mux_clk *clk) +{ + u32 regval; + unsigned long flags; + + if (!clk->en_mask) + return; + + spin_lock_irqsave(&mux_reg_lock, flags); + regval = readl_relaxed(*clk->base + clk->en_offset); + regval &= ~clk->en_mask; + writel_relaxed(regval, *clk->base + clk->en_offset); + spin_unlock_irqrestore(&mux_reg_lock, flags); +} + +static int mux_reg_set_mux_sel(struct mux_clk *clk, int sel) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&mux_reg_lock, flags); + regval = readl_relaxed(MUX_REG(clk)); + regval &= ~(clk->mask << clk->shift); + regval |= (sel & clk->mask) << clk->shift; + writel_relaxed(regval, MUX_REG(clk)); + /* Ensure switch request goes through before returning */ + mb(); + spin_unlock_irqrestore(&mux_reg_lock, flags); + + return 0; +} + +static int mux_reg_get_mux_sel(struct mux_clk *clk) +{ + u32 regval = readl_relaxed(MUX_REG(clk)); + + return (regval >> clk->shift) & clk->mask; +} + +static bool mux_reg_is_enabled(struct mux_clk *clk) +{ + u32 regval = readl_relaxed(MUX_REG(clk)); + + return !!(regval & clk->en_mask); +} + +static void __iomem *mux_clk_list_registers(struct mux_clk *clk, int n, + struct clk_register_data **regs, u32 *size) +{ + static struct clk_register_data data[] = { + {"DEBUG_CLK_CTL", 0x0}, + }; + + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return *clk->base + clk->offset; +} + +/* PLL post-divider setting for each divider value */ +static struct div_map postdiv_map[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 3 }, + { 0x3, 4 }, + { 0x5, 5 }, + { 0x7, 7 }, + { 0x7, 8 }, + { 0xF, 16 }, +}; + +static int postdiv_reg_set_div(struct div_clk *clk, int div) +{ + struct clk *parent = NULL; + u32 regval; + unsigned long flags; + unsigned int mask = -1; + int i, ret = 0; + + /* Divider is not configurable */ + if (!clk->mask) + return 0; + + for (i = 0; i < ARRAY_SIZE(postdiv_map); i++) { + if (postdiv_map[i].div == div) { + mask = postdiv_map[i].mask; + break; + } + } + + if (mask < 0) + return -EINVAL; + + spin_lock_irqsave(&clk->c.lock, flags); + parent = clk->c.parent; + if (parent->count && parent->ops->disable) + parent->ops->disable(parent); + + regval = readl_relaxed(DIV_REG(clk)); + regval &= ~(clk->mask << clk->shift); + regval |= (mask & clk->mask) << clk->shift; + writel_relaxed(regval, DIV_REG(clk)); + /* Ensure switch request goes through before returning */ + mb(); + + if (parent->count && parent->ops->enable) { + ret = parent->ops->enable(parent); + if (ret) + pr_err("Failed to force enable div parent!\n"); + } + + spin_unlock_irqrestore(&clk->c.lock, flags); + return ret; +} + +static int postdiv_reg_get_div(struct div_clk *clk) +{ + u32 regval; + int i, div = 0; + + /* Divider is not configurable */ + if (!clk->mask) + return clk->data.div; + + regval = readl_relaxed(DIV_REG(clk)); + regval = (regval >> clk->shift) & clk->mask; + for (i = 0; i < ARRAY_SIZE(postdiv_map); i++) { + if (postdiv_map[i].mask == regval) { + div = postdiv_map[i].div; + break; + } + } + if (!div) + return -EINVAL; + + return div; +} + +static int div_reg_set_div(struct div_clk *clk, int div) +{ + u32 regval; + unsigned long flags; + + /* Divider is not configurable */ + if (!clk->mask) + return 0; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(*clk->base + clk->offset); + regval &= ~(clk->mask << clk->shift); + regval |= (div & clk->mask) << clk->shift; + /* Ensure switch request goes through before returning */ + mb(); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + return 0; +} + +static int div_reg_get_div(struct div_clk *clk) +{ + u32 regval; + /* Divider is not configurable */ + if (!clk->mask) + return clk->data.div; + + regval = readl_relaxed(*clk->base + clk->offset); + return (regval >> clk->shift) & clk->mask; +} + +/* =================Half-integer RCG without MN counter================= */ +#define RCGR_CMD_REG(x) ((x)->base + (x)->div_offset) +#define RCGR_DIV_REG(x) ((x)->base + (x)->div_offset + 4) +#define RCGR_SRC_REG(x) ((x)->base + (x)->div_offset + 4) + +static int rcg_mux_div_update_config(struct mux_div_clk *md) +{ + u32 regval, count; + + regval = readl_relaxed(RCGR_CMD_REG(md)); + regval |= CMD_RCGR_CONFIG_UPDATE_BIT; + writel_relaxed(regval, RCGR_CMD_REG(md)); + + /* Wait for update to take effect */ + for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) { + if (!(readl_relaxed(RCGR_CMD_REG(md)) & + CMD_RCGR_CONFIG_UPDATE_BIT)) + return 0; + udelay(1); + } + + CLK_WARN(&md->c, true, "didn't update its configuration."); + + return -EBUSY; +} + +static void rcg_get_src_div(struct mux_div_clk *md, u32 *src_sel, u32 *div) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + /* Is there a pending configuration? */ + regval = readl_relaxed(RCGR_CMD_REG(md)); + if (regval & CMD_RCGR_CONFIG_DIRTY_MASK) { + CLK_WARN(&md->c, true, "it's a pending configuration."); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + return; + } + + regval = readl_relaxed(RCGR_DIV_REG(md)); + regval &= (md->div_mask << md->div_shift); + *div = regval >> md->div_shift; + + /* bypass */ + if (*div == 0) + *div = 1; + /* the div is doubled here*/ + *div += 1; + + regval = readl_relaxed(RCGR_SRC_REG(md)); + regval &= (md->src_mask << md->src_shift); + *src_sel = regval >> md->src_shift; + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +static void mux_div_set_force_enable(struct mux_div_clk *md) +{ + u32 regval; + unsigned long flags; + int count; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(RCGR_CMD_REG(md)); + regval |= CMD_RCGR_ROOT_ENABLE_BIT; + writel_relaxed(regval, RCGR_CMD_REG(md)); + + /* Wait for RCG to turn ON */ + for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) { + if (!(readl_relaxed(RCGR_CMD_REG(md)) & + CMD_RCGR_CONFIG_UPDATE_BIT)) + goto exit; + udelay(1); + } + CLK_WARN(&md->c, count == 0, "rcg didn't turn on."); +exit: + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +static void mux_div_clear_force_enable(struct mux_div_clk *md) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(RCGR_CMD_REG(md)); + regval &= ~CMD_RCGR_ROOT_ENABLE_BIT; + writel_relaxed(regval, RCGR_CMD_REG(md)); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +static int rcg_set_src_div(struct mux_div_clk *md, u32 src_sel, u32 div) +{ + u32 regval; + unsigned long flags; + int ret; + + /* for half-integer divider, div here is doubled */ + if (div) + div -= 1; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + regval = readl_relaxed(RCGR_DIV_REG(md)); + regval &= ~(md->div_mask << md->div_shift); + regval |= div << md->div_shift; + writel_relaxed(regval, RCGR_DIV_REG(md)); + + regval = readl_relaxed(RCGR_SRC_REG(md)); + regval &= ~(md->src_mask << md->src_shift); + regval |= src_sel << md->src_shift; + writel_relaxed(regval, RCGR_SRC_REG(md)); + + ret = rcg_mux_div_update_config(md); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + return ret; +} + +static int rcg_enable(struct mux_div_clk *md) +{ + if (md->force_enable_md) + mux_div_set_force_enable(md); + + return rcg_set_src_div(md, md->src_sel, md->data.div); +} + +static void rcg_disable(struct mux_div_clk *md) +{ + u32 src_sel; + + if (md->force_enable_md) + mux_div_clear_force_enable(md); + + if (!md->safe_freq) + return; + + src_sel = parent_to_src_sel(md->parents, md->num_parents, + md->safe_parent); + + rcg_set_src_div(md, src_sel, md->safe_div); +} + +static bool rcg_is_enabled(struct mux_div_clk *md) +{ + u32 regval; + + regval = readl_relaxed(RCGR_CMD_REG(md)); + if (regval & CMD_RCGR_ROOT_STATUS_BIT) + return false; + else + return true; +} + +static void __iomem *rcg_list_registers(struct mux_div_clk *md, int n, + struct clk_register_data **regs, u32 *size) +{ + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + }; + + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return RCGR_CMD_REG(md); +} + +const struct clk_ops clk_ops_empty; + +const struct clk_ops clk_ops_rst = { + .reset = reset_clk_rst, + .list_registers = reset_clk_list_registers, +}; + +const struct clk_ops clk_ops_rcg = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = rcg_clk_set_rate, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = rcg_clk_handoff, + .get_parent = rcg_clk_get_parent, + .set_parent = rcg_clk_set_parent, + .list_registers = rcg_hid_clk_list_registers, +}; + +const struct clk_ops clk_ops_rcg_mnd = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = rcg_clk_set_rate, + .set_duty_cycle = rcg_clk_set_duty_cycle, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = rcg_mnd_clk_handoff, + .get_parent = rcg_mnd_clk_get_parent, + .set_parent = rcg_clk_set_parent, + .list_registers = rcg_mnd_clk_list_registers, +}; + +const struct clk_ops clk_ops_pixel = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = set_rate_pixel, + .list_rate = rcg_clk_list_rate, + .round_rate = round_rate_pixel, + .handoff = pixel_rcg_handoff, + .list_registers = rcg_mnd_clk_list_registers, +}; + +const struct clk_ops clk_ops_pixel_multiparent = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = set_rate_pixel, + .list_rate = rcg_clk_list_rate, + .round_rate = round_rate_pixel, + .handoff = pixel_rcg_handoff, + .list_registers = rcg_mnd_clk_list_registers, + .get_parent = display_clk_get_parent, + .set_parent = rcg_clk_set_parent, +}; + +const struct clk_ops clk_ops_edppixel = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = set_rate_edp_pixel, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = pixel_rcg_handoff, + .list_registers = rcg_mnd_clk_list_registers, +}; + +const struct clk_ops clk_ops_byte = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = set_rate_byte, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = byte_rcg_handoff, + .list_registers = rcg_hid_clk_list_registers, +}; + +const struct clk_ops clk_ops_byte_multiparent = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = set_rate_byte, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = byte_rcg_handoff, + .list_registers = rcg_hid_clk_list_registers, + .get_parent = display_clk_get_parent, + .set_parent = rcg_clk_set_parent, +}; + +const struct clk_ops clk_ops_rcg_hdmi = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = rcg_clk_set_rate_hdmi, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = rcg_clk_handoff, + .get_parent = rcg_hdmi_clk_get_parent, + .list_registers = rcg_hid_clk_list_registers, +}; + +const struct clk_ops clk_ops_rcg_edp = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = rcg_clk_set_rate_edp, + .list_rate = rcg_clk_list_rate, + .round_rate = rcg_clk_round_rate, + .handoff = rcg_clk_handoff, + .get_parent = edp_clk_get_parent, + .list_registers = rcg_hid_clk_list_registers, +}; + +const struct clk_ops clk_ops_branch = { + .enable = branch_clk_enable, + .prepare = branch_clk_prepare, + .disable = branch_clk_disable, + .unprepare = branch_clk_unprepare, + .set_rate = branch_clk_set_rate, + .get_rate = branch_clk_get_rate, + .list_rate = branch_clk_list_rate, + .round_rate = branch_clk_round_rate, + .reset = branch_clk_reset, + .set_flags = branch_clk_set_flags, + .handoff = branch_clk_handoff, + .list_registers = branch_clk_list_registers, +}; + +const struct clk_ops clk_ops_vote = { + .enable = local_vote_clk_enable, + .disable = local_vote_clk_disable, + .reset = local_vote_clk_reset, + .handoff = local_vote_clk_handoff, + .list_registers = local_vote_clk_list_registers, +}; + +const struct clk_ops clk_ops_gate = { + .enable = gate_clk_enable, + .disable = gate_clk_disable, + .set_rate = parent_set_rate, + .get_rate = parent_get_rate, + .round_rate = parent_round_rate, + .set_flags = gate_clk_set_flags, + .handoff = gate_clk_handoff, + .list_registers = gate_clk_list_registers, +}; + +struct clk_mux_ops mux_reg_ops = { + .enable = mux_reg_enable, + .disable = mux_reg_disable, + .set_mux_sel = mux_reg_set_mux_sel, + .get_mux_sel = mux_reg_get_mux_sel, + .is_enabled = mux_reg_is_enabled, + .list_registers = mux_clk_list_registers, +}; + +struct clk_div_ops div_reg_ops = { + .set_div = div_reg_set_div, + .get_div = div_reg_get_div, +}; + +const struct clk_div_ops postdiv_reg_ops = { + .set_div = postdiv_reg_set_div, + .get_div = postdiv_reg_get_div, +}; + +struct mux_div_ops rcg_mux_div_ops = { + .enable = rcg_enable, + .disable = rcg_disable, + .set_src_div = rcg_set_src_div, + .get_src_div = rcg_get_src_div, + .is_enabled = rcg_is_enabled, + .list_registers = rcg_list_registers, +}; + +static void *cbc_dt_parser(struct device *dev, struct device_node *np) +{ + struct msmclk_data *drv; + struct branch_clk *branch_clk; + u32 rc; + + branch_clk = devm_kzalloc(dev, sizeof(*branch_clk), GFP_KERNEL); + if (!branch_clk) + return ERR_PTR(-ENOMEM); + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + branch_clk->base = &drv->base; + + rc = of_property_read_u32(np, "qcom,base-offset", + &branch_clk->cbcr_reg); + if (rc) { + dt_err(np, "missing/incorrect qcom,base-offset dt property\n"); + return ERR_PTR(rc); + } + + /* Optional property */ + of_property_read_u32(np, "qcom,bcr-offset", &branch_clk->bcr_reg); + + of_property_read_u32(np, "qcom,halt-check", + (u32 *)&branch_clk->halt_check); + + branch_clk->has_sibling = of_property_read_bool(np, + "qcom,has-sibling"); + + branch_clk->c.ops = &clk_ops_branch; + + return msmclk_generic_clk_init(dev, np, &branch_clk->c); +} +MSMCLK_PARSER(cbc_dt_parser, "qcom,cbc", 0); + +static void *local_vote_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct local_vote_clk *vote_clk; + struct msmclk_data *drv; + int rc, val; + + vote_clk = devm_kzalloc(dev, sizeof(*vote_clk), GFP_KERNEL); + if (!vote_clk) + return ERR_PTR(-ENOMEM); + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + vote_clk->base = &drv->base; + + rc = of_property_read_u32(np, "qcom,base-offset", + &vote_clk->cbcr_reg); + if (rc) { + dt_err(np, "missing/incorrect qcom,base-offset dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,en-offset", &vote_clk->vote_reg); + if (rc) { + dt_err(np, "missing/incorrect qcom,en-offset dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,en-bit", &val); + if (rc) { + dt_err(np, "missing/incorrect qcom,en-bit dt property\n"); + return ERR_PTR(-EINVAL); + } + vote_clk->en_mask = BIT(val); + + vote_clk->c.ops = &clk_ops_vote; + + /* Optional property */ + of_property_read_u32(np, "qcom,bcr-offset", &vote_clk->bcr_reg); + + return msmclk_generic_clk_init(dev, np, &vote_clk->c); +} +MSMCLK_PARSER(local_vote_clk_dt_parser, "qcom,local-vote-clk", 0); + +static void *gate_clk_dt_parser(struct device *dev, struct device_node *np) +{ + struct gate_clk *gate_clk; + struct msmclk_data *drv; + u32 en_bit, rc; + + gate_clk = devm_kzalloc(dev, sizeof(*gate_clk), GFP_KERNEL); + if (!gate_clk) + return ERR_PTR(-ENOMEM); + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + gate_clk->base = &drv->base; + + rc = of_property_read_u32(np, "qcom,en-offset", &gate_clk->en_reg); + if (rc) { + dt_err(np, "missing qcom,en-offset dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,en-bit", &en_bit); + if (rc) { + dt_err(np, "missing qcom,en-bit dt property\n"); + return ERR_PTR(-EINVAL); + } + gate_clk->en_mask = BIT(en_bit); + + /* Optional Property */ + rc = of_property_read_u32(np, "qcom,delay", &gate_clk->delay_us); + if (rc) + gate_clk->delay_us = 0; + + gate_clk->c.ops = &clk_ops_gate; + return msmclk_generic_clk_init(dev, np, &gate_clk->c); +} +MSMCLK_PARSER(gate_clk_dt_parser, "qcom,gate-clk", 0); + + +static inline u32 rcg_calc_m(u32 m, u32 n) +{ + return m; +} + +static inline u32 rcg_calc_n(u32 m, u32 n) +{ + n = n > 1 ? n : 0; + return ~((n)-(m)) * !!(n); +} + +static inline u32 rcg_calc_duty_cycle(u32 m, u32 n) +{ + return ~n; +} + +static inline u32 rcg_calc_div_src(u32 div_int, u32 div_frac, u32 src_sel) +{ + int div = 2 * div_int + (div_frac ? 1 : 0) - 1; + /* set bypass mode instead of a divider of 1 */ + div = (div != 1) ? div : 0; + return BVAL(4, 0, max(div, 0)) + | BVAL(10, 8, src_sel); +} + +struct clk_src *msmclk_parse_clk_src(struct device *dev, + struct device_node *np, int *array_size) +{ + struct clk_src *clks; + const void *prop; + int num_parents, len, i, prop_len, rc; + char *name = "qcom,parents"; + + if (!array_size) { + dt_err(np, "array_size must be a valid pointer\n"); + return ERR_PTR(-EINVAL); + } + + prop = of_get_property(np, name, &prop_len); + if (!prop) { + dt_prop_err(np, name, "missing dt property\n"); + return ERR_PTR(-EINVAL); + } + + len = sizeof(phandle) + sizeof(u32); + if (prop_len % len) { + dt_prop_err(np, name, "invalid property length\n"); + return ERR_PTR(-EINVAL); + } + num_parents = prop_len / len; + + clks = devm_kzalloc(dev, sizeof(*clks) * num_parents, GFP_KERNEL); + if (!clks) + return ERR_PTR(-ENOMEM); + + /* Assume that u32 and phandle have the same size */ + for (i = 0; i < num_parents; i++) { + phandle p; + struct clk_src *a = &clks[i]; + + rc = of_property_read_u32_index(np, name, 2 * i, &a->sel); + rc |= of_property_read_phandle_index(np, name, 2 * i + 1, &p); + + if (rc) { + dt_prop_err(np, name, + "unable to read parent clock or mux index\n"); + return ERR_PTR(-EINVAL); + } + + a->src = msmclk_parse_phandle(dev, p); + if (IS_ERR(a->src)) { + dt_prop_err(np, name, "hashtable lookup failed\n"); + return ERR_CAST(a->src); + } + } + + *array_size = num_parents; + + return clks; +} + +static int rcg_parse_freq_tbl(struct device *dev, + struct device_node *np, struct rcg_clk *rcg) +{ + const void *prop; + u32 prop_len, num_rows, i, j = 0; + struct clk_freq_tbl *tbl; + int rc; + char *name = "qcom,freq-tbl"; + + prop = of_get_property(np, name, &prop_len); + if (!prop) { + dt_prop_err(np, name, "missing dt property\n"); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % 6) { + dt_prop_err(np, name, "bad length\n"); + return -EINVAL; + } + + num_rows = prop_len / 6; + /* Array is null terminated. */ + rcg->freq_tbl = devm_kzalloc(dev, + sizeof(*rcg->freq_tbl) * (num_rows + 1), + GFP_KERNEL); + + if (!rcg->freq_tbl) { + dt_err(np, "memory alloc failure\n"); + return -ENOMEM; + } + + tbl = rcg->freq_tbl; + for (i = 0; i < num_rows; i++, tbl++) { + phandle p; + u32 div_int, div_frac, m, n, src_sel, freq_hz; + + rc = of_property_read_u32_index(np, name, j++, &freq_hz); + rc |= of_property_read_u32_index(np, name, j++, &div_int); + rc |= of_property_read_u32_index(np, name, j++, &div_frac); + rc |= of_property_read_u32_index(np, name, j++, &m); + rc |= of_property_read_u32_index(np, name, j++, &n); + rc |= of_property_read_u32_index(np, name, j++, &p); + + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return -EINVAL; + } + + tbl->freq_hz = (unsigned long)freq_hz; + tbl->src_clk = msmclk_parse_phandle(dev, p); + if (IS_ERR_OR_NULL(tbl->src_clk)) { + dt_prop_err(np, name, "hashtable lookup failure\n"); + return PTR_ERR(tbl->src_clk); + } + + tbl->m_val = rcg_calc_m(m, n); + tbl->n_val = rcg_calc_n(m, n); + tbl->d_val = rcg_calc_duty_cycle(m, n); + + src_sel = parent_to_src_sel(rcg->c.parents, + rcg->c.num_parents, tbl->src_clk); + tbl->div_src_val = rcg_calc_div_src(div_int, div_frac, + src_sel); + } + /* End table with special value */ + tbl->freq_hz = FREQ_END; + return 0; +} + +static void *rcg_clk_dt_parser(struct device *dev, struct device_node *np) +{ + struct rcg_clk *rcg; + struct msmclk_data *drv; + int rc; + + rcg = devm_kzalloc(dev, sizeof(*rcg), GFP_KERNEL); + if (!rcg) + return ERR_PTR(-ENOMEM); + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return drv; + rcg->base = &drv->base; + + rcg->c.parents = msmclk_parse_clk_src(dev, np, &rcg->c.num_parents); + if (IS_ERR(rcg->c.parents)) { + dt_err(np, "unable to read parents\n"); + return ERR_CAST(rcg->c.parents); + } + + rc = of_property_read_u32(np, "qcom,base-offset", &rcg->cmd_rcgr_reg); + if (rc) { + dt_err(np, "missing qcom,base-offset dt property\n"); + return ERR_PTR(rc); + } + + rc = rcg_parse_freq_tbl(dev, np, rcg); + if (rc) { + dt_err(np, "unable to read freq_tbl\n"); + return ERR_PTR(rc); + } + rcg->current_freq = &rcg_dummy_freq; + + if (of_device_is_compatible(np, "qcom,rcg-hid")) { + rcg->c.ops = &clk_ops_rcg; + rcg->set_rate = set_rate_hid; + } else if (of_device_is_compatible(np, "qcom,rcg-mn")) { + rcg->c.ops = &clk_ops_rcg_mnd; + rcg->set_rate = set_rate_mnd; + } else { + dt_err(np, "unexpected compatible string\n"); + return ERR_PTR(-EINVAL); + } + + return msmclk_generic_clk_init(dev, np, &rcg->c); +} +MSMCLK_PARSER(rcg_clk_dt_parser, "qcom,rcg-hid", 0); +MSMCLK_PARSER(rcg_clk_dt_parser, "qcom,rcg-mn", 1); + +static int parse_rec_parents(struct device *dev, + struct device_node *np, struct mux_clk *mux) +{ + int i, rc; + char *name = "qcom,recursive-parents"; + phandle p; + + mux->num_rec_parents = of_property_count_phandles(np, name); + if (mux->num_rec_parents <= 0) + return 0; + + mux->rec_parents = devm_kzalloc(dev, + sizeof(*mux->rec_parents) * mux->num_rec_parents, + GFP_KERNEL); + + if (!mux->rec_parents) { + dt_err(np, "memory alloc failure\n"); + return -ENOMEM; + } + + for (i = 0; i < mux->num_rec_parents; i++) { + rc = of_property_read_phandle_index(np, name, i, &p); + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return rc; + } + + mux->rec_parents[i] = msmclk_parse_phandle(dev, p); + if (IS_ERR(mux->rec_parents[i])) { + dt_prop_err(np, name, "hashtable lookup failure\n"); + return PTR_ERR(mux->rec_parents[i]); + } + } + + return 0; +} + +static void *mux_reg_clk_dt_parser(struct device *dev, struct device_node *np) +{ + struct mux_clk *mux; + struct msmclk_data *drv; + int rc; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->parents = msmclk_parse_clk_src(dev, np, &mux->num_parents); + if (IS_ERR(mux->parents)) + return mux->parents; + + mux->c.parents = mux->parents; + mux->c.num_parents = mux->num_parents; + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return drv; + mux->base = &drv->base; + + rc = parse_rec_parents(dev, np, mux); + if (rc) { + dt_err(np, "Incorrect qcom,recursive-parents dt property\n"); + return ERR_PTR(rc); + } + + rc = of_property_read_u32(np, "qcom,offset", &mux->offset); + if (rc) { + dt_err(np, "missing qcom,offset dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,mask", &mux->mask); + if (rc) { + dt_err(np, "missing qcom,mask dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,shift", &mux->shift); + if (rc) { + dt_err(np, "missing qcom,shift dt property\n"); + return ERR_PTR(-EINVAL); + } + + mux->c.ops = &clk_ops_gen_mux; + mux->ops = &mux_reg_ops; + + /* Optional Properties */ + of_property_read_u32(np, "qcom,en-offset", &mux->en_offset); + of_property_read_u32(np, "qcom,en-mask", &mux->en_mask); + + return msmclk_generic_clk_init(dev, np, &mux->c); +}; +MSMCLK_PARSER(mux_reg_clk_dt_parser, "qcom,mux-reg", 0); + +static void *measure_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct mux_clk *mux; + struct clk *c; + struct measure_clk_data *p; + struct clk_ops *clk_ops_measure_mux; + phandle cxo; + int rc; + + c = mux_reg_clk_dt_parser(dev, np); + if (IS_ERR(c)) + return c; + + mux = to_mux_clk(c); + + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + rc = of_property_read_phandle_index(np, "qcom,cxo", 0, &cxo); + if (rc) { + dt_err(np, "missing qcom,cxo\n"); + return ERR_PTR(-EINVAL); + } + p->cxo = msmclk_parse_phandle(dev, cxo); + if (IS_ERR_OR_NULL(p->cxo)) { + dt_prop_err(np, "qcom,cxo", "hashtable lookup failure\n"); + return p->cxo; + } + + rc = of_property_read_u32(np, "qcom,xo-div4-cbcr", &p->xo_div4_cbcr); + if (rc) { + dt_err(np, "missing qcom,xo-div4-cbcr dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,test-pad-config", &p->plltest_val); + if (rc) { + dt_err(np, "missing qcom,test-pad-config dt property\n"); + return ERR_PTR(-EINVAL); + } + + p->base = mux->base; + p->ctl_reg = mux->offset + 0x4; + p->status_reg = mux->offset + 0x8; + p->plltest_reg = mux->offset + 0xC; + mux->priv = p; + + clk_ops_measure_mux = devm_kzalloc(dev, sizeof(*clk_ops_measure_mux), + GFP_KERNEL); + if (!clk_ops_measure_mux) + return ERR_PTR(-ENOMEM); + + *clk_ops_measure_mux = clk_ops_gen_mux; + clk_ops_measure_mux->get_rate = measure_get_rate; + + mux->c.ops = clk_ops_measure_mux; + + /* Already did generic clk init */ + return &mux->c; +}; +MSMCLK_PARSER(measure_clk_dt_parser, "qcom,measure-mux", 0); + +static void *div_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct div_clk *div_clk; + struct msmclk_data *drv; + int rc; + + div_clk = devm_kzalloc(dev, sizeof(*div_clk), GFP_KERNEL); + if (!div_clk) + return ERR_PTR(-ENOMEM); + + rc = of_property_read_u32(np, "qcom,max-div", &div_clk->data.max_div); + if (rc) { + dt_err(np, "missing qcom,max-div\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,min-div", &div_clk->data.min_div); + if (rc) { + dt_err(np, "missing qcom,min-div\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,base-offset", &div_clk->offset); + if (rc) { + dt_err(np, "missing qcom,base-offset\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,mask", &div_clk->mask); + if (rc) { + dt_err(np, "missing qcom,mask\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,shift", &div_clk->shift); + if (rc) { + dt_err(np, "missing qcom,shift\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_bool(np, "qcom,slave-div")) + div_clk->c.ops = &clk_ops_slave_div; + else + div_clk->c.ops = &clk_ops_div; + div_clk->ops = &div_reg_ops; + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + div_clk->base = &drv->base; + + return msmclk_generic_clk_init(dev, np, &div_clk->c); +}; +MSMCLK_PARSER(div_clk_dt_parser, "qcom,div-clk", 0); + +static void *fixed_div_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct div_clk *div_clk; + int rc; + + div_clk = devm_kzalloc(dev, sizeof(*div_clk), GFP_KERNEL); + if (!div_clk) + return ERR_PTR(-ENOMEM); + + rc = of_property_read_u32(np, "qcom,div", &div_clk->data.div); + if (rc) { + dt_err(np, "missing qcom,div\n"); + return ERR_PTR(-EINVAL); + } + div_clk->data.min_div = div_clk->data.div; + div_clk->data.max_div = div_clk->data.div; + + if (of_property_read_bool(np, "qcom,slave-div")) + div_clk->c.ops = &clk_ops_slave_div; + else + div_clk->c.ops = &clk_ops_div; + div_clk->ops = &div_reg_ops; + + return msmclk_generic_clk_init(dev, np, &div_clk->c); +} +MSMCLK_PARSER(fixed_div_clk_dt_parser, "qcom,fixed-div-clk", 0); + +static void *reset_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct reset_clk *reset_clk; + struct msmclk_data *drv; + int rc; + + reset_clk = devm_kzalloc(dev, sizeof(*reset_clk), GFP_KERNEL); + if (!reset_clk) + return ERR_PTR(-ENOMEM); + + rc = of_property_read_u32(np, "qcom,base-offset", + &reset_clk->reset_reg); + if (rc) { + dt_err(np, "missing qcom,base-offset\n"); + return ERR_PTR(-EINVAL); + } + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + reset_clk->base = &drv->base; + + reset_clk->c.ops = &clk_ops_rst; + return msmclk_generic_clk_init(dev, np, &reset_clk->c); +}; +MSMCLK_PARSER(reset_clk_dt_parser, "qcom,reset-clk", 0); diff --git a/drivers/clk/msm/clock-pll.c b/drivers/clk/msm/clock-pll.c new file mode 100644 index 0000000000000000000000000000000000000000..26c04e5614447bd3b32adc0318879cb6f02aa3f2 --- /dev/null +++ b/drivers/clk/msm/clock-pll.c @@ -0,0 +1,1204 @@ +/* + * Copyright (c) 2012-2017, 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 +#include +#include +#include +#include +#include +#include +#include + +#include "clock.h" + +#define PLL_OUTCTRL BIT(0) +#define PLL_BYPASSNL BIT(1) +#define PLL_RESET_N BIT(2) +#define PLL_MODE_MASK BM(3, 0) + +#define PLL_EN_REG(x) (*(x)->base + (unsigned long) (x)->en_reg) +#define PLL_STATUS_REG(x) (*(x)->base + (unsigned long) (x)->status_reg) +#define PLL_ALT_STATUS_REG(x) (*(x)->base + (unsigned long) \ + (x)->alt_status_reg) +#define PLL_MODE_REG(x) (*(x)->base + (unsigned long) (x)->mode_reg) +#define PLL_L_REG(x) (*(x)->base + (unsigned long) (x)->l_reg) +#define PLL_M_REG(x) (*(x)->base + (unsigned long) (x)->m_reg) +#define PLL_N_REG(x) (*(x)->base + (unsigned long) (x)->n_reg) +#define PLL_CONFIG_REG(x) (*(x)->base + (unsigned long) (x)->config_reg) +#define PLL_ALPHA_REG(x) (*(x)->base + (unsigned long) (x)->alpha_reg) +#define PLL_CFG_ALT_REG(x) (*(x)->base + (unsigned long) \ + (x)->config_alt_reg) +#define PLL_CFG_CTL_REG(x) (*(x)->base + (unsigned long) \ + (x)->config_ctl_reg) +#define PLL_CFG_CTL_HI_REG(x) (*(x)->base + (unsigned long) \ + (x)->config_ctl_hi_reg) +#define PLL_TEST_CTL_LO_REG(x) (*(x)->base + (unsigned long) \ + (x)->test_ctl_lo_reg) +#define PLL_TEST_CTL_HI_REG(x) (*(x)->base + (unsigned long) \ + (x)->test_ctl_hi_reg) +static DEFINE_SPINLOCK(pll_reg_lock); + +#define ENABLE_WAIT_MAX_LOOPS 200 +#define PLL_LOCKED_BIT BIT(16) + +#define SPM_FORCE_EVENT 0x4 + +static int pll_vote_clk_enable(struct clk *c) +{ + u32 ena, count; + unsigned long flags; + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + spin_lock_irqsave(&pll_reg_lock, flags); + ena = readl_relaxed(PLL_EN_REG(pllv)); + ena |= pllv->en_mask; + writel_relaxed(ena, PLL_EN_REG(pllv)); + spin_unlock_irqrestore(&pll_reg_lock, flags); + + /* + * Use a memory barrier since some PLL status registers are + * not within the same 1K segment as the voting registers. + */ + mb(); + + /* Wait for pll to enable. */ + for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { + if (readl_relaxed(PLL_STATUS_REG(pllv)) & pllv->status_mask) + return 0; + udelay(1); + } + + WARN("PLL %s didn't enable after voting for it!\n", c->dbg_name); + + return -ETIMEDOUT; +} + +static void pll_vote_clk_disable(struct clk *c) +{ + u32 ena; + unsigned long flags; + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + spin_lock_irqsave(&pll_reg_lock, flags); + ena = readl_relaxed(PLL_EN_REG(pllv)); + ena &= ~(pllv->en_mask); + writel_relaxed(ena, PLL_EN_REG(pllv)); + spin_unlock_irqrestore(&pll_reg_lock, flags); +} + +static int pll_vote_clk_is_enabled(struct clk *c) +{ + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + return !!(readl_relaxed(PLL_STATUS_REG(pllv)) & pllv->status_mask); +} + +static enum handoff pll_vote_clk_handoff(struct clk *c) +{ + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + if (readl_relaxed(PLL_EN_REG(pllv)) & pllv->en_mask) + return HANDOFF_ENABLED_CLK; + + return HANDOFF_DISABLED_CLK; +} + +static void __iomem *pll_vote_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + static struct clk_register_data data1[] = { + {"APPS_VOTE", 0x0}, + }; + + if (n) + return ERR_PTR(-EINVAL); + + *regs = data1; + *size = ARRAY_SIZE(data1); + return PLL_EN_REG(pllv); +} + +const struct clk_ops clk_ops_pll_vote = { + .enable = pll_vote_clk_enable, + .disable = pll_vote_clk_disable, + .is_enabled = pll_vote_clk_is_enabled, + .handoff = pll_vote_clk_handoff, + .list_registers = pll_vote_clk_list_registers, +}; + +/* + * spm_event() -- Set/Clear SPM events + * PLL off sequence -- enable (1) + * Set L2_SPM_FORCE_EVENT_EN[bit] register to 1 + * Set L2_SPM_FORCE_EVENT[bit] register to 1 + * PLL on sequence -- enable (0) + * Clear L2_SPM_FORCE_EVENT[bit] register to 0 + * Clear L2_SPM_FORCE_EVENT_EN[bit] register to 0 + */ +static void spm_event(void __iomem *base, u32 offset, u32 bit, + bool enable) +{ + uint32_t val; + + if (!base) + return; + + if (enable) { + /* L2_SPM_FORCE_EVENT_EN */ + val = readl_relaxed(base + offset); + val |= BIT(bit); + writel_relaxed(val, (base + offset)); + /* Ensure that the write above goes through. */ + mb(); + + /* L2_SPM_FORCE_EVENT */ + val = readl_relaxed(base + offset + SPM_FORCE_EVENT); + val |= BIT(bit); + writel_relaxed(val, (base + offset + SPM_FORCE_EVENT)); + /* Ensure that the write above goes through. */ + mb(); + } else { + /* L2_SPM_FORCE_EVENT */ + val = readl_relaxed(base + offset + SPM_FORCE_EVENT); + val &= ~BIT(bit); + writel_relaxed(val, (base + offset + SPM_FORCE_EVENT)); + /* Ensure that the write above goes through. */ + mb(); + + /* L2_SPM_FORCE_EVENT_EN */ + val = readl_relaxed(base + offset); + val &= ~BIT(bit); + writel_relaxed(val, (base + offset)); + /* Ensure that the write above goes through. */ + mb(); + } +} + +static void __pll_config_reg(void __iomem *pll_config, struct pll_freq_tbl *f, + struct pll_config_masks *masks) +{ + u32 regval; + + regval = readl_relaxed(pll_config); + + /* Enable the MN counter if used */ + if (f->m_val) + regval |= masks->mn_en_mask; + + /* Set pre-divider and post-divider values */ + regval &= ~masks->pre_div_mask; + regval |= f->pre_div_val; + regval &= ~masks->post_div_mask; + regval |= f->post_div_val; + + /* Select VCO setting */ + regval &= ~masks->vco_mask; + regval |= f->vco_val; + + /* Enable main output if it has not been enabled */ + if (masks->main_output_mask && !(regval & masks->main_output_mask)) + regval |= masks->main_output_mask; + + writel_relaxed(regval, pll_config); +} + +static int sr2_pll_clk_enable(struct clk *c) +{ + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + int ret = 0, count; + u32 mode = readl_relaxed(PLL_MODE_REG(pll)); + u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; + + spin_lock_irqsave(&pll_reg_lock, flags); + + spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, + pll->spm_ctrl.event_bit, false); + + /* Disable PLL bypass mode. */ + mode |= PLL_BYPASSNL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + mb(); + udelay(10); + + /* De-assert active-low PLL reset. */ + mode |= PLL_RESET_N; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Wait for pll to lock. */ + for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { + if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) + break; + udelay(1); + } + + if (!(readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) + pr_err("PLL %s didn't lock after enabling it!\n", c->dbg_name); + + /* Enable PLL output. */ + mode |= PLL_OUTCTRL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Ensure that the write above goes through before returning. */ + mb(); + + spin_unlock_irqrestore(&pll_reg_lock, flags); + return ret; +} + +void __variable_rate_pll_init(struct clk *c) +{ + struct pll_clk *pll = to_pll_clk(c); + u32 regval; + + regval = readl_relaxed(PLL_CONFIG_REG(pll)); + + if (pll->masks.post_div_mask) { + regval &= ~pll->masks.post_div_mask; + regval |= pll->vals.post_div_masked; + } + + if (pll->masks.pre_div_mask) { + regval &= ~pll->masks.pre_div_mask; + regval |= pll->vals.pre_div_masked; + } + + if (pll->masks.main_output_mask) + regval |= pll->masks.main_output_mask; + + if (pll->masks.early_output_mask) + regval |= pll->masks.early_output_mask; + + if (pll->vals.enable_mn) + regval |= pll->masks.mn_en_mask; + else + regval &= ~pll->masks.mn_en_mask; + + writel_relaxed(regval, PLL_CONFIG_REG(pll)); + + regval = readl_relaxed(PLL_MODE_REG(pll)); + if (pll->masks.apc_pdn_mask) + regval &= ~pll->masks.apc_pdn_mask; + writel_relaxed(regval, PLL_MODE_REG(pll)); + + writel_relaxed(pll->vals.alpha_val, PLL_ALPHA_REG(pll)); + writel_relaxed(pll->vals.config_ctl_val, PLL_CFG_CTL_REG(pll)); + if (pll->vals.config_ctl_hi_val) + writel_relaxed(pll->vals.config_ctl_hi_val, + PLL_CFG_CTL_HI_REG(pll)); + if (pll->init_test_ctl) { + writel_relaxed(pll->vals.test_ctl_lo_val, + PLL_TEST_CTL_LO_REG(pll)); + writel_relaxed(pll->vals.test_ctl_hi_val, + PLL_TEST_CTL_HI_REG(pll)); + } + + pll->inited = true; +} + +static int variable_rate_pll_clk_enable(struct clk *c) +{ + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + int ret = 0, count; + u32 mode, testlo; + u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; + u32 mode_lock; + u64 time; + bool early_lock = false; + + spin_lock_irqsave(&pll_reg_lock, flags); + + if (unlikely(!to_pll_clk(c)->inited)) + __variable_rate_pll_init(c); + + mode = readl_relaxed(PLL_MODE_REG(pll)); + + /* Set test control bits as required by HW doc */ + if (pll->test_ctl_lo_reg && pll->vals.test_ctl_lo_val && + pll->pgm_test_ctl_enable) + writel_relaxed(pll->vals.test_ctl_lo_val, + PLL_TEST_CTL_LO_REG(pll)); + + if (!pll->test_ctl_dbg) { + /* Enable test_ctl debug */ + mode |= BIT(3); + writel_relaxed(mode, PLL_MODE_REG(pll)); + + testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + testlo &= ~BM(7, 6); + testlo |= 0xC0; + writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); + /* Wait for the write to complete */ + mb(); + } + + /* Disable PLL bypass mode. */ + mode |= PLL_BYPASSNL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Use 10us to be sure. + */ + mb(); + udelay(10); + + /* De-assert active-low PLL reset. */ + mode |= PLL_RESET_N; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* + * 5us delay mandated by HPG. However, put in a 200us delay here. + * This is to address possible locking issues with the PLL exhibit + * early "transient" locks about 16us from this point. With this + * higher delay, we avoid running into those transients. + */ + mb(); + udelay(200); + + /* Clear test control bits */ + if (pll->test_ctl_lo_reg && pll->vals.test_ctl_lo_val && + pll->pgm_test_ctl_enable) + writel_relaxed(0x0, PLL_TEST_CTL_LO_REG(pll)); + + + time = sched_clock(); + /* Wait for pll to lock. */ + for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { + if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) { + udelay(1); + /* + * Check again to be sure. This is to avoid + * breaking too early if there is a "transient" + * lock. + */ + if ((readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) + break; + early_lock = true; + } + udelay(1); + } + time = sched_clock() - time; + + mode_lock = readl_relaxed(PLL_STATUS_REG(pll)); + + if (!(mode_lock & lockmask)) { + pr_err("PLL lock bit detection total wait time: %lld ns", time); + pr_err("PLL %s didn't lock after enabling for L value 0x%x!\n", + c->dbg_name, readl_relaxed(PLL_L_REG(pll))); + pr_err("mode register is 0x%x\n", + readl_relaxed(PLL_STATUS_REG(pll))); + pr_err("user control register is 0x%x\n", + readl_relaxed(PLL_CONFIG_REG(pll))); + pr_err("config control register is 0x%x\n", + readl_relaxed(PLL_CFG_CTL_REG(pll))); + pr_err("test control high register is 0x%x\n", + readl_relaxed(PLL_TEST_CTL_HI_REG(pll))); + pr_err("test control low register is 0x%x\n", + readl_relaxed(PLL_TEST_CTL_LO_REG(pll))); + pr_err("early lock? %s\n", early_lock ? "yes" : "no"); + + testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + testlo &= ~BM(7, 6); + writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); + /* Wait for the write to complete */ + mb(); + + pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", + readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), + readl_relaxed(PLL_ALT_STATUS_REG(pll))); + + testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + testlo &= ~BM(7, 6); + testlo |= 0x40; + writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); + /* Wait for the write to complete */ + mb(); + pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", + readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), + readl_relaxed(PLL_ALT_STATUS_REG(pll))); + + testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + testlo &= ~BM(7, 6); + testlo |= 0x80; + writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); + /* Wait for the write to complete */ + mb(); + + pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", + readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), + readl_relaxed(PLL_ALT_STATUS_REG(pll))); + + testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + testlo &= ~BM(7, 6); + testlo |= 0xC0; + writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); + /* Wait for the write to complete */ + mb(); + + pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", + readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), + readl_relaxed(PLL_ALT_STATUS_REG(pll))); + panic("failed to lock %s PLL\n", c->dbg_name); + } + + /* Enable PLL output. */ + mode |= PLL_OUTCTRL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Ensure that the write above goes through before returning. */ + mb(); + + spin_unlock_irqrestore(&pll_reg_lock, flags); + + return ret; +} + +static void variable_rate_pll_clk_disable_hwfsm(struct clk *c) +{ + struct pll_clk *pll = to_pll_clk(c); + u32 regval; + + /* Set test control bit to stay-in-CFA if necessary */ + if (pll->test_ctl_lo_reg && pll->pgm_test_ctl_enable) { + regval = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + writel_relaxed(regval | BIT(16), + PLL_TEST_CTL_LO_REG(pll)); + } + + /* 8 reference clock cycle delay mandated by the HPG */ + udelay(1); +} + +static int variable_rate_pll_clk_enable_hwfsm(struct clk *c) +{ + struct pll_clk *pll = to_pll_clk(c); + int count; + u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; + unsigned long flags; + u32 regval; + + spin_lock_irqsave(&pll_reg_lock, flags); + + /* Clear test control bit if necessary */ + if (pll->test_ctl_lo_reg && pll->pgm_test_ctl_enable) { + regval = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); + regval &= ~BIT(16); + writel_relaxed(regval, PLL_TEST_CTL_LO_REG(pll)); + } + + /* Wait for 50us explicitly to avoid transient locks */ + udelay(50); + + for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { + if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) + break; + udelay(1); + } + + if (!(readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) + pr_err("PLL %s didn't lock after enabling it!\n", c->dbg_name); + + spin_unlock_irqrestore(&pll_reg_lock, flags); + + return 0; +} + +static void __pll_clk_enable_reg(void __iomem *mode_reg) +{ + u32 mode = readl_relaxed(mode_reg); + /* Disable PLL bypass mode. */ + mode |= PLL_BYPASSNL; + writel_relaxed(mode, mode_reg); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + mb(); + udelay(10); + + /* De-assert active-low PLL reset. */ + mode |= PLL_RESET_N; + writel_relaxed(mode, mode_reg); + + /* Wait until PLL is locked. */ + mb(); + udelay(50); + + /* Enable PLL output. */ + mode |= PLL_OUTCTRL; + writel_relaxed(mode, mode_reg); + + /* Ensure that the write above goes through before returning. */ + mb(); +} + +static int local_pll_clk_enable(struct clk *c) +{ + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + + spin_lock_irqsave(&pll_reg_lock, flags); + __pll_clk_enable_reg(PLL_MODE_REG(pll)); + spin_unlock_irqrestore(&pll_reg_lock, flags); + + return 0; +} + +static void __pll_clk_disable_reg(void __iomem *mode_reg) +{ + u32 mode = readl_relaxed(mode_reg); + + mode &= ~PLL_MODE_MASK; + writel_relaxed(mode, mode_reg); +} + +static void local_pll_clk_disable(struct clk *c) +{ + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + + /* + * Disable the PLL output, disable test mode, enable + * the bypass mode, and assert the reset. + */ + spin_lock_irqsave(&pll_reg_lock, flags); + spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, + pll->spm_ctrl.event_bit, true); + __pll_clk_disable_reg(PLL_MODE_REG(pll)); + spin_unlock_irqrestore(&pll_reg_lock, flags); +} + +static enum handoff local_pll_clk_handoff(struct clk *c) +{ + struct pll_clk *pll = to_pll_clk(c); + u32 mode = readl_relaxed(PLL_MODE_REG(pll)); + u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL; + unsigned long parent_rate; + u32 lval, mval, nval, userval; + + if ((mode & mask) != mask) + return HANDOFF_DISABLED_CLK; + + /* Assume bootloaders configure PLL to c->rate */ + if (c->rate) + return HANDOFF_ENABLED_CLK; + + parent_rate = clk_get_rate(c->parent); + lval = readl_relaxed(PLL_L_REG(pll)); + mval = readl_relaxed(PLL_M_REG(pll)); + nval = readl_relaxed(PLL_N_REG(pll)); + userval = readl_relaxed(PLL_CONFIG_REG(pll)); + + c->rate = parent_rate * lval; + + if (pll->masks.mn_en_mask && userval) { + if (!nval) + nval = 1; + c->rate += (parent_rate * mval) / nval; + } + + return HANDOFF_ENABLED_CLK; +} + +static long local_pll_clk_round_rate(struct clk *c, unsigned long rate) +{ + struct pll_freq_tbl *nf; + struct pll_clk *pll = to_pll_clk(c); + + if (!pll->freq_tbl) + return -EINVAL; + + for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END; nf++) + if (nf->freq_hz >= rate) + return nf->freq_hz; + + nf--; + return nf->freq_hz; +} + +static int local_pll_clk_set_rate(struct clk *c, unsigned long rate) +{ + struct pll_freq_tbl *nf; + struct pll_clk *pll = to_pll_clk(c); + unsigned long flags; + + for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END + && nf->freq_hz != rate; nf++) + ; + + if (nf->freq_hz == PLL_FREQ_END) + return -EINVAL; + + /* + * Ensure PLL is off before changing rate. For optimization reasons, + * assume no downstream clock is using actively using it. + */ + spin_lock_irqsave(&c->lock, flags); + if (c->count) + c->ops->disable(c); + + writel_relaxed(nf->l_val, PLL_L_REG(pll)); + writel_relaxed(nf->m_val, PLL_M_REG(pll)); + writel_relaxed(nf->n_val, PLL_N_REG(pll)); + + __pll_config_reg(PLL_CONFIG_REG(pll), nf, &pll->masks); + + if (c->count) + c->ops->enable(c); + + spin_unlock_irqrestore(&c->lock, flags); + return 0; +} + +static enum handoff variable_rate_pll_handoff(struct clk *c) +{ + struct pll_clk *pll = to_pll_clk(c); + u32 mode = readl_relaxed(PLL_MODE_REG(pll)); + u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL; + u32 lval; + + pll->src_rate = clk_get_rate(c->parent); + + lval = readl_relaxed(PLL_L_REG(pll)); + if (!lval) + return HANDOFF_DISABLED_CLK; + + c->rate = pll->src_rate * lval; + + if (c->rate > pll->max_rate || c->rate < pll->min_rate) { + WARN(1, "%s: Out of spec PLL", c->dbg_name); + return HANDOFF_DISABLED_CLK; + } + + if ((mode & mask) != mask) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +static long variable_rate_pll_round_rate(struct clk *c, unsigned long rate) +{ + struct pll_clk *pll = to_pll_clk(c); + + if (!pll->src_rate) + return 0; + + if (pll->no_prepared_reconfig && c->prepare_count && c->rate != rate) + return -EINVAL; + + if (rate < pll->min_rate) + rate = pll->min_rate; + if (rate > pll->max_rate) + rate = pll->max_rate; + + return min(pll->max_rate, + DIV_ROUND_UP(rate, pll->src_rate) * pll->src_rate); +} + +/* + * For optimization reasons, assumes no downstream clocks are actively using + * it. + */ +static int variable_rate_pll_set_rate(struct clk *c, unsigned long rate) +{ + struct pll_clk *pll = to_pll_clk(c); + unsigned long flags; + u32 l_val; + + if (rate != variable_rate_pll_round_rate(c, rate)) + return -EINVAL; + + l_val = rate / pll->src_rate; + + spin_lock_irqsave(&c->lock, flags); + + if (c->count && c->ops->disable) + c->ops->disable(c); + + writel_relaxed(l_val, PLL_L_REG(pll)); + + if (c->count && c->ops->enable) + c->ops->enable(c); + + spin_unlock_irqrestore(&c->lock, flags); + + return 0; +} + +int sr_pll_clk_enable(struct clk *c) +{ + u32 mode; + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + + spin_lock_irqsave(&pll_reg_lock, flags); + mode = readl_relaxed(PLL_MODE_REG(pll)); + /* De-assert active-low PLL reset. */ + mode |= PLL_RESET_N; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + mb(); + udelay(10); + + /* Disable PLL bypass mode. */ + mode |= PLL_BYPASSNL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Wait until PLL is locked. */ + mb(); + udelay(60); + + /* Enable PLL output. */ + mode |= PLL_OUTCTRL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Ensure that the write above goes through before returning. */ + mb(); + + spin_unlock_irqrestore(&pll_reg_lock, flags); + + return 0; +} + +int sr_hpm_lp_pll_clk_enable(struct clk *c) +{ + unsigned long flags; + struct pll_clk *pll = to_pll_clk(c); + u32 count, mode; + int ret = 0; + + spin_lock_irqsave(&pll_reg_lock, flags); + + /* Disable PLL bypass mode and de-assert reset. */ + mode = PLL_BYPASSNL | PLL_RESET_N; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Wait for pll to lock. */ + for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { + if (readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT) + break; + udelay(1); + } + + if (!(readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)) { + WARN("PLL %s didn't lock after enabling it!\n", c->dbg_name); + ret = -ETIMEDOUT; + goto out; + } + + /* Enable PLL output. */ + mode |= PLL_OUTCTRL; + writel_relaxed(mode, PLL_MODE_REG(pll)); + + /* Ensure the write above goes through before returning. */ + mb(); + +out: + spin_unlock_irqrestore(&pll_reg_lock, flags); + return ret; +} + + +static void __iomem *variable_rate_pll_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + struct pll_clk *pll = to_pll_clk(c); + static struct clk_register_data data[] = { + {"MODE", 0x0}, + {"L", 0x4}, + {"ALPHA", 0x8}, + {"USER_CTL", 0x10}, + {"CONFIG_CTL", 0x14}, + {"STATUS", 0x1C}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return PLL_MODE_REG(pll); +} + +static void __iomem *local_pll_clk_list_registers(struct clk *c, int n, + struct clk_register_data **regs, u32 *size) +{ + /* Not compatible with 8960 & friends */ + struct pll_clk *pll = to_pll_clk(c); + static struct clk_register_data data[] = { + {"MODE", 0x0}, + {"L", 0x4}, + {"M", 0x8}, + {"N", 0xC}, + {"USER", 0x10}, + {"CONFIG", 0x14}, + {"STATUS", 0x1C}, + }; + if (n) + return ERR_PTR(-EINVAL); + + *regs = data; + *size = ARRAY_SIZE(data); + return PLL_MODE_REG(pll); +} + + +const struct clk_ops clk_ops_local_pll = { + .enable = local_pll_clk_enable, + .disable = local_pll_clk_disable, + .set_rate = local_pll_clk_set_rate, + .handoff = local_pll_clk_handoff, + .list_registers = local_pll_clk_list_registers, +}; + +const struct clk_ops clk_ops_sr2_pll = { + .enable = sr2_pll_clk_enable, + .disable = local_pll_clk_disable, + .set_rate = local_pll_clk_set_rate, + .round_rate = local_pll_clk_round_rate, + .handoff = local_pll_clk_handoff, + .list_registers = local_pll_clk_list_registers, +}; + +const struct clk_ops clk_ops_variable_rate_pll_hwfsm = { + .enable = variable_rate_pll_clk_enable_hwfsm, + .disable = variable_rate_pll_clk_disable_hwfsm, + .set_rate = variable_rate_pll_set_rate, + .round_rate = variable_rate_pll_round_rate, + .handoff = variable_rate_pll_handoff, +}; + +const struct clk_ops clk_ops_variable_rate_pll = { + .enable = variable_rate_pll_clk_enable, + .disable = local_pll_clk_disable, + .set_rate = variable_rate_pll_set_rate, + .round_rate = variable_rate_pll_round_rate, + .handoff = variable_rate_pll_handoff, + .list_registers = variable_rate_pll_list_registers, +}; + +static DEFINE_SPINLOCK(soft_vote_lock); + +static int pll_acpu_vote_clk_enable(struct clk *c) +{ + int ret = 0; + unsigned long flags; + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + spin_lock_irqsave(&soft_vote_lock, flags); + + if (!*pllv->soft_vote) + ret = pll_vote_clk_enable(c); + if (ret == 0) + *pllv->soft_vote |= (pllv->soft_vote_mask); + + spin_unlock_irqrestore(&soft_vote_lock, flags); + return ret; +} + +static void pll_acpu_vote_clk_disable(struct clk *c) +{ + unsigned long flags; + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + spin_lock_irqsave(&soft_vote_lock, flags); + + *pllv->soft_vote &= ~(pllv->soft_vote_mask); + if (!*pllv->soft_vote) + pll_vote_clk_disable(c); + + spin_unlock_irqrestore(&soft_vote_lock, flags); +} + +static enum handoff pll_acpu_vote_clk_handoff(struct clk *c) +{ + if (pll_vote_clk_handoff(c) == HANDOFF_DISABLED_CLK) + return HANDOFF_DISABLED_CLK; + + if (pll_acpu_vote_clk_enable(c)) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +const struct clk_ops clk_ops_pll_acpu_vote = { + .enable = pll_acpu_vote_clk_enable, + .disable = pll_acpu_vote_clk_disable, + .is_enabled = pll_vote_clk_is_enabled, + .handoff = pll_acpu_vote_clk_handoff, + .list_registers = pll_vote_clk_list_registers, +}; + + +static int pll_sleep_clk_enable(struct clk *c) +{ + u32 ena; + unsigned long flags; + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + spin_lock_irqsave(&pll_reg_lock, flags); + ena = readl_relaxed(PLL_EN_REG(pllv)); + ena &= ~(pllv->en_mask); + writel_relaxed(ena, PLL_EN_REG(pllv)); + spin_unlock_irqrestore(&pll_reg_lock, flags); + return 0; +} + +static void pll_sleep_clk_disable(struct clk *c) +{ + u32 ena; + unsigned long flags; + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + spin_lock_irqsave(&pll_reg_lock, flags); + ena = readl_relaxed(PLL_EN_REG(pllv)); + ena |= pllv->en_mask; + writel_relaxed(ena, PLL_EN_REG(pllv)); + spin_unlock_irqrestore(&pll_reg_lock, flags); +} + +static enum handoff pll_sleep_clk_handoff(struct clk *c) +{ + struct pll_vote_clk *pllv = to_pll_vote_clk(c); + + if (!(readl_relaxed(PLL_EN_REG(pllv)) & pllv->en_mask)) + return HANDOFF_ENABLED_CLK; + + return HANDOFF_DISABLED_CLK; +} + +/* + * This .ops is meant to be used by gpll0_sleep_clk_src. The aim is to utilise + * the h/w feature of sleep enable bit to denote if the PLL can be turned OFF + * once APPS goes to PC. gpll0_sleep_clk_src will be enabled only if there is a + * peripheral client using it and disabled if there is none. The current + * implementation of enable .ops clears the h/w bit of sleep enable while the + * disable .ops asserts it. + */ + +const struct clk_ops clk_ops_pll_sleep_vote = { + .enable = pll_sleep_clk_enable, + .disable = pll_sleep_clk_disable, + .handoff = pll_sleep_clk_handoff, + .list_registers = pll_vote_clk_list_registers, +}; + +static void __set_fsm_mode(void __iomem *mode_reg, + u32 bias_count, u32 lock_count) +{ + u32 regval = readl_relaxed(mode_reg); + + /* De-assert reset to FSM */ + regval &= ~BIT(21); + writel_relaxed(regval, mode_reg); + + /* Program bias count */ + regval &= ~BM(19, 14); + regval |= BVAL(19, 14, bias_count); + writel_relaxed(regval, mode_reg); + + /* Program lock count */ + regval &= ~BM(13, 8); + regval |= BVAL(13, 8, lock_count); + writel_relaxed(regval, mode_reg); + + /* Enable PLL FSM voting */ + regval |= BIT(20); + writel_relaxed(regval, mode_reg); +} + +static void __configure_alt_config(struct pll_alt_config config, + struct pll_config_regs *regs) +{ + u32 regval; + + regval = readl_relaxed(PLL_CFG_ALT_REG(regs)); + + if (config.mask) { + regval &= ~config.mask; + regval |= config.val; + } + + writel_relaxed(regval, PLL_CFG_ALT_REG(regs)); +} + +void __configure_pll(struct pll_config *config, + struct pll_config_regs *regs, u32 ena_fsm_mode) +{ + u32 regval; + + writel_relaxed(config->l, PLL_L_REG(regs)); + writel_relaxed(config->m, PLL_M_REG(regs)); + writel_relaxed(config->n, PLL_N_REG(regs)); + + regval = readl_relaxed(PLL_CONFIG_REG(regs)); + + /* Enable the MN accumulator */ + if (config->mn_ena_mask) { + regval &= ~config->mn_ena_mask; + regval |= config->mn_ena_val; + } + + /* Enable the main output */ + if (config->main_output_mask) { + regval &= ~config->main_output_mask; + regval |= config->main_output_val; + } + + /* Enable the aux output */ + if (config->aux_output_mask) { + regval &= ~config->aux_output_mask; + regval |= config->aux_output_val; + } + + /* Set pre-divider and post-divider values */ + regval &= ~config->pre_div_mask; + regval |= config->pre_div_val; + regval &= ~config->post_div_mask; + regval |= config->post_div_val; + + /* Select VCO setting */ + regval &= ~config->vco_mask; + regval |= config->vco_val; + + if (config->add_factor_mask) { + regval &= ~config->add_factor_mask; + regval |= config->add_factor_val; + } + + writel_relaxed(regval, PLL_CONFIG_REG(regs)); + + if (regs->config_alt_reg) + __configure_alt_config(config->alt_cfg, regs); + + if (regs->config_ctl_reg) + writel_relaxed(config->cfg_ctl_val, PLL_CFG_CTL_REG(regs)); +} + +void configure_sr_pll(struct pll_config *config, + struct pll_config_regs *regs, u32 ena_fsm_mode) +{ + __configure_pll(config, regs, ena_fsm_mode); + if (ena_fsm_mode) + __set_fsm_mode(PLL_MODE_REG(regs), 0x1, 0x8); +} + +void configure_sr_hpm_lp_pll(struct pll_config *config, + struct pll_config_regs *regs, u32 ena_fsm_mode) +{ + __configure_pll(config, regs, ena_fsm_mode); + if (ena_fsm_mode) + __set_fsm_mode(PLL_MODE_REG(regs), 0x1, 0x0); +} + +static void *votable_pll_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct pll_vote_clk *v, *peer; + struct clk *c; + u32 val, rc; + phandle p; + struct msmclk_data *drv; + + v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); + if (!v) + return ERR_PTR(-ENOMEM); + + drv = msmclk_parse_phandle(dev, np->parent->phandle); + if (IS_ERR_OR_NULL(drv)) + return ERR_CAST(drv); + v->base = &drv->base; + + rc = of_property_read_u32(np, "qcom,en-offset", (u32 *)&v->en_reg); + if (rc) { + dt_err(np, "missing qcom,en-offset dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,en-bit", &val); + if (rc) { + dt_err(np, "missing qcom,en-bit dt property\n"); + return ERR_PTR(-EINVAL); + } + v->en_mask = BIT(val); + + rc = of_property_read_u32(np, "qcom,status-offset", + (u32 *)&v->status_reg); + if (rc) { + dt_err(np, "missing qcom,status-offset dt property\n"); + return ERR_PTR(-EINVAL); + } + + rc = of_property_read_u32(np, "qcom,status-bit", &val); + if (rc) { + dt_err(np, "missing qcom,status-bit dt property\n"); + return ERR_PTR(-EINVAL); + } + v->status_mask = BIT(val); + + rc = of_property_read_u32(np, "qcom,pll-config-rate", &val); + if (rc) { + dt_err(np, "missing qcom,pll-config-rate dt property\n"); + return ERR_PTR(-EINVAL); + } + v->c.rate = val; + + if (of_device_is_compatible(np, "qcom,active-only-pll")) + v->soft_vote_mask = PLL_SOFT_VOTE_ACPU; + else if (of_device_is_compatible(np, "qcom,sleep-active-pll")) + v->soft_vote_mask = PLL_SOFT_VOTE_PRIMARY; + + if (of_device_is_compatible(np, "qcom,votable-pll")) { + v->c.ops = &clk_ops_pll_vote; + return msmclk_generic_clk_init(dev, np, &v->c); + } + + rc = of_property_read_phandle_index(np, "qcom,peer", 0, &p); + if (rc) { + dt_err(np, "missing qcom,peer dt property\n"); + return ERR_PTR(-EINVAL); + } + + c = msmclk_lookup_phandle(dev, p); + if (!IS_ERR_OR_NULL(c)) { + v->soft_vote = devm_kzalloc(dev, sizeof(*v->soft_vote), + GFP_KERNEL); + if (!v->soft_vote) + return ERR_PTR(-ENOMEM); + + peer = to_pll_vote_clk(c); + peer->soft_vote = v->soft_vote; + } + + v->c.ops = &clk_ops_pll_acpu_vote; + return msmclk_generic_clk_init(dev, np, &v->c); +} +MSMCLK_PARSER(votable_pll_clk_dt_parser, "qcom,active-only-pll", 0); +MSMCLK_PARSER(votable_pll_clk_dt_parser, "qcom,sleep-active-pll", 1); +MSMCLK_PARSER(votable_pll_clk_dt_parser, "qcom,votable-pll", 2); diff --git a/drivers/clk/msm/clock-rcgwr.c b/drivers/clk/msm/clock-rcgwr.c new file mode 100644 index 0000000000000000000000000000000000000000..75f8e042cd8affdb09ab09f22c528ba4fa0282fb --- /dev/null +++ b/drivers/clk/msm/clock-rcgwr.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2015, 2017 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CMD_RCGR_REG 0x0 +#define CMD_UPDATE_EN BIT(0) +/* Async_clk_en */ +#define CMD_ROOT_EN BIT(1) + +struct rcgwr { + void __iomem *base; + void __iomem *rcg_base; + int *dfs_sid_offset; + int *dfs_sid_value; + int dfs_sid_len; + int *link_sid_offset; + int *link_sid_value; + int link_sid_len; + int *lmh_sid_offset; + int *lmh_sid_value; + int lmh_sid_len; + bool inited; +}; + +static struct rcgwr **rcgwr; +static struct platform_device *cpu_clock_dev; +static u32 num_clusters; + +#define DFS_SID_1_2 0x10 +#define DFS_SID_3_4 0x14 +#define DFS_SID_5_6 0x18 +#define DFS_SID_7_8 0x1C +#define DFS_SID_9_10 0x20 +#define DFS_SID_11_12 0x24 +#define DFS_SID_13_14 0x28 +#define DFS_SID_15 0x2C +#define LMH_SID_1_2 0x30 +#define LMH_SID_3_4 0x34 +#define LMH_SID_5 0x38 +#define DCVS_CFG_CTL 0x50 +#define LMH_CFG_CTL 0x54 +#define RC_CFG_CTL 0x58 +#define RC_CFG_DBG 0x5C +#define RC_CFG_UPDATE 0x60 + +#define RC_CFG_UPDATE_EN_BIT 8 +#define RC_CFG_ACK_BIT 16 + +#define UPDATE_CHECK_MAX_LOOPS 500 + +#define DFS_SID_START 0xE +#define LMH_SID_START 0x6 +#define DCVS_CONFIG 0x2 +#define LINK_SID 0x3 + +/* Sequence for enable */ +static int ramp_en[] = { 0x800, 0xC00, 0x400}; + +static int check_rcg_config(void __iomem *base) +{ + u32 cmd_rcgr_regval, count; + + cmd_rcgr_regval = readl_relaxed(base + CMD_RCGR_REG); + cmd_rcgr_regval |= CMD_ROOT_EN; + writel_relaxed(cmd_rcgr_regval, (base + CMD_RCGR_REG)); + + for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) { + cmd_rcgr_regval = readl_relaxed(base + CMD_RCGR_REG); + cmd_rcgr_regval &= CMD_UPDATE_EN; + if (!(cmd_rcgr_regval)) { + pr_debug("cmd_rcgr state on update bit cleared 0x%x, cmd 0x%x\n", + readl_relaxed(base + CMD_RCGR_REG), + cmd_rcgr_regval); + return 0; + } + udelay(1); + } + + WARN_ON(count == 0); + + return -EINVAL; +} + +static int rc_config_update(void __iomem *base, u32 rc_value, u32 rc_ack_bit) +{ + u32 count, ret = 0, regval; + + regval = readl_relaxed(base + RC_CFG_UPDATE); + regval |= rc_value; + writel_relaxed(regval, base + RC_CFG_UPDATE); + regval |= BIT(RC_CFG_UPDATE_EN_BIT); + writel_relaxed(regval, base + RC_CFG_UPDATE); + + /* Poll for update ack */ + for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) { + regval = readl_relaxed((base + RC_CFG_UPDATE)) + >> RC_CFG_ACK_BIT; + if (regval == BIT(rc_ack_bit)) { + ret = 0; + break; + } + udelay(1); + } + WARN_ON(count == 0); + + /* Clear RC_CFG_UPDATE_EN */ + writel_relaxed(0 << RC_CFG_UPDATE_EN_BIT, (base + RC_CFG_UPDATE)); + /* Poll for update ack */ + for (count = UPDATE_CHECK_MAX_LOOPS; count > 0; count--) { + regval = readl_relaxed((base + RC_CFG_UPDATE)) + >> RC_CFG_ACK_BIT; + if (!regval) + return ret; + udelay(1); + } + WARN_ON(count == 0); + + return -EINVAL; +} + + +static int ramp_control_enable(struct platform_device *pdev, + struct rcgwr *rcgwr) +{ + int i = 0, ret = 0; + + for (i = 0; i < ARRAY_SIZE(ramp_en); i++) { + ret = check_rcg_config(rcgwr->rcg_base); + if (ret) { + dev_err(&pdev->dev, "Failed to update config!!!\n"); + return ret; + } + writel_relaxed(ramp_en[i], rcgwr->base + DCVS_CFG_CTL); + ret = rc_config_update(rcgwr->base, DCVS_CONFIG, DCVS_CONFIG); + if (ret) { + dev_err(&pdev->dev, + "Failed to config update for 0x2 and ACK 0x4\n"); + break; + } + } + + return ret; +} + +static int ramp_down_disable(struct platform_device *pdev, + struct rcgwr *rcgwr) +{ + int ret = 0; + + ret = check_rcg_config(rcgwr->rcg_base); + if (ret) { + dev_err(&pdev->dev, "Failed to update config!!!\n"); + return ret; + } + + writel_relaxed(0x200, rcgwr->base + DCVS_CFG_CTL); + ret = rc_config_update(rcgwr->base, DCVS_CONFIG, DCVS_CONFIG); + if (ret) + dev_err(&pdev->dev, + "Failed to config update for 0x2 and ACK 0x4\n"); + + return ret; +} + +static int ramp_control_disable(struct platform_device *pdev, + struct rcgwr *rcgwr) +{ + int ret = 0; + + if (!rcgwr->inited) + return 0; + + ret = check_rcg_config(rcgwr->rcg_base); + if (ret) { + dev_err(&pdev->dev, "Failed to update config!!!\n"); + return ret; + } + + writel_relaxed(0x0, rcgwr->base + DCVS_CFG_CTL); + + ret = rc_config_update(rcgwr->base, DCVS_CONFIG, DCVS_CONFIG); + if (ret) + dev_err(&pdev->dev, + "Failed to config update for 0x2 and ACK 0x4\n"); + + rcgwr->inited = false; + + return ret; +} + +static int ramp_link_sid(struct platform_device *pdev, struct rcgwr *rcgwr) +{ + int ret = 0, i; + + if (!rcgwr->link_sid_len) { + pr_err("Use Default Link SID\n"); + return 0; + } + + ret = check_rcg_config(rcgwr->rcg_base); + if (ret) { + dev_err(&pdev->dev, "Failed to update config!!!\n"); + return ret; + } + + for (i = 0; i < rcgwr->link_sid_len; i++) + writel_relaxed(rcgwr->link_sid_value[i], + rcgwr->base + rcgwr->link_sid_offset[i]); + + ret = rc_config_update(rcgwr->base, LINK_SID, LINK_SID); + if (ret) + dev_err(&pdev->dev, + "Failed to config update for 0x3 and ACK 0x8\n"); + + return ret; +} + +static int ramp_lmh_sid(struct platform_device *pdev, struct rcgwr *rcgwr) +{ + int ret = 0, i, j; + + if (!rcgwr->lmh_sid_len) { + pr_err("Use Default LMH SID\n"); + return 0; + } + + ret = check_rcg_config(rcgwr->rcg_base); + if (ret) { + dev_err(&pdev->dev, "Failed to update config!!!\n"); + return ret; + } + + for (i = 0; i < rcgwr->lmh_sid_len; i++) + writel_relaxed(rcgwr->lmh_sid_value[i], + rcgwr->base + rcgwr->lmh_sid_offset[i]); + + for (i = LMH_SID_START, j = 0; j < rcgwr->lmh_sid_len; i--, j++) { + ret = rc_config_update(rcgwr->base, i, i); + if (ret) { + dev_err(&pdev->dev, + "Failed to update config for DFSSID-0x%x and ack 0x%lx\n", + i, BIT(i)); + break; + } + } + + return ret; +} + +static int ramp_dfs_sid(struct platform_device *pdev, struct rcgwr *rcgwr) +{ + int ret = 0, i, j; + + if (!rcgwr->dfs_sid_len) { + pr_err("Use Default DFS SID\n"); + return 0; + } + + ret = check_rcg_config(rcgwr->rcg_base); + if (ret) { + dev_err(&pdev->dev, "Failed to update config!!!\n"); + return ret; + } + + for (i = 0; i < rcgwr->dfs_sid_len; i++) + writel_relaxed(rcgwr->dfs_sid_value[i], + rcgwr->base + rcgwr->dfs_sid_offset[i]); + + for (i = DFS_SID_START, j = 0; j < rcgwr->dfs_sid_len; i--, j++) { + ret = rc_config_update(rcgwr->base, i, i); + if (ret) { + dev_err(&pdev->dev, + "Failed to update config for DFSSID-0x%x and ack 0x%lx\n", + i, BIT(i)); + break; + } + } + + return ret; +} + +static int parse_dt_rcgwr(struct platform_device *pdev, char *prop_name, + int **off, int **val, int *len) +{ + struct device_node *node = pdev->dev.of_node; + int prop_len, i; + u32 *array; + + if (!of_find_property(node, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % 2) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + prop_len /= 2; + + *off = devm_kzalloc(&pdev->dev, prop_len * sizeof(u32), GFP_KERNEL); + if (!*off) + return -ENOMEM; + + *val = devm_kzalloc(&pdev->dev, prop_len * sizeof(u32), GFP_KERNEL); + if (!*val) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, + prop_len * sizeof(u32) * 2, GFP_KERNEL); + if (!array) + return -ENOMEM; + + of_property_read_u32_array(node, prop_name, array, prop_len * 2); + for (i = 0; i < prop_len; i++) { + *(*off + i) = array[i * 2]; + *(*val + i) = array[2 * i + 1]; + } + + *len = prop_len; + + return 0; +} + +static int rcgwr_init_bases(struct platform_device *pdev, struct rcgwr *rcgwr, + const char *name) +{ + struct resource *res; + char rcg_name[] = "rcgwr-xxx-base"; + char rcg_mux[] = "xxx-mux"; + + snprintf(rcg_name, ARRAY_SIZE(rcg_name), "rcgwr-%s-base", name); + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, rcg_name); + if (!res) { + dev_err(&pdev->dev, "missing %s\n", rcg_name); + return -EINVAL; + } + + rcgwr->base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!rcgwr->base) { + dev_err(&pdev->dev, "ioremap failed for %s\n", + rcg_name); + return -ENOMEM; + } + + snprintf(rcg_mux, ARRAY_SIZE(rcg_mux), "%s-mux", name); + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, rcg_mux); + if (!res) { + dev_err(&pdev->dev, "missing %s\n", rcg_mux); + return -EINVAL; + } + + rcgwr->rcg_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!rcgwr->rcg_base) { + dev_err(&pdev->dev, "ioremap failed for %s\n", + rcg_name); + return -ENOMEM; + } + + return 0; +} + +/* + * Disable the RCG ramp controller. + */ +int clock_rcgwr_disable(struct platform_device *pdev) +{ + int i, ret = 0; + + for (i = 0; i < num_clusters; i++) { + if (!rcgwr[i]) + return -ENOMEM; + ret = ramp_control_disable(pdev, rcgwr[i]); + if (ret) + dev_err(&pdev->dev, + "Ramp controller disable failed for Cluster-%d\n", i); + } + + return ret; +} + +static int clock_rcgwr_disable_set(void *data, u64 val) +{ + if (val) { + pr_err("Enabling not supported!!\n"); + return -EINVAL; + } else + return clock_rcgwr_disable(cpu_clock_dev); +} + +DEFINE_SIMPLE_ATTRIBUTE(rcgwr_enable_fops, NULL, + clock_rcgwr_disable_set, "%lld\n"); + +static int clock_debug_enable_show(struct seq_file *m, void *v) +{ + int i = 0; + + seq_puts(m, "Cluster\t\tEnable\n"); + + for (i = 0; i < num_clusters; i++) + seq_printf(m, "%d\t\t%d\n", i, rcgwr[i]->inited); + + return 0; +} + +static int clock_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, clock_debug_enable_show, inode->i_private); +} + +static const struct file_operations rcgwr_enable_show = { + .owner = THIS_MODULE, + .open = clock_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* + * Program the DFS Sequence ID. + * Program the Link Sequence ID. + * Enable RCG with ramp controller. + */ +int clock_rcgwr_init(struct platform_device *pdev) +{ + int ret = 0, i; + char link_sid[] = "qcom,link-sid-xxx"; + char dfs_sid[] = "qcom,dfs-sid-xxx"; + char lmh_sid[] = "qcom,lmh-sid-xxx"; + char ramp_dis[] = "qcom,ramp-dis-xxx"; + char names[] = "cxxx"; + struct dentry *debugfs_base; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-clusters", + &num_clusters); + if (ret) + panic("Cannot read num-clusters from dt (ret:%d)\n", ret); + + rcgwr = devm_kzalloc(&pdev->dev, sizeof(struct rcgwr) * num_clusters, + GFP_KERNEL); + if (!rcgwr) + return -ENOMEM; + + for (i = 0; i < num_clusters; i++) { + rcgwr[i] = devm_kzalloc(&pdev->dev, sizeof(struct rcgwr), + GFP_KERNEL); + if (!rcgwr[i]) + goto fail_mem; + + snprintf(names, ARRAY_SIZE(names), "c%d", i); + + ret = rcgwr_init_bases(pdev, rcgwr[i], names); + if (ret) { + dev_err(&pdev->dev, "Failed to init_bases for RCGwR\n"); + goto fail_mem; + } + + snprintf(dfs_sid, ARRAY_SIZE(dfs_sid), + "qcom,dfs-sid-%s", names); + ret = parse_dt_rcgwr(pdev, dfs_sid, &(rcgwr[i]->dfs_sid_offset), + &(rcgwr[i]->dfs_sid_value), &(rcgwr[i]->dfs_sid_len)); + if (ret) + dev_err(&pdev->dev, + "No DFS SID tables found for Cluster-%d\n", i); + + snprintf(link_sid, ARRAY_SIZE(link_sid), + "qcom,link-sid-%s", names); + ret = parse_dt_rcgwr(pdev, link_sid, + &(rcgwr[i]->link_sid_offset), + &(rcgwr[i]->link_sid_value), &(rcgwr[i]->link_sid_len)); + if (ret) + dev_err(&pdev->dev, + "No Link SID tables found for Cluster-%d\n", i); + + snprintf(lmh_sid, ARRAY_SIZE(lmh_sid), + "qcom,lmh-sid-%s", names); + ret = parse_dt_rcgwr(pdev, lmh_sid, + &(rcgwr[i]->lmh_sid_offset), + &(rcgwr[i]->lmh_sid_value), &(rcgwr[i]->lmh_sid_len)); + if (ret) + dev_err(&pdev->dev, + "No LMH SID tables found for Cluster-%d\n", i); + + ret = ramp_lmh_sid(pdev, rcgwr[i]); + if (ret) + goto fail_mem; + + ret = ramp_dfs_sid(pdev, rcgwr[i]); + if (ret) + goto fail_mem; + + ret = ramp_link_sid(pdev, rcgwr[i]); + if (ret) + goto fail_mem; + + ret = ramp_control_enable(pdev, rcgwr[i]); + if (ret) + goto fail_mem; + + snprintf(ramp_dis, ARRAY_SIZE(ramp_dis), + "qcom,ramp-dis-%s", names); + if (of_property_read_bool(pdev->dev.of_node, ramp_dis)) { + ret = ramp_down_disable(pdev, rcgwr[i]); + if (ret) + goto fail_mem; + } + + rcgwr[i]->inited = true; + } + + cpu_clock_dev = pdev; + + debugfs_base = debugfs_create_dir("rcgwr", NULL); + if (debugfs_base) { + if (!debugfs_create_file("enable", 0444, debugfs_base, NULL, + &rcgwr_enable_fops)) { + pr_err("Unable to create `enable` debugfs entry\n"); + debugfs_remove(debugfs_base); + } + + if (!debugfs_create_file("status", 0444, debugfs_base, NULL, + &rcgwr_enable_show)) { + pr_err("Unable to create `status` debugfs entry\n"); + debugfs_remove_recursive(debugfs_base); + } + } else + pr_err("Unable to create debugfs dir\n"); + + pr_info("RCGwR Init Completed\n"); + + return ret; + +fail_mem: + --i; + for (; i >= 0 ; i--) { + devm_kfree(&pdev->dev, rcgwr[i]); + rcgwr[i] = NULL; + } + devm_kfree(&pdev->dev, rcgwr); + panic("RCGwR failed to Initialize\n"); +} diff --git a/drivers/clk/msm/clock-rpm.c b/drivers/clk/msm/clock-rpm.c new file mode 100644 index 0000000000000000000000000000000000000000..f95823df82f21bf425517a2a0997c92272dd9e1c --- /dev/null +++ b/drivers/clk/msm/clock-rpm.c @@ -0,0 +1,473 @@ +/* Copyright (c) 2010-2015, 2017, 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 +#include +#include +#include +#include + +#define __clk_rpmrs_set_rate(r, value, ctx) \ + ((r)->rpmrs_data->set_rate_fn((r), (value), (ctx))) + +#define clk_rpmrs_set_rate_sleep(r, value) \ + __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_sleep_id) + +#define clk_rpmrs_set_rate_active(r, value) \ + __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_active_id) + +static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value, + uint32_t context) +{ + int ret; + + struct msm_rpm_kvp kvp = { + .key = r->rpm_key, + .data = (void *)&value, + .length = sizeof(value), + }; + + switch (context) { + case MSM_RPM_CTX_ACTIVE_SET: + if (*r->last_active_set_vote == value) + return 0; + break; + case MSM_RPM_CTX_SLEEP_SET: + if (*r->last_sleep_set_vote == value) + return 0; + break; + default: + return -EINVAL; + }; + + ret = msm_rpm_send_message(context, r->rpm_res_type, r->rpm_clk_id, + &kvp, 1); + if (ret) + return ret; + + switch (context) { + case MSM_RPM_CTX_ACTIVE_SET: + *r->last_active_set_vote = value; + break; + case MSM_RPM_CTX_SLEEP_SET: + *r->last_sleep_set_vote = value; + break; + } + + return 0; +} + +static int clk_rpmrs_handoff_smd(struct rpm_clk *r) +{ + if (!r->branch) + r->c.rate = INT_MAX; + + return 0; +} + +static int clk_rpmrs_is_enabled_smd(struct rpm_clk *r) +{ + return !!r->c.prepare_count; +} + +struct clk_rpmrs_data { + int (*set_rate_fn)(struct rpm_clk *r, uint32_t value, uint32_t context); + int (*get_rate_fn)(struct rpm_clk *r); + int (*handoff_fn)(struct rpm_clk *r); + int (*is_enabled)(struct rpm_clk *r); + int ctx_active_id; + int ctx_sleep_id; +}; + +struct clk_rpmrs_data clk_rpmrs_data_smd = { + .set_rate_fn = clk_rpmrs_set_rate_smd, + .handoff_fn = clk_rpmrs_handoff_smd, + .is_enabled = clk_rpmrs_is_enabled_smd, + .ctx_active_id = MSM_RPM_CTX_ACTIVE_SET, + .ctx_sleep_id = MSM_RPM_CTX_SLEEP_SET, +}; + +static DEFINE_RT_MUTEX(rpm_clock_lock); + +static void to_active_sleep_khz(struct rpm_clk *r, unsigned long rate, + unsigned long *active_khz, unsigned long *sleep_khz) +{ + /* Convert the rate (hz) to khz */ + *active_khz = DIV_ROUND_UP(rate, 1000); + + /* + * Active-only clocks don't care what the rate is during sleep. So, + * they vote for zero. + */ + if (r->active_only) + *sleep_khz = 0; + else + *sleep_khz = *active_khz; +} + +static int rpm_clk_prepare(struct clk *clk) +{ + struct rpm_clk *r = to_rpm_clk(clk); + uint32_t value; + int rc = 0; + unsigned long this_khz, this_sleep_khz; + unsigned long peer_khz = 0, peer_sleep_khz = 0; + struct rpm_clk *peer = r->peer; + + rt_mutex_lock(&rpm_clock_lock); + + to_active_sleep_khz(r, r->c.rate, &this_khz, &this_sleep_khz); + + /* Don't send requests to the RPM if the rate has not been set. */ + if (this_khz == 0) + goto out; + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep_khz(peer, peer->c.rate, + &peer_khz, &peer_sleep_khz); + + value = max(this_khz, peer_khz); + if (r->branch) + value = !!value; + + rc = clk_rpmrs_set_rate_active(r, value); + if (rc) + goto out; + + value = max(this_sleep_khz, peer_sleep_khz); + if (r->branch) + value = !!value; + + rc = clk_rpmrs_set_rate_sleep(r, value); + if (rc) { + /* Undo the active set vote and restore it to peer_khz */ + value = peer_khz; + rc = clk_rpmrs_set_rate_active(r, value); + } + +out: + if (!rc) + r->enabled = true; + + rt_mutex_unlock(&rpm_clock_lock); + + return rc; +} + +static void rpm_clk_unprepare(struct clk *clk) +{ + struct rpm_clk *r = to_rpm_clk(clk); + + rt_mutex_lock(&rpm_clock_lock); + + if (r->c.rate) { + uint32_t value; + struct rpm_clk *peer = r->peer; + unsigned long peer_khz = 0, peer_sleep_khz = 0; + int rc; + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep_khz(peer, peer->c.rate, + &peer_khz, &peer_sleep_khz); + + value = r->branch ? !!peer_khz : peer_khz; + rc = clk_rpmrs_set_rate_active(r, value); + if (rc) + goto out; + + value = r->branch ? !!peer_sleep_khz : peer_sleep_khz; + rc = clk_rpmrs_set_rate_sleep(r, value); + } + r->enabled = false; +out: + rt_mutex_unlock(&rpm_clock_lock); + +} + +static int rpm_clk_set_rate(struct clk *clk, unsigned long rate) +{ + struct rpm_clk *r = to_rpm_clk(clk); + unsigned long this_khz, this_sleep_khz; + int rc = 0; + + rt_mutex_lock(&rpm_clock_lock); + + if (r->enabled) { + uint32_t value; + struct rpm_clk *peer = r->peer; + unsigned long peer_khz = 0, peer_sleep_khz = 0; + + to_active_sleep_khz(r, rate, &this_khz, &this_sleep_khz); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep_khz(peer, peer->c.rate, + &peer_khz, &peer_sleep_khz); + + value = max(this_khz, peer_khz); + rc = clk_rpmrs_set_rate_active(r, value); + if (rc) + goto out; + + value = max(this_sleep_khz, peer_sleep_khz); + rc = clk_rpmrs_set_rate_sleep(r, value); + } + +out: + rt_mutex_unlock(&rpm_clock_lock); + + return rc; +} + +static unsigned long rpm_clk_get_rate(struct clk *clk) +{ + struct rpm_clk *r = to_rpm_clk(clk); + + if (r->rpmrs_data->get_rate_fn) + return r->rpmrs_data->get_rate_fn(r); + else + return clk->rate; +} + +static int rpm_clk_is_enabled(struct clk *clk) +{ + struct rpm_clk *r = to_rpm_clk(clk); + + return r->rpmrs_data->is_enabled(r); +} + +static long rpm_clk_round_rate(struct clk *clk, unsigned long rate) +{ + /* Not supported. */ + return rate; +} + +static bool rpm_clk_is_local(struct clk *clk) +{ + return false; +} + +static enum handoff rpm_clk_handoff(struct clk *clk) +{ + struct rpm_clk *r = to_rpm_clk(clk); + int rc; + + /* + * Querying an RPM clock's status will return 0 unless the clock's + * rate has previously been set through the RPM. When handing off, + * assume these clocks are enabled (unless the RPM call fails) so + * child clocks of these RPM clocks can still be handed off. + */ + rc = r->rpmrs_data->handoff_fn(r); + if (rc < 0) + return HANDOFF_DISABLED_CLK; + + /* + * Since RPM handoff code may update the software rate of the clock by + * querying the RPM, we need to make sure our request to RPM now + * matches the software rate of the clock. When we send the request + * to RPM, we also need to update any other state info we would + * normally update. So, call the appropriate clock function instead + * of directly using the RPM driver APIs. + */ + rc = rpm_clk_prepare(clk); + if (rc < 0) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +#define RPM_MISC_CLK_TYPE 0x306b6c63 +#define RPM_SCALING_ENABLE_ID 0x2 + +int enable_rpm_scaling(void) +{ + int rc, value = 0x1; + static int is_inited; + + struct msm_rpm_kvp kvp = { + .key = RPM_SMD_KEY_ENABLE, + .data = (void *)&value, + .length = sizeof(value), + }; + + if (is_inited) + return 0; + + rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET, + RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + WARN(1, "RPM clock scaling (sleep set) did not enable!\n"); + return rc; + } + + rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET, + RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + WARN(1, "RPM clock scaling (active set) did not enable!\n"); + return rc; + } + + is_inited++; + return 0; +} + +int vote_bimc(struct rpm_clk *r, uint32_t value) +{ + int rc; + + struct msm_rpm_kvp kvp = { + .key = r->rpm_key, + .data = (void *)&value, + .length = sizeof(value), + }; + + rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET, + r->rpm_res_type, r->rpmrs_data->ctx_active_id, + &kvp, 1); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + WARN(1, "BIMC vote not sent!\n"); + return rc; + } + + return rc; +} + +const struct clk_ops clk_ops_rpm = { + .prepare = rpm_clk_prepare, + .unprepare = rpm_clk_unprepare, + .set_rate = rpm_clk_set_rate, + .get_rate = rpm_clk_get_rate, + .is_enabled = rpm_clk_is_enabled, + .round_rate = rpm_clk_round_rate, + .is_local = rpm_clk_is_local, + .handoff = rpm_clk_handoff, +}; + +const struct clk_ops clk_ops_rpm_branch = { + .prepare = rpm_clk_prepare, + .unprepare = rpm_clk_unprepare, + .is_local = rpm_clk_is_local, + .handoff = rpm_clk_handoff, +}; + +static struct rpm_clk *rpm_clk_dt_parser_common(struct device *dev, + struct device_node *np) +{ + struct rpm_clk *rpm, *peer; + struct clk *c; + int rc = 0; + phandle p; + const char *str; + + rpm = devm_kzalloc(dev, sizeof(*rpm), GFP_KERNEL); + if (!rpm) + return ERR_PTR(-ENOMEM); + + rc = of_property_read_phandle_index(np, "qcom,rpm-peer", 0, &p); + if (rc) { + dt_err(np, "missing qcom,rpm-peer dt property\n"); + return ERR_PTR(rc); + } + + /* Rely on whoever's called last to setup the circular ref */ + c = msmclk_lookup_phandle(dev, p); + if (!IS_ERR(c)) { + uint32_t *sleep = devm_kzalloc(dev, sizeof(uint32_t), + GFP_KERNEL); + uint32_t *active = + devm_kzalloc(dev, sizeof(uint32_t), + GFP_KERNEL); + + if (!sleep || !active) + return ERR_PTR(-ENOMEM); + peer = to_rpm_clk(c); + peer->peer = rpm; + rpm->peer = peer; + rpm->last_active_set_vote = active; + peer->last_active_set_vote = active; + rpm->last_sleep_set_vote = sleep; + peer->last_sleep_set_vote = sleep; + } + + rpm->rpmrs_data = &clk_rpmrs_data_smd; + rpm->active_only = of_device_is_compatible(np, "qcom,rpm-a-clk") || + of_device_is_compatible(np, "qcom,rpm-branch-a-clk"); + + rc = of_property_read_string(np, "qcom,res-type", &str); + if (rc) { + dt_err(np, "missing qcom,res-type dt property\n"); + return ERR_PTR(rc); + } + if (sscanf(str, "%4c", (char *) &rpm->rpm_res_type) <= 0) + return ERR_PTR(-EINVAL); + + rc = of_property_read_u32(np, "qcom,res-id", &rpm->rpm_clk_id); + if (rc) { + dt_err(np, "missing qcom,res-id dt property\n"); + return ERR_PTR(rc); + } + + rc = of_property_read_string(np, "qcom,key", &str); + if (rc) { + dt_err(np, "missing qcom,key dt property\n"); + return ERR_PTR(rc); + } + if (sscanf(str, "%4c", (char *) &rpm->rpm_key) <= 0) + return ERR_PTR(-EINVAL); + return rpm; +} + +static void *rpm_clk_dt_parser(struct device *dev, struct device_node *np) +{ + struct rpm_clk *rpm; + + rpm = rpm_clk_dt_parser_common(dev, np); + if (IS_ERR(rpm)) + return rpm; + + rpm->c.ops = &clk_ops_rpm; + return msmclk_generic_clk_init(dev, np, &rpm->c); +} + +static void *rpm_branch_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct rpm_clk *rpm; + u32 rate; + int rc; + + rpm = rpm_clk_dt_parser_common(dev, np); + if (IS_ERR(rpm)) + return rpm; + + rpm->c.ops = &clk_ops_rpm_branch; + rpm->branch = true; + + rc = of_property_read_u32(np, "qcom,rcg-init-rate", &rate); + if (!rc) + rpm->c.rate = rate; + + return msmclk_generic_clk_init(dev, np, &rpm->c); +} +MSMCLK_PARSER(rpm_clk_dt_parser, "qcom,rpm-clk", 0); +MSMCLK_PARSER(rpm_clk_dt_parser, "qcom,rpm-a-clk", 1); +MSMCLK_PARSER(rpm_branch_clk_dt_parser, "qcom,rpm-branch-clk", 0); +MSMCLK_PARSER(rpm_branch_clk_dt_parser, "qcom,rpm-branch-a-clk", 1); diff --git a/drivers/clk/msm/clock-voter.c b/drivers/clk/msm/clock-voter.c new file mode 100644 index 0000000000000000000000000000000000000000..b504724e0c26d89173ec4d9d0e910a734d5cc0dd --- /dev/null +++ b/drivers/clk/msm/clock-voter.c @@ -0,0 +1,202 @@ +/* Copyright (c) 2010-2015, 2017, 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 +#include +#include +#include +#include +#include + +static DEFINE_RT_MUTEX(voter_clk_lock); + +/* Aggregate the rate of clocks that are currently on. */ +static unsigned long voter_clk_aggregate_rate(const struct clk *parent) +{ + struct clk *clk; + unsigned long rate = 0; + + list_for_each_entry(clk, &parent->children, siblings) { + struct clk_voter *v = to_clk_voter(clk); + + if (v->enabled) + rate = max(clk->rate, rate); + } + return rate; +} + +static int voter_clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *clkp; + struct clk_voter *clkh, *v = to_clk_voter(clk); + unsigned long cur_rate, new_rate, other_rate = 0; + + if (v->is_branch) + return 0; + + rt_mutex_lock(&voter_clk_lock); + + if (v->enabled) { + struct clk *parent = clk->parent; + + /* + * Get the aggregate rate without this clock's vote and update + * if the new rate is different than the current rate + */ + list_for_each_entry(clkp, &parent->children, siblings) { + clkh = to_clk_voter(clkp); + if (clkh->enabled && clkh != v) + other_rate = max(clkp->rate, other_rate); + } + + cur_rate = max(other_rate, clk->rate); + new_rate = max(other_rate, rate); + + if (new_rate != cur_rate) { + ret = clk_set_rate(parent, new_rate); + if (ret) + goto unlock; + } + } + clk->rate = rate; +unlock: + rt_mutex_unlock(&voter_clk_lock); + + return ret; +} + +static int voter_clk_prepare(struct clk *clk) +{ + int ret = 0; + unsigned long cur_rate; + struct clk *parent; + struct clk_voter *v = to_clk_voter(clk); + + rt_mutex_lock(&voter_clk_lock); + parent = clk->parent; + + if (v->is_branch) { + v->enabled = true; + goto out; + } + + /* + * Increase the rate if this clock is voting for a higher rate + * than the current rate. + */ + cur_rate = voter_clk_aggregate_rate(parent); + if (clk->rate > cur_rate) { + ret = clk_set_rate(parent, clk->rate); + if (ret) + goto out; + } + v->enabled = true; +out: + rt_mutex_unlock(&voter_clk_lock); + + return ret; +} + +static void voter_clk_unprepare(struct clk *clk) +{ + unsigned long cur_rate, new_rate; + struct clk *parent; + struct clk_voter *v = to_clk_voter(clk); + + + rt_mutex_lock(&voter_clk_lock); + parent = clk->parent; + + /* + * Decrease the rate if this clock was the only one voting for + * the highest rate. + */ + v->enabled = false; + if (v->is_branch) + goto out; + + new_rate = voter_clk_aggregate_rate(parent); + cur_rate = max(new_rate, clk->rate); + + if (new_rate < cur_rate) + clk_set_rate(parent, new_rate); + +out: + rt_mutex_unlock(&voter_clk_lock); +} + +static int voter_clk_is_enabled(struct clk *clk) +{ + struct clk_voter *v = to_clk_voter(clk); + + return v->enabled; +} + +static long voter_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return clk_round_rate(clk->parent, rate); +} + +static bool voter_clk_is_local(struct clk *clk) +{ + return true; +} + +static enum handoff voter_clk_handoff(struct clk *clk) +{ + if (!clk->rate) + return HANDOFF_DISABLED_CLK; + + /* + * Send the default rate to the parent if necessary and update the + * software state of the voter clock. + */ + if (voter_clk_prepare(clk) < 0) + return HANDOFF_DISABLED_CLK; + + return HANDOFF_ENABLED_CLK; +} + +const struct clk_ops clk_ops_voter = { + .prepare = voter_clk_prepare, + .unprepare = voter_clk_unprepare, + .set_rate = voter_clk_set_rate, + .is_enabled = voter_clk_is_enabled, + .round_rate = voter_clk_round_rate, + .is_local = voter_clk_is_local, + .handoff = voter_clk_handoff, +}; + +static void *sw_vote_clk_dt_parser(struct device *dev, + struct device_node *np) +{ + struct clk_voter *v; + int rc; + u32 temp; + + v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); + if (!v) + return ERR_PTR(-ENOMEM); + + rc = of_property_read_u32(np, "qcom,config-rate", &temp); + if (rc) { + dt_prop_err(np, "qcom,config-rate", "is missing"); + return ERR_PTR(rc); + } + + v->c.ops = &clk_ops_voter; + return msmclk_generic_clk_init(dev, np, &v->c); +} +MSMCLK_PARSER(sw_vote_clk_dt_parser, "qcom,sw-vote-clk", 0); diff --git a/drivers/clk/msm/clock.c b/drivers/clk/msm/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..30eac98d3ee3a754d89b0870b8bfb4cc0dd43ad5 --- /dev/null +++ b/drivers/clk/msm/clock.c @@ -0,0 +1,1407 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "clock.h" + +struct handoff_clk { + struct list_head list; + struct clk *clk; +}; +static LIST_HEAD(handoff_list); + +struct handoff_vdd { + struct list_head list; + struct clk_vdd_class *vdd_class; +}; +static LIST_HEAD(handoff_vdd_list); + +static DEFINE_MUTEX(msm_clock_init_lock); +LIST_HEAD(orphan_clk_list); +static LIST_HEAD(clk_notifier_list); + +/* Find the voltage level required for a given rate. */ +int find_vdd_level(struct clk *clk, unsigned long rate) +{ + int level; + + for (level = 0; level < clk->num_fmax; level++) + if (rate <= clk->fmax[level]) + break; + + if (level == clk->num_fmax) { + pr_err("Rate %lu for %s is greater than highest Fmax\n", rate, + clk->dbg_name); + return -EINVAL; + } + + return level; +} + +/* Update voltage level given the current votes. */ +static int update_vdd(struct clk_vdd_class *vdd_class) +{ + int level, rc = 0, i, ignore; + struct regulator **r = vdd_class->regulator; + int *uv = vdd_class->vdd_uv; + int *ua = vdd_class->vdd_ua; + int n_reg = vdd_class->num_regulators; + int cur_lvl = vdd_class->cur_level; + int max_lvl = vdd_class->num_levels - 1; + int cur_base = cur_lvl * n_reg; + int new_base; + + /* aggregate votes */ + for (level = max_lvl; level > 0; level--) + if (vdd_class->level_votes[level]) + break; + + if (level == cur_lvl) + return 0; + + max_lvl = max_lvl * n_reg; + new_base = level * n_reg; + for (i = 0; i < vdd_class->num_regulators; i++) { + rc = regulator_set_voltage(r[i], uv[new_base + i], + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + if (rc) + goto set_voltage_fail; + + if (ua) { + rc = regulator_set_load(r[i], ua[new_base + i]); + rc = rc > 0 ? 0 : rc; + if (rc) + goto set_mode_fail; + } + if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels) + rc = regulator_enable(r[i]); + else if (level == 0) + rc = regulator_disable(r[i]); + if (rc) + goto enable_disable_fail; + } + if (vdd_class->set_vdd && !vdd_class->num_regulators) + rc = vdd_class->set_vdd(vdd_class, level); + + if (!rc) + vdd_class->cur_level = level; + + return rc; + +enable_disable_fail: + /* + * set_optimum_mode could use voltage to derive mode. Restore + * previous voltage setting for r[i] first. + */ + if (ua) { + regulator_set_voltage(r[i], uv[cur_base + i], + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + regulator_set_load(r[i], ua[cur_base + i]); + } + +set_mode_fail: + regulator_set_voltage(r[i], uv[cur_base + i], + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + +set_voltage_fail: + for (i--; i >= 0; i--) { + regulator_set_voltage(r[i], uv[cur_base + i], + vdd_class->use_max_uV ? INT_MAX : uv[max_lvl + i]); + if (ua) + regulator_set_load(r[i], ua[cur_base + i]); + if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels) + regulator_disable(r[i]); + else if (level == 0) + ignore = regulator_enable(r[i]); + } + return rc; +} + +/* Vote for a voltage level. */ +int vote_vdd_level(struct clk_vdd_class *vdd_class, int level) +{ + int rc; + + if (level >= vdd_class->num_levels) + return -EINVAL; + + mutex_lock(&vdd_class->lock); + vdd_class->level_votes[level]++; + rc = update_vdd(vdd_class); + if (rc) + vdd_class->level_votes[level]--; + mutex_unlock(&vdd_class->lock); + + return rc; +} + +/* Remove vote for a voltage level. */ +int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level) +{ + int rc = 0; + + if (level >= vdd_class->num_levels) + return -EINVAL; + + mutex_lock(&vdd_class->lock); + if (WARN(!vdd_class->level_votes[level], + "Reference counts are incorrect for %s level %d\n", + vdd_class->class_name, level)) + goto out; + vdd_class->level_votes[level]--; + rc = update_vdd(vdd_class); + if (rc) + vdd_class->level_votes[level]++; +out: + mutex_unlock(&vdd_class->lock); + return rc; +} + +/* Vote for a voltage level corresponding to a clock's rate. */ +static int vote_rate_vdd(struct clk *clk, unsigned long rate) +{ + int level; + + if (!clk->vdd_class) + return 0; + + level = find_vdd_level(clk, rate); + if (level < 0) + return level; + + return vote_vdd_level(clk->vdd_class, level); +} + +/* Remove vote for a voltage level corresponding to a clock's rate. */ +static void unvote_rate_vdd(struct clk *clk, unsigned long rate) +{ + int level; + + if (!clk->vdd_class) + return; + + level = find_vdd_level(clk, rate); + if (level < 0) + return; + + unvote_vdd_level(clk->vdd_class, level); +} + +/* Check if the rate is within the voltage limits of the clock. */ +bool is_rate_valid(struct clk *clk, unsigned long rate) +{ + int level; + + if (!clk->vdd_class) + return true; + + level = find_vdd_level(clk, rate); + return level >= 0; +} + +/** + * __clk_pre_reparent() - Set up the new parent before switching to it and + * prevent the enable state of the child clock from changing. + * @c: The child clock that's going to switch parents + * @new: The new parent that the child clock is going to switch to + * @flags: Pointer to scratch space to save spinlock flags + * + * Cannot be called from atomic context. + * + * Use this API to set up the @new parent clock to be able to support the + * current prepare and enable state of the child clock @c. Once the parent is + * set up, the child clock can safely switch to it. + * + * The caller shall grab the prepare_lock of clock @c before calling this API + * and only release it after calling __clk_post_reparent() for clock @c (or + * if this API fails). This is necessary to prevent the prepare state of the + * child clock @c from changing while the reparenting is in progress. Since + * this API takes care of grabbing the enable lock of @c, only atomic + * operation are allowed between calls to __clk_pre_reparent and + * __clk_post_reparent() + * + * The scratch space pointed to by @flags should not be altered before + * calling __clk_post_reparent() for clock @c. + * + * See also: __clk_post_reparent() + */ +int __clk_pre_reparent(struct clk *c, struct clk *new, unsigned long *flags) +{ + int rc; + + if (c->prepare_count) { + rc = clk_prepare(new); + if (rc) + return rc; + } + + spin_lock_irqsave(&c->lock, *flags); + if (c->count) { + rc = clk_enable(new); + if (rc) { + spin_unlock_irqrestore(&c->lock, *flags); + clk_unprepare(new); + return rc; + } + } + return 0; +} + +/** + * __clk_post_reparent() - Release requirements on old parent after switching + * away from it and allow changes to the child clock's enable state. + * @c: The child clock that switched parents + * @old: The old parent that the child clock switched away from or the new + * parent of a failed reparent attempt. + * @flags: Pointer to scratch space where spinlock flags were saved + * + * Cannot be called from atomic context. + * + * This API works in tandem with __clk_pre_reparent. Use this API to + * - Remove prepare and enable requirements from the @old parent after + * switching away from it + * - Or, undo the effects of __clk_pre_reparent() after a failed attempt to + * change parents + * + * The caller shall release the prepare_lock of @c that was grabbed before + * calling __clk_pre_reparent() only after this API is called (or if + * __clk_pre_reparent() fails). This is necessary to prevent the prepare + * state of the child clock @c from changing while the reparenting is in + * progress. Since this API releases the enable lock of @c, the limit to + * atomic operations set by __clk_pre_reparent() is no longer present. + * + * The scratch space pointed to by @flags shall not be altered since the call + * to __clk_pre_reparent() for clock @c. + * + * See also: __clk_pre_reparent() + */ +void __clk_post_reparent(struct clk *c, struct clk *old, unsigned long *flags) +{ + if (c->count) + clk_disable(old); + spin_unlock_irqrestore(&c->lock, *flags); + + if (c->prepare_count) + clk_unprepare(old); +} + +int clk_prepare(struct clk *clk) +{ + int ret = 0; + struct clk *parent; + + if (!clk) + return 0; + if (IS_ERR(clk)) + return -EINVAL; + + mutex_lock(&clk->prepare_lock); + if (clk->prepare_count == 0) { + parent = clk->parent; + + ret = clk_prepare(parent); + if (ret) + goto out; + ret = clk_prepare(clk->depends); + if (ret) + goto err_prepare_depends; + + ret = vote_rate_vdd(clk, clk->rate); + if (ret) + goto err_vote_vdd; + if (clk->ops->prepare) + ret = clk->ops->prepare(clk); + if (ret) + goto err_prepare_clock; + } + clk->prepare_count++; +out: + mutex_unlock(&clk->prepare_lock); + return ret; +err_prepare_clock: + unvote_rate_vdd(clk, clk->rate); +err_vote_vdd: + clk_unprepare(clk->depends); +err_prepare_depends: + clk_unprepare(parent); + goto out; +} +EXPORT_SYMBOL(clk_prepare); + +/* + * Standard clock functions defined in include/linux/clk.h + */ +int clk_enable(struct clk *clk) +{ + int ret = 0; + unsigned long flags; + struct clk *parent; + const char *name; + + if (!clk) + return 0; + if (IS_ERR(clk)) + return -EINVAL; + name = clk->dbg_name; + + spin_lock_irqsave(&clk->lock, flags); + WARN(!clk->prepare_count, + "%s: Don't call enable on unprepared clocks\n", name); + if (clk->count == 0) { + parent = clk->parent; + + ret = clk_enable(parent); + if (ret) + goto err_enable_parent; + ret = clk_enable(clk->depends); + if (ret) + goto err_enable_depends; + + trace_clock_enable(name, 1, smp_processor_id()); + if (clk->ops->enable) + ret = clk->ops->enable(clk); + if (ret) + goto err_enable_clock; + } + clk->count++; + spin_unlock_irqrestore(&clk->lock, flags); + + return 0; + +err_enable_clock: + clk_disable(clk->depends); +err_enable_depends: + clk_disable(parent); +err_enable_parent: + spin_unlock_irqrestore(&clk->lock, flags); + return ret; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + const char *name; + unsigned long flags; + + if (IS_ERR_OR_NULL(clk)) + return; + name = clk->dbg_name; + + spin_lock_irqsave(&clk->lock, flags); + WARN(!clk->prepare_count, + "%s: Never called prepare or calling disable after unprepare\n", + name); + if (WARN(clk->count == 0, "%s is unbalanced", name)) + goto out; + if (clk->count == 1) { + struct clk *parent = clk->parent; + + trace_clock_disable(name, 0, smp_processor_id()); + if (clk->ops->disable) + clk->ops->disable(clk); + clk_disable(clk->depends); + clk_disable(parent); + } + clk->count--; +out: + spin_unlock_irqrestore(&clk->lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +void clk_unprepare(struct clk *clk) +{ + const char *name; + + if (IS_ERR_OR_NULL(clk)) + return; + name = clk->dbg_name; + + mutex_lock(&clk->prepare_lock); + if (WARN(!clk->prepare_count, "%s is unbalanced (prepare)", name)) + goto out; + if (clk->prepare_count == 1) { + struct clk *parent = clk->parent; + + WARN(clk->count, + "%s: Don't call unprepare when the clock is enabled\n", + name); + + if (clk->ops->unprepare) + clk->ops->unprepare(clk); + unvote_rate_vdd(clk, clk->rate); + clk_unprepare(clk->depends); + clk_unprepare(parent); + } + clk->prepare_count--; +out: + mutex_unlock(&clk->prepare_lock); +} +EXPORT_SYMBOL(clk_unprepare); + +int clk_reset(struct clk *clk, enum clk_reset_action action) +{ + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + + if (!clk->ops->reset) + return -EINVAL; + + return clk->ops->reset(clk, action); +} +EXPORT_SYMBOL(clk_reset); + +/** + * __clk_notify - call clk notifier chain + * @clk: struct clk * that is changing rate + * @msg: clk notifier type (see include/linux/clk.h) + * @old_rate: old clk rate + * @new_rate: new clk rate + * + * Triggers a notifier call chain on the clk rate-change notification + * for 'clk'. Passes a pointer to the struct clk and the previous + * and current rates to the notifier callback. Intended to be called by + * internal clock code only. Returns NOTIFY_DONE from the last driver + * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if + * a driver returns that. + */ +static int __clk_notify(struct clk *clk, unsigned long msg, + unsigned long old_rate, unsigned long new_rate) +{ + struct msm_clk_notifier *cn; + struct msm_clk_notifier_data cnd; + int ret = NOTIFY_DONE; + + cnd.clk = clk; + cnd.old_rate = old_rate; + cnd.new_rate = new_rate; + + list_for_each_entry(cn, &clk_notifier_list, node) { + if (cn->clk == clk) { + ret = srcu_notifier_call_chain(&cn->notifier_head, msg, + &cnd); + break; + } + } + + return ret; +} + +/* + * clk rate change notifiers + * + * Note - The following notifier functionality is a verbatim copy + * of the implementation in the common clock framework, copied here + * until MSM switches to the common clock framework. + */ + +/** + * msm_clk_notif_register - add a clk rate change notifier + * @clk: struct clk * to watch + * @nb: struct notifier_block * with callback info + * + * Request notification when clk's rate changes. This uses an SRCU + * notifier because we want it to block and notifier unregistrations are + * uncommon. The callbacks associated with the notifier must not + * re-enter into the clk framework by calling any top-level clk APIs; + * this will cause a nested prepare_lock mutex. + * + * Pre-change notifier callbacks will be passed the current, pre-change + * rate of the clk via struct msm_clk_notifier_data.old_rate. The new, + * post-change rate of the clk is passed via struct + * msm_clk_notifier_data.new_rate. + * + * Post-change notifiers will pass the now-current, post-change rate of + * the clk in both struct msm_clk_notifier_data.old_rate and struct + * msm_clk_notifier_data.new_rate. + * + * Abort-change notifiers are effectively the opposite of pre-change + * notifiers: the original pre-change clk rate is passed in via struct + * msm_clk_notifier_data.new_rate and the failed post-change rate is passed + * in via struct msm_clk_notifier_data.old_rate. + * + * msm_clk_notif_register() must be called from non-atomic context. + * Returns -EINVAL if called with null arguments, -ENOMEM upon + * allocation failure; otherwise, passes along the return value of + * srcu_notifier_chain_register(). + */ +int msm_clk_notif_register(struct clk *clk, struct notifier_block *nb) +{ + struct msm_clk_notifier *cn; + int ret = -ENOMEM; + + if (!clk || !nb) + return -EINVAL; + + mutex_lock(&clk->prepare_lock); + + /* search the list of notifiers for this clk */ + list_for_each_entry(cn, &clk_notifier_list, node) + if (cn->clk == clk) + break; + + /* if clk wasn't in the notifier list, allocate new clk_notifier */ + if (cn->clk != clk) { + cn = kzalloc(sizeof(struct msm_clk_notifier), GFP_KERNEL); + if (!cn) + goto out; + + cn->clk = clk; + srcu_init_notifier_head(&cn->notifier_head); + + list_add(&cn->node, &clk_notifier_list); + } + + ret = srcu_notifier_chain_register(&cn->notifier_head, nb); + + clk->notifier_count++; + +out: + mutex_unlock(&clk->prepare_lock); + + return ret; +} + +/** + * msm_clk_notif_unregister - remove a clk rate change notifier + * @clk: struct clk * + * @nb: struct notifier_block * with callback info + * + * Request no further notification for changes to 'clk' and frees memory + * allocated in msm_clk_notifier_register. + * + * Returns -EINVAL if called with null arguments; otherwise, passes + * along the return value of srcu_notifier_chain_unregister(). + */ +int msm_clk_notif_unregister(struct clk *clk, struct notifier_block *nb) +{ + struct msm_clk_notifier *cn = NULL; + int ret = -EINVAL; + + if (!clk || !nb) + return -EINVAL; + + mutex_lock(&clk->prepare_lock); + + list_for_each_entry(cn, &clk_notifier_list, node) + if (cn->clk == clk) + break; + + if (cn->clk == clk) { + ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb); + + clk->notifier_count--; + + /* XXX the notifier code should handle this better */ + if (!cn->notifier_head.head) { + srcu_cleanup_notifier_head(&cn->notifier_head); + list_del(&cn->node); + kfree(cn); + } + + } else { + ret = -ENOENT; + } + + mutex_unlock(&clk->prepare_lock); + + return ret; +} + +unsigned long clk_get_rate(struct clk *clk) +{ + if (IS_ERR_OR_NULL(clk)) + return 0; + + if (!clk->ops->get_rate) + return clk->rate; + + return clk->ops->get_rate(clk); +} +EXPORT_SYMBOL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long start_rate; + int rc = 0; + const char *name; + + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + name = clk->dbg_name; + + if (!is_rate_valid(clk, rate)) + return -EINVAL; + + mutex_lock(&clk->prepare_lock); + + /* Return early if the rate isn't going to change */ + if (clk->rate == rate && !(clk->flags & CLKFLAG_NO_RATE_CACHE)) + goto out; + + if (!clk->ops->set_rate) { + rc = -EINVAL; + goto out; + } + + trace_clock_set_rate(name, rate, raw_smp_processor_id()); + + start_rate = clk->rate; + + if (clk->notifier_count) + __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, rate); + + if (clk->ops->pre_set_rate) { + rc = clk->ops->pre_set_rate(clk, rate); + if (rc) + goto abort_set_rate; + } + + /* Enforce vdd requirements for target frequency. */ + if (clk->prepare_count) { + rc = vote_rate_vdd(clk, rate); + if (rc) + goto err_vote_vdd; + } + + rc = clk->ops->set_rate(clk, rate); + if (rc) + goto err_set_rate; + clk->rate = rate; + + /* Release vdd requirements for starting frequency. */ + if (clk->prepare_count) + unvote_rate_vdd(clk, start_rate); + + if (clk->ops->post_set_rate) + clk->ops->post_set_rate(clk, start_rate); + + if (clk->notifier_count) + __clk_notify(clk, POST_RATE_CHANGE, start_rate, clk->rate); + + trace_clock_set_rate_complete(name, clk->rate, raw_smp_processor_id()); +out: + mutex_unlock(&clk->prepare_lock); + return rc; + +abort_set_rate: + __clk_notify(clk, ABORT_RATE_CHANGE, clk->rate, rate); +err_set_rate: + if (clk->prepare_count) + unvote_rate_vdd(clk, rate); +err_vote_vdd: + /* clk->rate is still the old rate. So, pass the new rate instead. */ + if (clk->ops->post_set_rate) + clk->ops->post_set_rate(clk, rate); + goto out; +} +EXPORT_SYMBOL(clk_set_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + long rrate; + unsigned long fmax = 0, i; + + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + + for (i = 0; i < clk->num_fmax; i++) + fmax = max(fmax, clk->fmax[i]); + if (!fmax) + fmax = ULONG_MAX; + rate = min(rate, fmax); + + if (clk->ops->round_rate) + rrate = clk->ops->round_rate(clk, rate); + else if (clk->rate) + rrate = clk->rate; + else + return -EINVAL; + + if (rrate > fmax) + return -EINVAL; + return rrate; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_max_rate(struct clk *clk, unsigned long rate) +{ + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + + if (!clk->ops->set_max_rate) + return -EINVAL; + + return clk->ops->set_max_rate(clk, rate); +} +EXPORT_SYMBOL(clk_set_max_rate); + +int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p) +{ + int i; + + for (i = 0; i < num_parents; i++) { + if (parents[i].src == p) + return parents[i].sel; + } + + return -EINVAL; +} +EXPORT_SYMBOL(parent_to_src_sel); + +int clk_get_parent_sel(struct clk *c, struct clk *parent) +{ + return parent_to_src_sel(c->parents, c->num_parents, parent); +} +EXPORT_SYMBOL(clk_get_parent_sel); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int rc = 0; + + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + + if (!clk->ops->set_parent && clk->parent == parent) + return 0; + + if (!clk->ops->set_parent) + return -EINVAL; + + mutex_lock(&clk->prepare_lock); + if (clk->parent == parent && !(clk->flags & CLKFLAG_NO_RATE_CACHE)) + goto out; + rc = clk->ops->set_parent(clk, parent); +out: + mutex_unlock(&clk->prepare_lock); + + return rc; +} +EXPORT_SYMBOL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *clk) +{ + if (IS_ERR_OR_NULL(clk)) + return NULL; + + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_flags(struct clk *clk, unsigned long flags) +{ + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + if (!clk->ops->set_flags) + return -EINVAL; + + return clk->ops->set_flags(clk, flags); +} +EXPORT_SYMBOL(clk_set_flags); + +int clk_set_duty_cycle(struct clk *clk, u32 numerator, u32 denominator) +{ + if (IS_ERR_OR_NULL(clk)) + return -EINVAL; + + if (numerator > denominator) { + pr_err("Numerator cannot be > denominator\n"); + return -EINVAL; + } + + if (!denominator) { + pr_err("Denominator can not be Zero\n"); + return -EINVAL; + } + + if (!clk->ops->set_duty_cycle) + return -EINVAL; + + return clk->ops->set_duty_cycle(clk, numerator, denominator); +} +EXPORT_SYMBOL(clk_set_duty_cycle); + +static LIST_HEAD(initdata_list); + +static void init_sibling_lists(struct clk_lookup *clock_tbl, size_t num_clocks) +{ + struct clk *clk, *parent; + unsigned long n; + + for (n = 0; n < num_clocks; n++) { + clk = clock_tbl[n].clk; + parent = clk->parent; + if (parent && list_empty(&clk->siblings)) + list_add(&clk->siblings, &parent->children); + } +} + +static void vdd_class_init(struct clk_vdd_class *vdd) +{ + struct handoff_vdd *v; + + if (!vdd) + return; + + if (vdd->skip_handoff) + return; + + list_for_each_entry(v, &handoff_vdd_list, list) { + if (v->vdd_class == vdd) + return; + } + + pr_debug("voting for vdd_class %s\n", vdd->class_name); + if (vote_vdd_level(vdd, vdd->num_levels - 1)) + pr_err("failed to vote for %s\n", vdd->class_name); + + v = kmalloc(sizeof(*v), GFP_KERNEL); + if (!v) + return; + + v->vdd_class = vdd; + list_add_tail(&v->list, &handoff_vdd_list); +} + +static int __handoff_clk(struct clk *clk) +{ + enum handoff state = HANDOFF_DISABLED_CLK; + struct handoff_clk *h = NULL; + int rc, i; + + if (clk == NULL || clk->flags & CLKFLAG_INIT_DONE || + clk->flags & CLKFLAG_SKIP_HANDOFF) + return 0; + + if (clk->flags & CLKFLAG_INIT_ERR) + return -ENXIO; + + if (clk->flags & CLKFLAG_EPROBE_DEFER) + return -EPROBE_DEFER; + + /* Handoff any 'depends' clock first. */ + rc = __handoff_clk(clk->depends); + if (rc) + goto err; + + /* + * Handoff functions for the parent must be called before the + * children can be handed off. Without handing off the parents and + * knowing their rate and state (on/off), it's impossible to figure + * out the rate and state of the children. + */ + if (clk->ops->get_parent) + clk->parent = clk->ops->get_parent(clk); + + if (IS_ERR(clk->parent)) { + rc = PTR_ERR(clk->parent); + goto err; + } + + rc = __handoff_clk(clk->parent); + if (rc) + goto err; + + for (i = 0; i < clk->num_parents; i++) { + rc = __handoff_clk(clk->parents[i].src); + if (rc) + goto err; + } + + if (clk->ops->handoff) + state = clk->ops->handoff(clk); + + if (state == HANDOFF_ENABLED_CLK) { + + h = kmalloc(sizeof(*h), GFP_KERNEL); + if (!h) { + rc = -ENOMEM; + goto err; + } + + rc = clk_prepare_enable(clk->parent); + if (rc) + goto err; + + rc = clk_prepare_enable(clk->depends); + if (rc) + goto err_depends; + + rc = vote_rate_vdd(clk, clk->rate); + WARN(rc, "%s unable to vote for voltage!\n", clk->dbg_name); + + clk->count = 1; + clk->prepare_count = 1; + h->clk = clk; + list_add_tail(&h->list, &handoff_list); + + pr_debug("Handed off %s rate=%lu\n", clk->dbg_name, clk->rate); + } + + if (clk->init_rate && clk_set_rate(clk, clk->init_rate)) + pr_err("failed to set an init rate of %lu on %s\n", + clk->init_rate, clk->dbg_name); + if (clk->always_on && clk_prepare_enable(clk)) + pr_err("failed to enable always-on clock %s\n", + clk->dbg_name); + + clk->flags |= CLKFLAG_INIT_DONE; + /* if the clk is on orphan list, remove it */ + list_del_init(&clk->list); + clock_debug_register(clk); + + return 0; + +err_depends: + clk_disable_unprepare(clk->parent); +err: + kfree(h); + if (rc == -EPROBE_DEFER) { + clk->flags |= CLKFLAG_EPROBE_DEFER; + if (list_empty(&clk->list)) + list_add_tail(&clk->list, &orphan_clk_list); + } else { + pr_err("%s handoff failed (%d)\n", clk->dbg_name, rc); + clk->flags |= CLKFLAG_INIT_ERR; + } + return rc; +} + +/** + * msm_clock_register() - Register additional clock tables + * @table: Table of clocks + * @size: Size of @table + * + * Upon return, clock APIs may be used to control clocks registered using this + * function. + */ +int msm_clock_register(struct clk_lookup *table, size_t size) +{ + int n = 0, rc; + struct clk *c, *safe; + bool found_more_clks; + + mutex_lock(&msm_clock_init_lock); + + init_sibling_lists(table, size); + + /* + * Enable regulators and temporarily set them up at maximum voltage. + * Once all the clocks have made their respective vote, remove this + * temporary vote. The removing of the temporary vote is done at + * late_init, by which time we assume all the clocks would have been + * handed off. + */ + for (n = 0; n < size; n++) + vdd_class_init(table[n].clk->vdd_class); + + /* + * Detect and preserve initial clock state until clock_late_init() or + * a driver explicitly changes it, whichever is first. + */ + + for (n = 0; n < size; n++) + __handoff_clk(table[n].clk); + + /* maintain backwards compatibility */ + if (table[0].con_id || table[0].dev_id) + clkdev_add_table(table, size); + + do { + found_more_clks = false; + /* clear cached __handoff_clk return values */ + list_for_each_entry_safe(c, safe, &orphan_clk_list, list) + c->flags &= ~CLKFLAG_EPROBE_DEFER; + + list_for_each_entry_safe(c, safe, &orphan_clk_list, list) { + rc = __handoff_clk(c); + if (!rc) + found_more_clks = true; + } + } while (found_more_clks); + + mutex_unlock(&msm_clock_init_lock); + + return 0; +} +EXPORT_SYMBOL(msm_clock_register); + +struct of_msm_provider_data { + struct clk_lookup *table; + size_t size; +}; + +static struct clk *of_clk_src_get(struct of_phandle_args *clkspec, + void *data) +{ + struct of_msm_provider_data *ofdata = data; + int n; + + for (n = 0; n < ofdata->size; n++) { + if (clkspec->args[0] == ofdata->table[n].of_idx) + return ofdata->table[n].clk; + } + return ERR_PTR(-ENOENT); +} + +#define MAX_LEN_OPP_HANDLE 50 +#define LEN_OPP_HANDLE 16 +#define LEN_OPP_VCORNER_HANDLE 22 + +static struct device **derive_device_list(struct clk *clk, + struct device_node *np, + char *clk_handle_name, int len) +{ + int j, count, cpu; + struct platform_device *pdev; + struct device_node *dev_node; + struct device **device_list; + + count = len/sizeof(u32); + device_list = kmalloc_array(count, sizeof(struct device *), + GFP_KERNEL); + if (!device_list) + return ERR_PTR(-ENOMEM); + + for (j = 0; j < count; j++) { + device_list[j] = NULL; + dev_node = of_parse_phandle(np, clk_handle_name, j); + if (!dev_node) { + pr_err("Unable to get device_node pointer for %s opp-handle (%s)\n", + clk->dbg_name, clk_handle_name); + goto err_parse_phandle; + } + + for_each_possible_cpu(cpu) { + if (of_get_cpu_node(cpu, NULL) == dev_node) + device_list[j] = get_cpu_device(cpu); + } + + if (device_list[j]) + continue; + + pdev = of_find_device_by_node(dev_node); + if (!pdev) { + pr_err("Unable to find platform_device node for %s opp-handle\n", + clk->dbg_name); + goto err_parse_phandle; + } + device_list[j] = &pdev->dev; + } + return device_list; +err_parse_phandle: + kfree(device_list); + return ERR_PTR(-EINVAL); +} + +static int get_voltage(struct clk *clk, unsigned long rate, + int store_vcorner, int n) +{ + struct clk_vdd_class *vdd; + int uv, level, corner; + + /* + * Use the first regulator in the vdd class + * for the OPP table. + */ + vdd = clk->vdd_class; + if (vdd->num_regulators > 1) { + corner = vdd->vdd_uv[vdd->num_regulators * n]; + } else { + level = find_vdd_level(clk, rate); + if (level < 0) { + pr_err("Could not find vdd level\n"); + return -EINVAL; + } + corner = vdd->vdd_uv[level]; + } + + if (!corner) { + pr_err("%s: Unable to find vdd level for rate %lu\n", + clk->dbg_name, rate); + return -EINVAL; + } + + if (store_vcorner) { + uv = corner; + return uv; + } + + uv = regulator_list_corner_voltage(vdd->regulator[0], corner); + if (uv < 0) { + pr_err("%s: no uv for corner %d - err: %d\n", + clk->dbg_name, corner, uv); + return uv; + } + return uv; +} + +static int add_and_print_opp(struct clk *clk, struct device **device_list, + int count, unsigned long rate, int uv, int n) +{ + int j, ret = 0; + + for (j = 0; j < count; j++) { + ret = dev_pm_opp_add(device_list[j], rate, uv); + if (ret) { + pr_err("%s: couldn't add OPP for %lu - err: %d\n", + clk->dbg_name, rate, ret); + return ret; + } + if (n == 1 || n == clk->num_fmax - 1 || + rate == clk_round_rate(clk, INT_MAX)) + pr_info("%s: set OPP pair(%lu Hz: %u uV) on %s\n", + clk->dbg_name, rate, uv, + dev_name(device_list[j])); + } + return ret; +} + +static void populate_clock_opp_table(struct device_node *np, + struct clk_lookup *table, size_t size) +{ + struct device **device_list; + struct clk *clk; + char clk_handle_name[MAX_LEN_OPP_HANDLE]; + char clk_store_volt_corner[MAX_LEN_OPP_HANDLE]; + size_t i; + int n, len, count, uv = 0; + unsigned long rate, ret = 0; + bool store_vcorner; + + /* Iterate across all clocks in the clock controller */ + for (i = 0; i < size; i++) { + n = 1; + rate = 0; + + store_vcorner = false; + clk = table[i].clk; + if (!clk || !clk->num_fmax || clk->opp_table_populated) + continue; + + if (strlen(clk->dbg_name) + LEN_OPP_HANDLE + < MAX_LEN_OPP_HANDLE) { + ret = snprintf(clk_handle_name, + ARRAY_SIZE(clk_handle_name), + "qcom,%s-opp-handle", clk->dbg_name); + if (ret < strlen(clk->dbg_name) + LEN_OPP_HANDLE) { + pr_err("Failed to hold clk_handle_name\n"); + continue; + } + } else { + pr_err("clk name (%s) too large to fit in clk_handle_name\n", + clk->dbg_name); + continue; + } + + if (strlen(clk->dbg_name) + LEN_OPP_VCORNER_HANDLE + < MAX_LEN_OPP_HANDLE) { + ret = snprintf(clk_store_volt_corner, + ARRAY_SIZE(clk_store_volt_corner), + "qcom,%s-opp-store-vcorner", clk->dbg_name); + if (ret < strlen(clk->dbg_name) + + LEN_OPP_VCORNER_HANDLE) { + pr_err("Failed to hold clk_store_volt_corner\n"); + continue; + } + } else { + pr_err("clk name (%s) too large to fit in clk_store_volt_corner\n", + clk->dbg_name); + continue; + } + + if (!of_find_property(np, clk_handle_name, &len)) { + pr_debug("Unable to find %s\n", clk_handle_name); + if (!of_find_property(np, clk_store_volt_corner, + &len)) { + pr_debug("Unable to find %s\n", + clk_store_volt_corner); + continue; + } else { + store_vcorner = true; + device_list = derive_device_list(clk, np, + clk_store_volt_corner, len); + } + } else + device_list = derive_device_list(clk, np, + clk_handle_name, len); + if (IS_ERR_OR_NULL(device_list)) { + pr_err("Failed to fill device_list\n"); + continue; + } + + count = len/sizeof(u32); + while (1) { + /* + * Calling clk_round_rate will not work for all clocks + * (eg. mux_div). Use their fmax values instead to get + * list of all available frequencies. + */ + if (clk->ops->list_rate) { + ret = clk_round_rate(clk, rate + 1); + if (ret < 0) { + pr_err("clk_round_rate failed for %s\n", + clk->dbg_name); + goto err_round_rate; + } + /* + * If clk_round_rate give the same value on + * consecutive iterations, exit loop since + * we're at the maximum clock frequency. + */ + if (rate == ret) + break; + rate = ret; + } else { + if (n < clk->num_fmax) + rate = clk->fmax[n]; + else + break; + } + + uv = get_voltage(clk, rate, store_vcorner, n); + if (uv < 0) + goto err_round_rate; + + ret = add_and_print_opp(clk, device_list, count, + rate, uv, n); + if (ret) + goto err_round_rate; + + n++; + } +err_round_rate: + /* If OPP table population was successful, set the flag */ + if (uv >= 0 && ret >= 0) + clk->opp_table_populated = true; + kfree(device_list); + } +} + +/** + * of_msm_clock_register() - Register clock tables with clkdev and with the + * clock DT framework + * @table: Table of clocks + * @size: Size of @table + * @np: Device pointer corresponding to the clock-provider device + * + * Upon return, clock APIs may be used to control clocks registered using this + * function. + */ +int of_msm_clock_register(struct device_node *np, struct clk_lookup *table, + size_t size) +{ + int ret = 0; + struct of_msm_provider_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->table = table; + data->size = size; + + ret = of_clk_add_provider(np, of_clk_src_get, data); + if (ret) { + kfree(data); + return -ENOMEM; + } + + populate_clock_opp_table(np, table, size); + return msm_clock_register(table, size); +} +EXPORT_SYMBOL(of_msm_clock_register); + +/** + * msm_clock_init() - Register and initialize a clock driver + * @data: Driver-specific clock initialization data + * + * Upon return from this call, clock APIs may be used to control + * clocks registered with this API. + */ +int __init msm_clock_init(struct clock_init_data *data) +{ + if (!data) + return -EINVAL; + + if (data->pre_init) + data->pre_init(); + + mutex_lock(&msm_clock_init_lock); + if (data->late_init) + list_add(&data->list, &initdata_list); + mutex_unlock(&msm_clock_init_lock); + + msm_clock_register(data->table, data->size); + + if (data->post_init) + data->post_init(); + + return 0; +} + +static int __init clock_late_init(void) +{ + struct handoff_clk *h, *h_temp; + struct handoff_vdd *v, *v_temp; + struct clock_init_data *initdata, *initdata_temp; + int ret = 0; + + pr_info("%s: Removing enables held for handed-off clocks\n", __func__); + + mutex_lock(&msm_clock_init_lock); + + list_for_each_entry_safe(initdata, initdata_temp, + &initdata_list, list) { + ret = initdata->late_init(); + if (ret) + pr_err("%s: %pS failed late_init.\n", __func__, + initdata); + } + + list_for_each_entry_safe(h, h_temp, &handoff_list, list) { + clk_disable_unprepare(h->clk); + list_del(&h->list); + kfree(h); + } + + list_for_each_entry_safe(v, v_temp, &handoff_vdd_list, list) { + unvote_vdd_level(v->vdd_class, v->vdd_class->num_levels - 1); + list_del(&v->list); + kfree(v); + } + + mutex_unlock(&msm_clock_init_lock); + + return ret; +} +/* clock_late_init should run only after all deferred probing + * (excluding DLKM probes) has completed. + */ +late_initcall_sync(clock_late_init); diff --git a/drivers/clk/msm/clock.h b/drivers/clk/msm/clock.h new file mode 100644 index 0000000000000000000000000000000000000000..f8c6fbff97c3c90b896c98510598ada1e6721353 --- /dev/null +++ b/drivers/clk/msm/clock.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DRIVERS_CLK_MSM_CLOCK_H +#define __DRIVERS_CLK_MSM_CLOCK_H + +#include + +/** + * struct clock_init_data - SoC specific clock initialization data + * @table: table of lookups to add + * @size: size of @table + * @pre_init: called before initializing the clock driver. + * @post_init: called after registering @table. clock APIs can be called inside. + * @late_init: called during late init + */ +struct clock_init_data { + struct list_head list; + struct clk_lookup *table; + size_t size; + void (*pre_init)(void); + void (*post_init)(void); + int (*late_init)(void); +}; + +int msm_clock_init(struct clock_init_data *data); +int find_vdd_level(struct clk *clk, unsigned long rate); +extern struct list_head orphan_clk_list; + +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMMON_CLK_MSM) +int clock_debug_register(struct clk *clk); +void clock_debug_print_enabled(bool print_parent); +#elif defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMMON_CLK_QCOM) +void clock_debug_print_enabled(bool print_parent); +#else +static inline int clock_debug_register(struct clk *unused) +{ + return 0; +} +static inline void clock_debug_print_enabled(void) { return; } +#endif + +#endif diff --git a/drivers/clk/msm/gdsc.c b/drivers/clk/msm/gdsc.c new file mode 100644 index 0000000000000000000000000000000000000000..e24795e2ae285cfc13ee86f3057f2cbf49f213e4 --- /dev/null +++ b/drivers/clk/msm/gdsc.c @@ -0,0 +1,721 @@ +/* + * Copyright (c) 2012-2017, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PWR_ON_MASK BIT(31) +#define EN_REST_WAIT_MASK (0xF << 20) +#define EN_FEW_WAIT_MASK (0xF << 16) +#define CLK_DIS_WAIT_MASK (0xF << 12) +#define SW_OVERRIDE_MASK BIT(2) +#define HW_CONTROL_MASK BIT(1) +#define SW_COLLAPSE_MASK BIT(0) +#define GMEM_CLAMP_IO_MASK BIT(0) +#define GMEM_RESET_MASK BIT(4) +#define BCR_BLK_ARES_BIT BIT(0) + +/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ +#define EN_REST_WAIT_VAL (0x2 << 20) +#define EN_FEW_WAIT_VAL (0x8 << 16) +#define CLK_DIS_WAIT_VAL (0x2 << 12) + +#define TIMEOUT_US 100 + +struct gdsc { + struct regulator_dev *rdev; + struct regulator_desc rdesc; + void __iomem *gdscr; + struct clk **clocks; + struct reset_control **reset_clocks; + int clock_count; + int reset_count; + bool toggle_mem; + bool toggle_periph; + bool toggle_logic; + bool resets_asserted; + bool root_en; + bool force_root_en; + int root_clk_idx; + bool no_status_check_on_disable; + bool is_gdsc_enabled; + bool allow_clear; + bool reset_aon; + void __iomem *domain_addr; + void __iomem *hw_ctrl_addr; + void __iomem *sw_reset_addr; + u32 gds_timeout; +}; + +enum gdscr_status { + ENABLED, + DISABLED, +}; + +static DEFINE_MUTEX(gdsc_seq_lock); + +void gdsc_allow_clear_retention(struct regulator *regulator) +{ + struct gdsc *sc = regulator_get_drvdata(regulator); + + if (sc) + sc->allow_clear = true; +} + +static int poll_gdsc_status(struct gdsc *sc, enum gdscr_status status) +{ + void __iomem *gdscr; + int count = sc->gds_timeout; + u32 val; + + if (sc->hw_ctrl_addr) + gdscr = sc->hw_ctrl_addr; + else + gdscr = sc->gdscr; + + for (; count > 0; count--) { + val = readl_relaxed(gdscr); + val &= PWR_ON_MASK; + switch (status) { + case ENABLED: + if (val) + return 0; + break; + case DISABLED: + if (!val) + return 0; + break; + } + /* + * There is no guarantee about the delay needed for the enable + * bit in the GDSCR to be set or reset after the GDSC state + * changes. Hence, keep on checking for a reasonable number + * of times until the bit is set with the least possible delay + * between succeessive tries. + */ + udelay(1); + } + return -ETIMEDOUT; +} + +static int gdsc_is_enabled(struct regulator_dev *rdev) +{ + struct gdsc *sc = rdev_get_drvdata(rdev); + uint32_t regval; + + if (!sc->toggle_logic) + return !sc->resets_asserted; + + regval = readl_relaxed(sc->gdscr); + if (regval & PWR_ON_MASK) { + /* + * The GDSC might be turned on due to TZ/HYP vote on the + * votable GDS registers. Check the SW_COLLAPSE_MASK to + * determine if HLOS has voted for it. + */ + if (!(regval & SW_COLLAPSE_MASK)) + return true; + } + return false; +} + +static int gdsc_enable(struct regulator_dev *rdev) +{ + struct gdsc *sc = rdev_get_drvdata(rdev); + uint32_t regval, hw_ctrl_regval = 0x0; + int i, ret = 0; + + mutex_lock(&gdsc_seq_lock); + + if (sc->root_en || sc->force_root_en) + clk_prepare_enable(sc->clocks[sc->root_clk_idx]); + + if (sc->toggle_logic) { + if (sc->sw_reset_addr) { + regval = readl_relaxed(sc->sw_reset_addr); + regval |= BCR_BLK_ARES_BIT; + writel_relaxed(regval, sc->sw_reset_addr); + /* + * BLK_ARES should be kept asserted for 1us before + * being de-asserted. + */ + wmb(); + udelay(1); + + regval &= ~BCR_BLK_ARES_BIT; + writel_relaxed(regval, sc->sw_reset_addr); + + /* Make sure de-assert goes through before continuing */ + wmb(); + } + + if (sc->domain_addr) { + if (sc->reset_aon) { + regval = readl_relaxed(sc->domain_addr); + regval |= GMEM_RESET_MASK; + writel_relaxed(regval, sc->domain_addr); + /* + * Keep reset asserted for at-least 1us before + * continuing. + */ + wmb(); + udelay(1); + + regval &= ~GMEM_RESET_MASK; + writel_relaxed(regval, sc->domain_addr); + /* + * Make sure GMEM_RESET is de-asserted before + * continuing. + */ + wmb(); + } + + regval = readl_relaxed(sc->domain_addr); + regval &= ~GMEM_CLAMP_IO_MASK; + writel_relaxed(regval, sc->domain_addr); + /* + * Make sure CLAMP_IO is de-asserted before continuing. + */ + wmb(); + } + + regval = readl_relaxed(sc->gdscr); + if (regval & HW_CONTROL_MASK) { + dev_warn(&rdev->dev, "Invalid enable while %s is under HW control\n", + sc->rdesc.name); + mutex_unlock(&gdsc_seq_lock); + return -EBUSY; + } + + regval &= ~SW_COLLAPSE_MASK; + writel_relaxed(regval, sc->gdscr); + + /* Wait for 8 XO cycles before polling the status bit. */ + mb(); + udelay(1); + + ret = poll_gdsc_status(sc, ENABLED); + if (ret) { + regval = readl_relaxed(sc->gdscr); + if (sc->hw_ctrl_addr) { + hw_ctrl_regval = + readl_relaxed(sc->hw_ctrl_addr); + dev_warn(&rdev->dev, "%s state (after %d us timeout): 0x%x, GDS_HW_CTRL: 0x%x. Re-polling.\n", + sc->rdesc.name, sc->gds_timeout, + regval, hw_ctrl_regval); + + ret = poll_gdsc_status(sc, ENABLED); + if (ret) { + dev_err(&rdev->dev, "%s final state (after additional %d us timeout): 0x%x, GDS_HW_CTRL: 0x%x\n", + sc->rdesc.name, sc->gds_timeout, + readl_relaxed(sc->gdscr), + readl_relaxed(sc->hw_ctrl_addr)); + + mutex_unlock(&gdsc_seq_lock); + return ret; + } + } else { + dev_err(&rdev->dev, "%s enable timed out: 0x%x\n", + sc->rdesc.name, + regval); + udelay(sc->gds_timeout); + regval = readl_relaxed(sc->gdscr); + dev_err(&rdev->dev, "%s final state: 0x%x (%d us after timeout)\n", + sc->rdesc.name, regval, + sc->gds_timeout); + mutex_unlock(&gdsc_seq_lock); + return ret; + } + } + } else { + for (i = 0; i < sc->reset_count; i++) + reset_control_deassert(sc->reset_clocks[i]); + sc->resets_asserted = false; + } + + for (i = 0; i < sc->clock_count; i++) { + if (unlikely(i == sc->root_clk_idx)) + continue; + if (sc->toggle_mem) + clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM); + if (sc->toggle_periph) + clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH); + } + + /* + * If clocks to this power domain were already on, they will take an + * additional 4 clock cycles to re-enable after the rail is enabled. + * Delay to account for this. A delay is also needed to ensure clocks + * are not enabled within 400ns of enabling power to the memories. + */ + udelay(1); + + /* Delay to account for staggered memory powerup. */ + udelay(1); + + if (sc->force_root_en) + clk_disable_unprepare(sc->clocks[sc->root_clk_idx]); + sc->is_gdsc_enabled = true; + + mutex_unlock(&gdsc_seq_lock); + + return ret; +} + +static int gdsc_disable(struct regulator_dev *rdev) +{ + struct gdsc *sc = rdev_get_drvdata(rdev); + uint32_t regval; + int i, ret = 0; + + mutex_lock(&gdsc_seq_lock); + + if (sc->force_root_en) + clk_prepare_enable(sc->clocks[sc->root_clk_idx]); + + for (i = sc->clock_count-1; i >= 0; i--) { + if (unlikely(i == sc->root_clk_idx)) + continue; + if (sc->toggle_mem && sc->allow_clear) + clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM); + if (sc->toggle_periph && sc->allow_clear) + clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH); + } + + /* Delay to account for staggered memory powerdown. */ + udelay(1); + + if (sc->toggle_logic) { + regval = readl_relaxed(sc->gdscr); + if (regval & HW_CONTROL_MASK) { + dev_warn(&rdev->dev, "Invalid disable while %s is under HW control\n", + sc->rdesc.name); + mutex_unlock(&gdsc_seq_lock); + return -EBUSY; + } + + regval |= SW_COLLAPSE_MASK; + writel_relaxed(regval, sc->gdscr); + /* Wait for 8 XO cycles before polling the status bit. */ + mb(); + udelay(1); + + if (sc->no_status_check_on_disable) { + /* + * Add a short delay here to ensure that gdsc_enable + * right after it was disabled does not put it in a + * weird state. + */ + udelay(TIMEOUT_US); + } else { + ret = poll_gdsc_status(sc, DISABLED); + if (ret) + dev_err(&rdev->dev, "%s disable timed out: 0x%x\n", + sc->rdesc.name, regval); + } + + if (sc->domain_addr) { + regval = readl_relaxed(sc->domain_addr); + regval |= GMEM_CLAMP_IO_MASK; + writel_relaxed(regval, sc->domain_addr); + /* Make sure CLAMP_IO is asserted before continuing. */ + wmb(); + } + } else { + for (i = sc->reset_count-1; i >= 0; i--) + reset_control_assert(sc->reset_clocks[i]); + sc->resets_asserted = true; + } + + /* + * Check if gdsc_enable was called for this GDSC. If not, the root + * clock will not have been enabled prior to this. + */ + if ((sc->is_gdsc_enabled && sc->root_en) || sc->force_root_en) + clk_disable_unprepare(sc->clocks[sc->root_clk_idx]); + sc->is_gdsc_enabled = false; + + mutex_unlock(&gdsc_seq_lock); + + return ret; +} + +static unsigned int gdsc_get_mode(struct regulator_dev *rdev) +{ + struct gdsc *sc = rdev_get_drvdata(rdev); + uint32_t regval; + + mutex_lock(&gdsc_seq_lock); + regval = readl_relaxed(sc->gdscr); + mutex_unlock(&gdsc_seq_lock); + if (regval & HW_CONTROL_MASK) + return REGULATOR_MODE_FAST; + return REGULATOR_MODE_NORMAL; +} + +static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct gdsc *sc = rdev_get_drvdata(rdev); + uint32_t regval; + int ret = 0; + + mutex_lock(&gdsc_seq_lock); + + regval = readl_relaxed(sc->gdscr); + + /* + * HW control can only be enable/disabled when SW_COLLAPSE + * indicates on. + */ + if (regval & SW_COLLAPSE_MASK) { + dev_err(&rdev->dev, "can't enable hw collapse now\n"); + mutex_unlock(&gdsc_seq_lock); + return -EBUSY; + } + + switch (mode) { + case REGULATOR_MODE_FAST: + /* Turn on HW trigger mode */ + regval |= HW_CONTROL_MASK; + writel_relaxed(regval, sc->gdscr); + /* + * There may be a race with internal HW trigger signal, + * that will result in GDSC going through a power down and + * up cycle. In case HW trigger signal is controlled by + * firmware that also poll same status bits as we do, FW + * might read an 'on' status before the GDSC can finish + * power cycle. We wait 1us before returning to ensure + * FW can't immediately poll the status bit. + */ + mb(); + udelay(1); + break; + + case REGULATOR_MODE_NORMAL: + /* Turn off HW trigger mode */ + regval &= ~HW_CONTROL_MASK; + writel_relaxed(regval, sc->gdscr); + /* + * There may be a race with internal HW trigger signal, + * that will result in GDSC going through a power down and + * up cycle. If we poll too early, status bit will + * indicate 'on' before the GDSC can finish the power cycle. + * Account for this case by waiting 1us before polling. + */ + mb(); + udelay(1); + + ret = poll_gdsc_status(sc, ENABLED); + if (ret) + dev_err(&rdev->dev, "%s set_mode timed out: 0x%x\n", + sc->rdesc.name, regval); + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&gdsc_seq_lock); + + return ret; +} + +static struct regulator_ops gdsc_ops = { + .is_enabled = gdsc_is_enabled, + .enable = gdsc_enable, + .disable = gdsc_disable, + .set_mode = gdsc_set_mode, + .get_mode = gdsc_get_mode, +}; + +static int gdsc_probe(struct platform_device *pdev) +{ + static atomic_t gdsc_count = ATOMIC_INIT(-1); + struct regulator_config reg_config = {}; + struct regulator_init_data *init_data; + struct resource *res; + struct gdsc *sc; + uint32_t regval, clk_dis_wait_val = CLK_DIS_WAIT_VAL; + bool retain_mem, retain_periph, support_hw_trigger; + int i, ret; + u32 timeout; + + sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL); + if (sc == NULL) + return -ENOMEM; + + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, + &sc->rdesc); + if (init_data == NULL) + return -ENOMEM; + + if (of_get_property(pdev->dev.of_node, "parent-supply", NULL)) + init_data->supply_regulator = "parent"; + + ret = of_property_read_string(pdev->dev.of_node, "regulator-name", + &sc->rdesc.name); + if (ret) + return ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -EINVAL; + sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (sc->gdscr == NULL) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "domain_addr"); + if (res) { + sc->domain_addr = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (sc->domain_addr == NULL) + return -ENOMEM; + } + + sc->reset_aon = of_property_read_bool(pdev->dev.of_node, + "qcom,reset-aon-logic"); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "sw_reset"); + if (res) { + sc->sw_reset_addr = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (sc->sw_reset_addr == NULL) + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "hw_ctrl_addr"); + if (res) { + sc->hw_ctrl_addr = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (sc->hw_ctrl_addr == NULL) + return -ENOMEM; + } + + sc->gds_timeout = TIMEOUT_US; + ret = of_property_read_u32(pdev->dev.of_node, "qcom,gds-timeout", + &timeout); + if (!ret) + sc->gds_timeout = timeout; + + sc->clock_count = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if (sc->clock_count == -EINVAL) { + sc->clock_count = 0; + } else if (IS_ERR_VALUE((unsigned long)sc->clock_count)) { + dev_err(&pdev->dev, "Failed to get clock names\n"); + return -EINVAL; + } + + sc->clocks = devm_kzalloc(&pdev->dev, + sizeof(struct clk *) * sc->clock_count, GFP_KERNEL); + if (!sc->clocks) + return -ENOMEM; + + sc->root_clk_idx = -1; + + sc->root_en = of_property_read_bool(pdev->dev.of_node, + "qcom,enable-root-clk"); + sc->force_root_en = of_property_read_bool(pdev->dev.of_node, + "qcom,force-enable-root-clk"); + for (i = 0; i < sc->clock_count; i++) { + const char *clock_name; + + of_property_read_string_index(pdev->dev.of_node, "clock-names", + i, &clock_name); + sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name); + if (IS_ERR(sc->clocks[i])) { + int rc = PTR_ERR(sc->clocks[i]); + + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get %s\n", + clock_name); + return rc; + } + + if (!strcmp(clock_name, "core_root_clk")) + sc->root_clk_idx = i; + } + + if ((sc->root_en || sc->force_root_en) && (sc->root_clk_idx == -1)) { + dev_err(&pdev->dev, "Failed to get root clock name\n"); + return -EINVAL; + } + + sc->rdesc.id = atomic_inc_return(&gdsc_count); + sc->rdesc.ops = &gdsc_ops; + sc->rdesc.type = REGULATOR_VOLTAGE; + sc->rdesc.owner = THIS_MODULE; + platform_set_drvdata(pdev, sc); + + /* + * Disable HW trigger: collapse/restore occur based on registers writes. + * Disable SW override: Use hardware state-machine for sequencing. + */ + regval = readl_relaxed(sc->gdscr); + regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK); + + if (!of_property_read_u32(pdev->dev.of_node, "qcom,clk-dis-wait-val", + &clk_dis_wait_val)) + clk_dis_wait_val = clk_dis_wait_val << 12; + + /* Configure wait time between states. */ + regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK); + regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | clk_dis_wait_val; + writel_relaxed(regval, sc->gdscr); + + sc->no_status_check_on_disable = + of_property_read_bool(pdev->dev.of_node, + "qcom,no-status-check-on-disable"); + retain_mem = of_property_read_bool(pdev->dev.of_node, + "qcom,retain-mem"); + sc->toggle_mem = !retain_mem; + retain_periph = of_property_read_bool(pdev->dev.of_node, + "qcom,retain-periph"); + sc->toggle_periph = !retain_periph; + sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node, + "qcom,skip-logic-collapse"); + support_hw_trigger = of_property_read_bool(pdev->dev.of_node, + "qcom,support-hw-trigger"); + if (support_hw_trigger) { + init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE; + init_data->constraints.valid_modes_mask |= + REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST; + } + + if (!sc->toggle_logic) { + sc->reset_count = of_property_count_strings(pdev->dev.of_node, + "reset-names"); + if (sc->reset_count == -EINVAL) { + sc->reset_count = 0; + } else if (IS_ERR_VALUE((unsigned long)sc->reset_count)) { + dev_err(&pdev->dev, "Failed to get reset reset names\n"); + return -EINVAL; + } + + sc->reset_clocks = devm_kzalloc(&pdev->dev, + sizeof(struct reset_control *) * + sc->reset_count, + GFP_KERNEL); + if (!sc->reset_clocks) + return -ENOMEM; + + for (i = 0; i < sc->reset_count; i++) { + const char *reset_name; + + of_property_read_string_index(pdev->dev.of_node, + "reset-names", i, &reset_name); + sc->reset_clocks[i] = devm_reset_control_get(&pdev->dev, + reset_name); + if (IS_ERR(sc->reset_clocks[i])) { + int rc = PTR_ERR(sc->reset_clocks[i]); + + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get %s\n", + reset_name); + return rc; + } + } + + regval &= ~SW_COLLAPSE_MASK; + writel_relaxed(regval, sc->gdscr); + + ret = poll_gdsc_status(sc, ENABLED); + if (ret) { + dev_err(&pdev->dev, "%s enable timed out: 0x%x\n", + sc->rdesc.name, regval); + return ret; + } + } + + sc->allow_clear = of_property_read_bool(pdev->dev.of_node, + "qcom,disallow-clear"); + sc->allow_clear = !sc->allow_clear; + + for (i = 0; i < sc->clock_count; i++) { + if (retain_mem || (regval & PWR_ON_MASK) || !sc->allow_clear) + clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM); + else + clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM); + + if (retain_periph || (regval & PWR_ON_MASK) || !sc->allow_clear) + clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH); + else + clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH); + } + + reg_config.dev = &pdev->dev; + reg_config.init_data = init_data; + reg_config.driver_data = sc; + reg_config.of_node = pdev->dev.of_node; + sc->rdev = regulator_register(&sc->rdesc, ®_config); + if (IS_ERR(sc->rdev)) { + dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n", + sc->rdesc.name); + return PTR_ERR(sc->rdev); + } + + return 0; +} + +static int gdsc_remove(struct platform_device *pdev) +{ + struct gdsc *sc = platform_get_drvdata(pdev); + + regulator_unregister(sc->rdev); + return 0; +} + +static const struct of_device_id gdsc_match_table[] = { + { .compatible = "qcom,gdsc" }, + {} +}; + +static struct platform_driver gdsc_driver = { + .probe = gdsc_probe, + .remove = gdsc_remove, + .driver = { + .name = "gdsc", + .of_match_table = gdsc_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init gdsc_init(void) +{ + return platform_driver_register(&gdsc_driver); +} +subsys_initcall(gdsc_init); + +static void __exit gdsc_exit(void) +{ + platform_driver_unregister(&gdsc_driver); +} +module_exit(gdsc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM8974 GDSC power rail regulator driver"); diff --git a/drivers/clk/msm/msm-clock-controller.c b/drivers/clk/msm/msm-clock-controller.c new file mode 100644 index 0000000000000000000000000000000000000000..82ffb6edb2bb6b4cbd5467da7ec3a429a02703f1 --- /dev/null +++ b/drivers/clk/msm/msm-clock-controller.c @@ -0,0 +1,748 @@ +/* + * Copyright (c) 2014, 2016-2017, 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) "msmclock: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Protects list operations */ +static DEFINE_MUTEX(msmclk_lock); +static LIST_HEAD(msmclk_parser_list); +static u32 msmclk_debug; + +struct hitem { + struct hlist_node list; + phandle key; + void *ptr; +}; + +int of_property_count_phandles(struct device_node *np, char *propname) +{ + const __be32 *phandle; + int size; + + phandle = of_get_property(np, propname, &size); + return phandle ? (size / sizeof(*phandle)) : -EINVAL; +} +EXPORT_SYMBOL(of_property_count_phandles); + +int of_property_read_phandle_index(struct device_node *np, char *propname, + int index, phandle *p) +{ + const __be32 *phandle; + int size; + + phandle = of_get_property(np, propname, &size); + if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) + return -EINVAL; + + *p = be32_to_cpup(phandle + index); + return 0; +} +EXPORT_SYMBOL(of_property_read_phandle_index); + +static int generic_vdd_parse_regulators(struct device *dev, + struct clk_vdd_class *vdd, struct device_node *np) +{ + int num_regulators, i, rc; + char *name = "qcom,regulators"; + + num_regulators = of_property_count_phandles(np, name); + if (num_regulators <= 0) { + dt_prop_err(np, name, "missing dt property\n"); + return -EINVAL; + } + + vdd->regulator = devm_kzalloc(dev, + sizeof(*vdd->regulator) * num_regulators, + GFP_KERNEL); + if (!vdd->regulator) { + dt_err(np, "memory alloc failure\n"); + return -ENOMEM; + } + + for (i = 0; i < num_regulators; i++) { + phandle p; + + rc = of_property_read_phandle_index(np, name, i, &p); + if (rc) { + dt_prop_err(np, name, "unable to read phandle\n"); + return rc; + } + + vdd->regulator[i] = msmclk_parse_phandle(dev, p); + if (IS_ERR(vdd->regulator[i])) { + dt_prop_err(np, name, "hashtable lookup failed\n"); + return PTR_ERR(vdd->regulator[i]); + } + } + + vdd->num_regulators = num_regulators; + return 0; +} + +static int generic_vdd_parse_levels(struct device *dev, + struct clk_vdd_class *vdd, struct device_node *np) +{ + int len, rc; + char *name = "qcom,uV-levels"; + + if (!of_find_property(np, name, &len)) { + dt_prop_err(np, name, "missing dt property\n"); + return -EINVAL; + } + + len /= sizeof(u32); + if (len % vdd->num_regulators) { + dt_err(np, "mismatch beween qcom,uV-levels and qcom,regulators dt properties\n"); + return -EINVAL; + } + + vdd->num_levels = len / vdd->num_regulators; + vdd->vdd_uv = devm_kzalloc(dev, len * sizeof(*vdd->vdd_uv), + GFP_KERNEL); + vdd->level_votes = devm_kzalloc(dev, + vdd->num_levels * sizeof(*vdd->level_votes), + GFP_KERNEL); + + if (!vdd->vdd_uv || !vdd->level_votes) { + dt_err(np, "memory alloc failure\n"); + return -ENOMEM; + } + + rc = of_property_read_u32_array(np, name, vdd->vdd_uv, + vdd->num_levels * vdd->num_regulators); + if (rc) { + dt_prop_err(np, name, "unable to read u32 array\n"); + return -EINVAL; + } + + /* Optional Property */ + name = "qcom,uA-levels"; + if (!of_find_property(np, name, &len)) + return 0; + + len /= sizeof(u32); + if (len / vdd->num_regulators != vdd->num_levels) { + dt_err(np, "size of qcom,uA-levels and qcom,uV-levels must match\n"); + return -EINVAL; + } + + vdd->vdd_ua = devm_kzalloc(dev, len * sizeof(*vdd->vdd_ua), + GFP_KERNEL); + if (!vdd->vdd_ua) + return -ENOMEM; + + rc = of_property_read_u32_array(np, name, vdd->vdd_ua, + vdd->num_levels * vdd->num_regulators); + if (rc) { + dt_prop_err(np, name, "unable to read u32 array\n"); + return -EINVAL; + } + + return 0; +} + +static void *simple_vdd_class_dt_parser(struct device *dev, + struct device_node *np) +{ + struct clk_vdd_class *vdd; + int rc = 0; + + vdd = devm_kzalloc(dev, sizeof(*vdd), GFP_KERNEL); + if (!vdd) + return ERR_PTR(-ENOMEM); + + mutex_init(&vdd->lock); + vdd->class_name = np->name; + + rc = generic_vdd_parse_regulators(dev, vdd, np); + rc |= generic_vdd_parse_levels(dev, vdd, np); + if (rc) { + dt_err(np, "unable to read vdd_class\n"); + return ERR_PTR(rc); + } + + return vdd; +} +MSMCLK_PARSER(simple_vdd_class_dt_parser, "qcom,simple-vdd-class", 0); + +static int generic_clk_parse_parents(struct device *dev, struct clk *c, + struct device_node *np) +{ + int rc; + phandle p; + char *name = "qcom,parent"; + + /* This property is optional */ + if (!of_find_property(np, name, NULL)) + return 0; + + rc = of_property_read_phandle_index(np, name, 0, &p); + if (rc) { + dt_prop_err(np, name, "unable to read phandle\n"); + return rc; + } + + c->parent = msmclk_parse_phandle(dev, p); + if (IS_ERR(c->parent)) { + dt_prop_err(np, name, "hashtable lookup failed\n"); + return PTR_ERR(c->parent); + } + + return 0; +} + +static int generic_clk_parse_vdd(struct device *dev, struct clk *c, + struct device_node *np) +{ + phandle p; + int rc; + char *name = "qcom,supply-group"; + + /* This property is optional */ + if (!of_find_property(np, name, NULL)) + return 0; + + rc = of_property_read_phandle_index(np, name, 0, &p); + if (rc) { + dt_prop_err(np, name, "unable to read phandle\n"); + return rc; + } + + c->vdd_class = msmclk_parse_phandle(dev, p); + if (IS_ERR(c->vdd_class)) { + dt_prop_err(np, name, "hashtable lookup failed\n"); + return PTR_ERR(c->vdd_class); + } + + return 0; +} + +static int generic_clk_parse_flags(struct device *dev, struct clk *c, + struct device_node *np) +{ + int rc; + char *name = "qcom,clk-flags"; + + /* This property is optional */ + if (!of_find_property(np, name, NULL)) + return 0; + + rc = of_property_read_u32(np, name, &c->flags); + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return rc; + } + + return 0; +} + +static int generic_clk_parse_fmax(struct device *dev, struct clk *c, + struct device_node *np) +{ + u32 prop_len, i; + int rc; + char *name = "qcom,clk-fmax"; + + /* This property is optional */ + if (!of_find_property(np, name, &prop_len)) + return 0; + + if (!c->vdd_class) { + dt_err(np, "both qcom,clk-fmax and qcom,supply-group must be defined\n"); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % 2) { + dt_prop_err(np, name, "bad length\n"); + return -EINVAL; + } + + /* Value at proplen - 2 is the index of the last entry in fmax array */ + rc = of_property_read_u32_index(np, name, prop_len - 2, &c->num_fmax); + c->num_fmax += 1; + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return rc; + } + + c->fmax = devm_kzalloc(dev, sizeof(*c->fmax) * c->num_fmax, GFP_KERNEL); + if (!c->fmax) + return -ENOMEM; + + for (i = 0; i < prop_len; i += 2) { + u32 level, value; + + rc = of_property_read_u32_index(np, name, i, &level); + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return rc; + } + + rc = of_property_read_u32_index(np, name, i + 1, &value); + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return rc; + } + + if (level >= c->num_fmax) { + dt_prop_err(np, name, "must be sorted\n"); + return -EINVAL; + } + c->fmax[level] = value; + } + + return 0; +} + +static int generic_clk_add_lookup_tbl_entry(struct device *dev, struct clk *c) +{ + struct msmclk_data *drv = dev_get_drvdata(dev); + struct clk_lookup *cl; + + if (drv->clk_tbl_size >= drv->max_clk_tbl_size) { + dev_err(dev, "child node count should be > clock_count?\n"); + return -EINVAL; + } + + cl = drv->clk_tbl + drv->clk_tbl_size; + cl->clk = c; + drv->clk_tbl_size++; + return 0; +} + +static int generic_clk_parse_depends(struct device *dev, struct clk *c, + struct device_node *np) +{ + phandle p; + int rc; + char *name = "qcom,depends"; + + /* This property is optional */ + if (!of_find_property(np, name, NULL)) + return 0; + + rc = of_property_read_phandle_index(np, name, 0, &p); + if (rc) { + dt_prop_err(np, name, "unable to read phandle\n"); + return rc; + } + + c->depends = msmclk_parse_phandle(dev, p); + if (IS_ERR(c->depends)) { + dt_prop_err(np, name, "hashtable lookup failed\n"); + return PTR_ERR(c->depends); + } + + return 0; +} + +static int generic_clk_parse_init_config(struct device *dev, struct clk *c, + struct device_node *np) +{ + int rc; + u32 temp; + char *name = "qcom,always-on"; + + c->always_on = of_property_read_bool(np, name); + + name = "qcom,config-rate"; + /* This property is optional */ + if (!of_find_property(np, name, NULL)) + return 0; + + rc = of_property_read_u32(np, name, &temp); + if (rc) { + dt_prop_err(np, name, "unable to read u32\n"); + return rc; + } + c->init_rate = temp; + + return rc; +} + +void *msmclk_generic_clk_init(struct device *dev, struct device_node *np, + struct clk *c) +{ + int rc; + + /* CLK_INIT macro */ + spin_lock_init(&c->lock); + mutex_init(&c->prepare_lock); + INIT_LIST_HEAD(&c->children); + INIT_LIST_HEAD(&c->siblings); + INIT_LIST_HEAD(&c->list); + c->dbg_name = np->name; + + rc = generic_clk_add_lookup_tbl_entry(dev, c); + rc |= generic_clk_parse_flags(dev, c, np); + rc |= generic_clk_parse_parents(dev, c, np); + rc |= generic_clk_parse_vdd(dev, c, np); + rc |= generic_clk_parse_fmax(dev, c, np); + rc |= generic_clk_parse_depends(dev, c, np); + rc |= generic_clk_parse_init_config(dev, c, np); + + if (rc) { + dt_err(np, "unable to read clk\n"); + return ERR_PTR(-EINVAL); + } + + return c; +} + +static struct msmclk_parser *msmclk_parser_lookup(struct device_node *np) +{ + struct msmclk_parser *item; + + list_for_each_entry(item, &msmclk_parser_list, list) { + if (of_device_is_compatible(np, item->compatible)) + return item; + } + return NULL; +} +void msmclk_parser_register(struct msmclk_parser *item) +{ + mutex_lock(&msmclk_lock); + list_add(&item->list, &msmclk_parser_list); + mutex_unlock(&msmclk_lock); +} + +static int msmclk_htable_add(struct device *dev, void *result, phandle key); + +void *msmclk_parse_dt_node(struct device *dev, struct device_node *np) +{ + struct msmclk_parser *parser; + phandle key; + void *result; + int rc; + + key = np->phandle; + result = msmclk_lookup_phandle(dev, key); + if (!result) + return ERR_PTR(-EINVAL); + + if (!of_device_is_available(np)) { + dt_err(np, "node is disabled\n"); + return ERR_PTR(-EINVAL); + } + + parser = msmclk_parser_lookup(np); + if (IS_ERR_OR_NULL(parser)) { + dt_err(np, "no parser found\n"); + return ERR_PTR(-EINVAL); + } + + /* This may return -EPROBE_DEFER */ + result = parser->parsedt(dev, np); + if (IS_ERR(result)) { + dt_err(np, "parsedt failed"); + return result; + } + + rc = msmclk_htable_add(dev, result, key); + if (rc) + return ERR_PTR(rc); + + return result; +} + +void *msmclk_parse_phandle(struct device *dev, phandle key) +{ + struct hitem *item; + struct device_node *np; + struct msmclk_data *drv = dev_get_drvdata(dev); + + /* + * the default phandle value is 0. Since hashtable keys must + * be unique, reject the default value. + */ + if (!key) + return ERR_PTR(-EINVAL); + + hash_for_each_possible(drv->htable, item, list, key) { + if (item->key == key) + return item->ptr; + } + + np = of_find_node_by_phandle(key); + if (!np) + return ERR_PTR(-EINVAL); + + return msmclk_parse_dt_node(dev, np); +} +EXPORT_SYMBOL(msmclk_parse_phandle); + +void *msmclk_lookup_phandle(struct device *dev, phandle key) +{ + struct hitem *item; + struct msmclk_data *drv = dev_get_drvdata(dev); + + hash_for_each_possible(drv->htable, item, list, key) { + if (item->key == key) + return item->ptr; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL(msmclk_lookup_phandle); + +static int msmclk_htable_add(struct device *dev, void *data, phandle key) +{ + struct hitem *item; + struct msmclk_data *drv = dev_get_drvdata(dev); + + /* + * If there are no phandle references to a node, key == 0. However, if + * there is a second node like this, both will have key == 0. This + * violates the requirement that hashtable keys be unique. Skip it. + */ + if (!key) + return 0; + + if (!IS_ERR(msmclk_lookup_phandle(dev, key))) { + struct device_node *np = of_find_node_by_phandle(key); + + dev_err(dev, "attempt to add duplicate entry for %s\n", + np ? np->name : "NULL"); + return -EINVAL; + } + + item = devm_kzalloc(dev, sizeof(*item), GFP_KERNEL); + if (!item) + return -ENOMEM; + + INIT_HLIST_NODE(&item->list); + item->key = key; + item->ptr = data; + + hash_add(drv->htable, &item->list, key); + return 0; +} + +/* + * Currently, regulators are the only elements capable of probe deferral. + * Check them first to handle probe deferal efficiently. + */ +static int get_ext_regulators(struct device *dev) +{ + int num_strings, i, rc; + struct device_node *np; + void *item; + char *name = "qcom,regulator-names"; + + np = dev->of_node; + /* This property is optional */ + num_strings = of_property_count_strings(np, name); + if (num_strings <= 0) + return 0; + + for (i = 0; i < num_strings; i++) { + const char *str; + char buf[50]; + phandle key; + + rc = of_property_read_string_index(np, name, i, &str); + if (rc) { + dt_prop_err(np, name, "unable to read string\n"); + return rc; + } + + item = devm_regulator_get(dev, str); + if (IS_ERR(item)) { + dev_err(dev, "Failed to get regulator: %s\n", str); + return PTR_ERR(item); + } + + snprintf(buf, ARRAY_SIZE(buf), "%s-supply", str); + rc = of_property_read_phandle_index(np, buf, 0, &key); + if (rc) { + dt_prop_err(np, buf, "unable to read phandle\n"); + return rc; + } + + rc = msmclk_htable_add(dev, item, key); + if (rc) + return rc; + } + return 0; +} + +static struct clk *msmclk_clk_get(struct of_phandle_args *clkspec, void *data) +{ + phandle key; + struct clk *c = ERR_PTR(-ENOENT); + + key = clkspec->args[0]; + c = msmclk_lookup_phandle(data, key); + + if (!IS_ERR(c) && !(c->flags & CLKFLAG_INIT_DONE)) + return ERR_PTR(-EPROBE_DEFER); + + return c; +} + +static void *regulator_dt_parser(struct device *dev, struct device_node *np) +{ + dt_err(np, "regulators should be handled in probe()"); + return ERR_PTR(-EINVAL); +} +MSMCLK_PARSER(regulator_dt_parser, "qcom,rpm-smd-regulator", 0); + +static void *msmclk_dt_parser(struct device *dev, struct device_node *np) +{ + dt_err(np, "calling into other clock controllers isn't allowed"); + return ERR_PTR(-EINVAL); +} +MSMCLK_PARSER(msmclk_dt_parser, "qcom,msm-clock-controller", 0); + +static struct msmclk_data *msmclk_drv_init(struct device *dev) +{ + struct msmclk_data *drv; + size_t size; + + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); + if (!drv) + return ERR_PTR(-ENOMEM); + + dev_set_drvdata(dev, drv); + + drv->dev = dev; + INIT_LIST_HEAD(&drv->list); + + /* This overestimates size */ + drv->max_clk_tbl_size = of_get_child_count(dev->of_node); + size = sizeof(*drv->clk_tbl) * drv->max_clk_tbl_size; + drv->clk_tbl = devm_kzalloc(dev, size, GFP_KERNEL); + if (!drv->clk_tbl) + return ERR_PTR(-ENOMEM); + + hash_init(drv->htable); + return drv; +} + +static int msmclk_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device *dev; + struct msmclk_data *drv; + struct device_node *child; + void *result; + int rc = 0; + + dev = &pdev->dev; + drv = msmclk_drv_init(dev); + if (IS_ERR(drv)) + return PTR_ERR(drv); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc-base"); + if (!res) { + dt_err(dev->of_node, "missing cc-base\n"); + return -EINVAL; + } + drv->base = devm_ioremap(dev, res->start, resource_size(res)); + if (!drv->base) { + dev_err(dev, "ioremap failed for drv->base\n"); + return -ENOMEM; + } + rc = msmclk_htable_add(dev, drv, dev->of_node->phandle); + if (rc) + return rc; + + rc = enable_rpm_scaling(); + if (rc) + return rc; + + rc = get_ext_regulators(dev); + if (rc) + return rc; + + /* + * Returning -EPROBE_DEFER here is inefficient due to + * destroying work 'unnecessarily' + */ + for_each_available_child_of_node(dev->of_node, child) { + result = msmclk_parse_dt_node(dev, child); + if (!IS_ERR(result)) + continue; + if (!msmclk_debug) + return PTR_ERR(result); + /* + * Parse and report all errors instead of immediately + * exiting. Return the first error code. + */ + if (!rc) + rc = PTR_ERR(result); + } + if (rc) + return rc; + + rc = of_clk_add_provider(dev->of_node, msmclk_clk_get, dev); + if (rc) { + dev_err(dev, "of_clk_add_provider failed\n"); + return rc; + } + + /* + * can't fail after registering clocks, because users may have + * gotten clock references. Failing would delete the memory. + */ + WARN_ON(msm_clock_register(drv->clk_tbl, drv->clk_tbl_size)); + dev_info(dev, "registered clocks\n"); + + return 0; +} + +static const struct of_device_id msmclk_match_table[] = { + {.compatible = "qcom,msm-clock-controller"}, + {} +}; + +static struct platform_driver msmclk_driver = { + .probe = msmclk_probe, + .driver = { + .name = "msm-clock-controller", + .of_match_table = msmclk_match_table, + .owner = THIS_MODULE, + }, +}; + +static bool initialized; +int __init msmclk_init(void) +{ + int rc; + + if (initialized) + return 0; + + rc = platform_driver_register(&msmclk_driver); + if (rc) + return rc; + initialized = true; + return rc; +} +arch_initcall(msmclk_init); diff --git a/drivers/clk/msm/reset.c b/drivers/clk/msm/reset.c new file mode 100644 index 0000000000000000000000000000000000000000..0f47fd6c0040f04c72c4ac52e1a9b17803abc05c --- /dev/null +++ b/drivers/clk/msm/reset.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016-2017, 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 +#include +#include +#include + +#include "reset.h" + +static int msm_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + rcdev->ops->assert(rcdev, id); + udelay(1); + rcdev->ops->deassert(rcdev, id); + return 0; +} + +static int +msm_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct msm_reset_controller *rst; + const struct msm_reset_map *map; + u32 regval; + + rst = to_msm_reset_controller(rcdev); + map = &rst->reset_map[id]; + + regval = readl_relaxed(rst->base + map->reg); + regval |= BIT(map->bit); + writel_relaxed(regval, rst->base + map->reg); + + /* Make sure the reset is asserted */ + mb(); + + return 0; +} + +static int +msm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct msm_reset_controller *rst; + const struct msm_reset_map *map; + u32 regval; + + rst = to_msm_reset_controller(rcdev); + map = &rst->reset_map[id]; + + regval = readl_relaxed(rst->base + map->reg); + regval &= ~BIT(map->bit); + writel_relaxed(regval, rst->base + map->reg); + + /* Make sure the reset is de-asserted */ + mb(); + + return 0; +} + +struct reset_control_ops msm_reset_ops = { + .reset = msm_reset, + .assert = msm_reset_assert, + .deassert = msm_reset_deassert, +}; +EXPORT_SYMBOL(msm_reset_ops); + +int msm_reset_controller_register(struct platform_device *pdev, + const struct msm_reset_map *map, unsigned int num_resets, + void __iomem *virt_base) +{ + struct msm_reset_controller *reset; + int ret = 0; + + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rcdev.of_node = pdev->dev.of_node; + reset->rcdev.ops = &msm_reset_ops; + reset->rcdev.owner = pdev->dev.driver->owner; + reset->rcdev.nr_resets = num_resets; + reset->reset_map = map; + reset->base = virt_base; + + ret = reset_controller_register(&reset->rcdev); + if (ret) + dev_err(&pdev->dev, "Failed to register with reset controller\n"); + + return ret; +} +EXPORT_SYMBOL(msm_reset_controller_register); diff --git a/drivers/clk/msm/reset.h b/drivers/clk/msm/reset.h new file mode 100644 index 0000000000000000000000000000000000000000..9e3b2fbeb1604fe58b11e0496e10b9f35e27c35a --- /dev/null +++ b/drivers/clk/msm/reset.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016-2017, 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 __DRIVERS_CLK_RESET_H +#define __DRIVERS_CLK_RESET_H + +#include +#include + +struct msm_reset_map { + unsigned int reg; + u8 bit; +}; + +struct msm_reset_controller { + const struct msm_reset_map *reset_map; + struct reset_controller_dev rcdev; + void __iomem *base; +}; + +#define to_msm_reset_controller(r) \ + container_of(r, struct msm_reset_controller, rcdev) + +extern struct reset_control_ops msm_reset_ops; + +int msm_reset_controller_register(struct platform_device *pdev, + const struct msm_reset_map *map, unsigned int nr_resets, + void __iomem *virt_base); +#endif diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c index 02023baf86c930ec2f68cdc3e4cbe7e9fc170a47..962e0c5f6f4daf5ce618845fed21a8a62cc8c092 100644 --- a/drivers/clk/mvebu/ap806-system-controller.c +++ b/drivers/clk/mvebu/ap806-system-controller.c @@ -55,21 +55,39 @@ static int ap806_syscon_clk_probe(struct platform_device *pdev) freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK; switch (freq_mode) { - case 0x0 ... 0x5: + case 0x0: + case 0x1: cpuclk_freq = 2000; break; - case 0x6 ... 0xB: + case 0x6: + case 0x7: cpuclk_freq = 1800; break; - case 0xC ... 0x11: + case 0x4: + case 0xB: + case 0xD: cpuclk_freq = 1600; break; - case 0x12 ... 0x16: + case 0x1a: cpuclk_freq = 1400; break; - case 0x17 ... 0x19: + case 0x14: + case 0x17: cpuclk_freq = 1300; break; + case 0x19: + cpuclk_freq = 1200; + break; + case 0x13: + case 0x1d: + cpuclk_freq = 1000; + break; + case 0x1c: + cpuclk_freq = 800; + break; + case 0x1b: + cpuclk_freq = 600; + break; default: dev_err(&pdev->dev, "invalid SAR value\n"); return -EINVAL; diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index d47b66e43c99bfe8879be689a0a2f4f7eee21438..87d067ae67ccf170087ecc381d44dea9ee28b90b 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -235,4 +235,21 @@ config MSM_CLK_AOP_QMP subsystems via QMP mailboxes. Say Y to support the clocks managed by AOP on platforms such as sdm845. +config MDM_GCC_SDXPOORWILLS + tristate "SDXPOORWILLS Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on sdxpoorwills devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, SD/eMMC, etc. + +config MDM_CLOCK_CPU_SDXPOORWILLS + tristate "SDXPOORWILLS CPU Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the cpu clock controller on sdxpoorwills + based devices. + Say Y if you want to support CPU clock scaling using + CPUfreq drivers for dyanmic power management. + source "drivers/clk/qcom/mdss/Kconfig" diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 930e281331fa7e843ee0b5895b9b1089c6b9f15c..8cb46a7e40a04903f3895cb3efc2f607c867770f 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -9,6 +9,7 @@ clk-qcom-y += clk-rcg2.o clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o +clk-qcom-y += clk-regmap-mux-div.o clk-qcom-y += reset.o clk-voter.o clk-qcom-y += clk-dummy.o clk-debug.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o gdsc-regulator.o @@ -21,7 +22,9 @@ obj-$(CONFIG_CLOCK_QPNP_DIV) += clk-qpnp-div.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o +obj-$(CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS) += clk-cpu-a7.o obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o +obj-$(CONFIG_MDM_GCC_SDXPOORWILLS) += gcc-sdxpoorwills.o obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o obj-$(CONFIG_MSM_CAMCC_SDM845) += camcc-sdm845.o obj-$(CONFIG_MSM_CLK_AOP_QMP) += clk-aop-qmp.o diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c index 6296c40deefe2c73a9d0ccf87bbf2d5f3a817486..836c25c788f49fc42f6392b8c3318fd0fdb57c9f 100644 --- a/drivers/clk/qcom/camcc-sdm845.c +++ b/drivers/clk/qcom/camcc-sdm845.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -87,7 +89,7 @@ static const char * const cam_cc_parent_names_1[] = { }; static struct pll_vco fabia_vco[] = { - { 250000000, 2000000000, 0 }, + { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, }; @@ -278,6 +280,7 @@ static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { }; static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), @@ -316,7 +319,6 @@ static const struct freq_tbl ftbl_cam_cc_cci_clk_src[] = { { } }; - static struct clk_rcg2 cam_cc_cci_clk_src = { .cmd_rcgr = 0xb0d8, .mnd_width = 8, @@ -341,7 +343,13 @@ static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), F(320000000, P_CAM_CC_PLL2_OUT_ODD, 3, 0, 0), - F(384000000, P_CAM_CC_PLL2_OUT_ODD, 2.5, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), { } }; @@ -429,7 +437,27 @@ static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = { }, }; +static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x5070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 240000000, + LOW, 269333333), + }, +}; + static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0), F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), @@ -468,6 +496,15 @@ static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src[] = { { } }; +static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + static struct clk_rcg2 cam_cc_fd_core_clk_src = { .cmd_rcgr = 0xb0b0, .mnd_width = 0, @@ -490,13 +527,31 @@ static struct clk_rcg2 cam_cc_fd_core_clk_src = { }, }; +static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + static struct clk_rcg2 cam_cc_icp_clk_src = { .cmd_rcgr = 0xb088, .mnd_width = 0, .hid_width = 5, .enable_safe_config = true, .parent_map = cam_cc_parent_map_0, - .freq_tbl = ftbl_cam_cc_fd_core_clk_src, + .freq_tbl = ftbl_cam_cc_icp_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "cam_cc_icp_clk_src", .parent_names = cam_cc_parent_names_0, @@ -513,6 +568,7 @@ static struct clk_rcg2 cam_cc_icp_clk_src = { }; static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), @@ -544,6 +600,7 @@ static struct clk_rcg2 cam_cc_ife_0_clk_src = { }; static const struct freq_tbl ftbl_cam_cc_ife_0_csid_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0), F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), @@ -655,6 +712,7 @@ static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { }; static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0), F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), @@ -733,6 +791,7 @@ static struct clk_rcg2 cam_cc_jpeg_clk_src = { }; static const struct freq_tbl ftbl_cam_cc_lrme_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), F(384000000, P_CAM_CC_PLL2_OUT_ODD, 2.5, 0, 0), @@ -741,6 +800,16 @@ static const struct freq_tbl ftbl_cam_cc_lrme_clk_src[] = { { } }; +static const struct freq_tbl ftbl_cam_cc_lrme_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + static struct clk_rcg2 cam_cc_lrme_clk_src = { .cmd_rcgr = 0xb0f8, .mnd_width = 0, @@ -764,7 +833,8 @@ static struct clk_rcg2 cam_cc_lrme_clk_src = { }; static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { - F(24000000, P_CAM_CC_PLL3_OUT_EVEN, 16, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_CAM_CC_PLL2_OUT_EVEN, 10, 1, 2), F(33333333, P_CAM_CC_PLL0_OUT_EVEN, 2, 1, 9), F(34285714, P_CAM_CC_PLL2_OUT_EVEN, 14, 0, 0), { } @@ -1058,6 +1128,24 @@ static struct clk_branch cam_cc_csi2phytimer_clk = { }, }; +static struct clk_branch cam_cc_csi3phytimer_clk = { + .halt_reg = 0x5088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi3phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch cam_cc_csiphy0_clk = { .halt_reg = 0x5020, .halt_check = BRANCH_HALT, @@ -1115,6 +1203,25 @@ static struct clk_branch cam_cc_csiphy2_clk = { }, }; +static struct clk_branch cam_cc_csiphy3_clk = { + .halt_reg = 0x508c, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x508c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy3_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch cam_cc_fd_core_clk = { .halt_reg = 0xb0c8, .halt_check = BRANCH_HALT, @@ -1748,9 +1855,12 @@ static struct clk_regmap *cam_cc_sdm845_clocks[] = { [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr, [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr, [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr, + [CAM_CC_CSI3PHYTIMER_CLK] = NULL, + [CAM_CC_CSI3PHYTIMER_CLK_SRC] = NULL, [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr, [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr, [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr, + [CAM_CC_CSIPHY3_CLK] = NULL, [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, [CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr, [CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr, @@ -1818,22 +1928,11 @@ static struct clk_regmap *cam_cc_sdm845_clocks[] = { }; static const struct qcom_reset_map cam_cc_sdm845_resets[] = { - [TITAN_CAM_CC_BPS_BCR] = { 0x6000 }, - [TITAN_CAM_CC_CAMNOC_BCR] = { 0xb120 }, [TITAN_CAM_CC_CCI_BCR] = { 0xb0d4 }, [TITAN_CAM_CC_CPAS_BCR] = { 0xb118 }, [TITAN_CAM_CC_CSI0PHY_BCR] = { 0x5000 }, [TITAN_CAM_CC_CSI1PHY_BCR] = { 0x5024 }, [TITAN_CAM_CC_CSI2PHY_BCR] = { 0x5048 }, - [TITAN_CAM_CC_FD_BCR] = { 0xb0ac }, - [TITAN_CAM_CC_ICP_BCR] = { 0xb074 }, - [TITAN_CAM_CC_IFE_0_BCR] = { 0x9000 }, - [TITAN_CAM_CC_IFE_1_BCR] = { 0xa000 }, - [TITAN_CAM_CC_IFE_LITE_BCR] = { 0xb000 }, - [TITAN_CAM_CC_IPE_0_BCR] = { 0x7000 }, - [TITAN_CAM_CC_IPE_1_BCR] = { 0x8000 }, - [TITAN_CAM_CC_JPEG_BCR] = { 0xb048 }, - [TITAN_CAM_CC_LRME_BCR] = { 0xb0f4 }, [TITAN_CAM_CC_MCLK0_BCR] = { 0x4000 }, [TITAN_CAM_CC_MCLK1_BCR] = { 0x4020 }, [TITAN_CAM_CC_MCLK2_BCR] = { 0x4040 }, @@ -1859,10 +1958,137 @@ static const struct qcom_cc_desc cam_cc_sdm845_desc = { static const struct of_device_id cam_cc_sdm845_match_table[] = { { .compatible = "qcom,cam_cc-sdm845" }, + { .compatible = "qcom,cam_cc-sdm845-v2" }, + { .compatible = "qcom,cam_cc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table); +static void cam_cc_sdm845_fixup_sdm845v2(void) +{ + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK] = + &cam_cc_csi3phytimer_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK_SRC] = + &cam_cc_csi3phytimer_clk_src.clkr; + cam_cc_bps_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_bps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_cci_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_cci_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_cphy_rx_clk_src.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 384000000; + cam_cc_csi0phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_csi0phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_csi1phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_csi1phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_csi2phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_csi2phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_fast_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_fast_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_fd_core_clk_src.freq_tbl = ftbl_cam_cc_fd_core_clk_src_sdm845_v2; + cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_icp_clk_src.freq_tbl = ftbl_cam_cc_icp_clk_src_sdm845_v2; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 600000000; + cam_cc_ife_0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_0_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_0_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_0_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 384000000; + cam_cc_ife_1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_1_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_1_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_1_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 384000000; + cam_cc_ife_lite_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_lite_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_lite_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_lite_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_lite_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 384000000; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_jpeg_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_jpeg_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_lrme_clk_src.freq_tbl = ftbl_cam_cc_lrme_clk_src_sdm845_v2; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 269333333; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 320000000; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 400000000; + cam_cc_mclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_mclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_mclk2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk2_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk2_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_mclk3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk3_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk3_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 80000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 80000000; +} + +static void cam_cc_sdm845_fixup_sdm670(void) +{ + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK] = + &cam_cc_csi3phytimer_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK_SRC] = + &cam_cc_csi3phytimer_clk_src.clkr; + cam_cc_cphy_rx_clk_src.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 384000000; + cam_cc_fd_core_clk_src.freq_tbl = ftbl_cam_cc_fd_core_clk_src_sdm845_v2; + cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000; + cam_cc_icp_clk_src.freq_tbl = ftbl_cam_cc_icp_clk_src_sdm845_v2; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 600000000; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_lrme_clk_src.freq_tbl = ftbl_cam_cc_lrme_clk_src_sdm845_v2; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 269333333; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 320000000; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 400000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 80000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 80000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 80000000; +} + +static int cam_cc_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,cam_cc-sdm845-v2")) + cam_cc_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,cam_cc-sdm670")) + cam_cc_sdm845_fixup_sdm670(); + + return 0; +} + static int cam_cc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; @@ -1890,6 +2116,10 @@ static int cam_cc_sdm845_probe(struct platform_device *pdev) return PTR_ERR(vdd_mx.regulator[0]); } + ret = cam_cc_sdm845_fixup(pdev); + if (ret) + return ret; + clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config); clk_fabia_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); @@ -1917,7 +2147,7 @@ static int __init cam_cc_sdm845_init(void) { return platform_driver_register(&cam_cc_sdm845_driver); } -core_initcall(cam_cc_sdm845_init); +subsys_initcall(cam_cc_sdm845_init); static void __exit cam_cc_sdm845_exit(void) { diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 6ff621d3808297d57fb298c6ae5b0f0faf9c6712..514c0ad356c73a1f0e11416130421e14b8332deb 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -20,6 +22,8 @@ #include "clk-alpha-pll.h" #define PLL_MODE 0x00 +#define PLL_STANDBY 0x0 +#define PLL_RUN 0x1 # define PLL_OUTCTRL BIT(0) # define PLL_BYPASSNL BIT(1) # define PLL_RESET_N BIT(2) @@ -49,26 +53,40 @@ #define PLL_TEST_CTL 0x1c #define PLL_TEST_CTL_U 0x20 #define PLL_STATUS 0x24 +#define PLL_UPDATE BIT(22) +#define PLL_ACK_LATCH BIT(29) +#define PLL_CALIBRATION_MASK (0x7<<3) +#define PLL_CALIBRATION_CONTROL 2 +#define PLL_HW_UPDATE_LOGIC_BYPASS BIT(23) +#define ALPHA_16_BIT_PLL_RATE_MARGIN 500 /* * Even though 40 bits are present, use only 32 for ease of calculation. */ #define ALPHA_REG_BITWIDTH 40 #define ALPHA_BITWIDTH 32 -#define FABIA_BITWIDTH 16 +#define SUPPORTS_16BIT_ALPHA 16 #define FABIA_USER_CTL_LO 0xc #define FABIA_USER_CTL_HI 0x10 -#define FABIA_CAL_L_VAL 0x8 #define FABIA_FRAC_VAL 0x38 #define FABIA_OPMODE 0x2c -#define FABIA_PLL_STANDBY 0x0 -#define FABIA_PLL_RUN 0x1 #define FABIA_PLL_OUT_MASK 0x7 -#define FABIA_PLL_RATE_MARGIN 500 #define FABIA_PLL_ACK_LATCH BIT(29) #define FABIA_PLL_UPDATE BIT(22) -#define FABIA_PLL_HW_UPDATE_LOGIC_BYPASS BIT(23) + +#define TRION_PLL_CAL_VAL 0x44 +#define TRION_PLL_CAL_L_VAL 0x8 +#define TRION_PLL_USER_CTL 0xc +#define TRION_PLL_USER_CTL_U 0x10 +#define TRION_PLL_USER_CTL_U1 0x14 +#define TRION_PLL_CONFIG_CTL_U 0x1c +#define TRION_PLL_CONFIG_CTL_U1 0x20 +#define TRION_PLL_OPMODE 0x38 +#define TRION_PLL_ALPHA_VAL 0x40 + +#define TRION_PLL_OUT_MASK 0x7 +#define TRION_PLL_ENABLE_STATE_READ BIT(4) #define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll, clkr) @@ -101,7 +119,7 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse, udelay(1); } - WARN(1, "%s failed to %s!\n", name, action); + WARN(1, "clk: %s failed to %s!\n", name, action); return -ETIMEDOUT; } @@ -120,6 +138,10 @@ static int wait_for_pll_offline(struct clk_alpha_pll *pll, u32 mask) return wait_for_pll(pll, mask, 0, "offline"); } +static int wait_for_pll_latch_ack(struct clk_alpha_pll *pll, u32 mask) +{ + return wait_for_pll(pll, mask, 0, "latch_ack"); +} /* alpha pll with hwfsm support */ @@ -293,8 +315,8 @@ static unsigned long alpha_pll_calc_rate(const struct clk_alpha_pll *pll, { int alpha_bw = ALPHA_BITWIDTH; - if (pll->type == FABIA_PLL) - alpha_bw = FABIA_BITWIDTH; + if (pll->type == FABIA_PLL || pll->type == TRION_PLL) + alpha_bw = SUPPORTS_16BIT_ALPHA; return (prate * l) + ((prate * a) >> alpha_bw); } @@ -307,6 +329,15 @@ alpha_pll_round_rate(const struct clk_alpha_pll *pll, unsigned long rate, u64 quotient; int alpha_bw = ALPHA_BITWIDTH; + /* + * The PLLs parent rate is zero probably since the parent hasn't + * registered yet. Return early with the requested rate. + */ + if (!prate) { + pr_debug("PLLs parent rate hasn't been initialized.\n"); + return rate; + } + quotient = rate; remainder = do_div(quotient, prate); *l = quotient; @@ -316,9 +347,9 @@ alpha_pll_round_rate(const struct clk_alpha_pll *pll, unsigned long rate, return rate; } - /* Fabia PLLs only have 16 bits to program the fractional divider */ - if (pll->type == FABIA_PLL) - alpha_bw = FABIA_BITWIDTH; + /* Some PLLs only have 16 bits to program the fractional divider */ + if (pll->type == FABIA_PLL || pll->type == TRION_PLL) + alpha_bw = SUPPORTS_16BIT_ALPHA; /* Upper ALPHA_BITWIDTH bits of Alpha */ quotient = remainder << alpha_bw; @@ -370,8 +401,8 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); const struct pll_vco *vco; - u32 l, off = pll->offset; - u64 a; + u32 l = 0, off = pll->offset; + u64 a = 0; rate = alpha_pll_round_rate(pll, rate, prate, &l, &a); vco = alpha_pll_find_vco(pll, rate); @@ -405,7 +436,8 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long min_freq, max_freq; rate = alpha_pll_round_rate(pll, rate, *prate, &l, &a); - if (pll->type == FABIA_PLL || alpha_pll_find_vco(pll, rate)) + if (pll->type == FABIA_PLL || pll->type == TRION_PLL || + alpha_pll_find_vco(pll, rate)) return rate; min_freq = pll->vco_table[0].min_freq; @@ -449,21 +481,50 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw) } } +static int clk_fabia_pll_latch_input(struct clk_alpha_pll *pll, + struct regmap *regmap) +{ + u32 regval; + int ret = 0; + + /* Latch the PLL input */ + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + FABIA_PLL_UPDATE, FABIA_PLL_UPDATE); + if (ret) + return ret; + + /* Wait for 2 reference cycles before checking the ACK bit. */ + udelay(1); + regmap_read(regmap, pll->offset + PLL_MODE, ®val); + if (!(regval & FABIA_PLL_ACK_LATCH)) { + WARN(1, "clk: PLL latch failed. Output may be unstable!\n"); + return -EINVAL; + } + + /* Return the latch input to 0 */ + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + FABIA_PLL_UPDATE, 0); + if (ret) + return ret; + + /* Wait for PLL output to stabilize */ + udelay(100); + return ret; +} + void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct pll_config *config) { u32 val, mask; - if (config->l) { + if (config->l) regmap_write(regmap, pll->offset + PLL_L_VAL, config->l); - regmap_write(regmap, pll->offset + FABIA_CAL_L_VAL, - config->l); - } if (config->frac) regmap_write(regmap, pll->offset + FABIA_FRAC_VAL, config->frac); + if (config->config_ctl_val) regmap_write(regmap, pll->offset + PLL_CONFIG_CTL, config->config_ctl_val); @@ -475,9 +536,17 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, mask, val); } + /* + * If the PLL has already been initialized, it would now be in a STANDBY + * state. Any new updates to the PLL frequency will require setting the + * PLL_UPDATE bit. + */ + if (pll->inited) + clk_fabia_pll_latch_input(pll, regmap); + regmap_update_bits(regmap, pll->offset + PLL_MODE, - FABIA_PLL_HW_UPDATE_LOGIC_BYPASS, - FABIA_PLL_HW_UPDATE_LOGIC_BYPASS); + PLL_HW_UPDATE_LOGIC_BYPASS, + PLL_HW_UPDATE_LOGIC_BYPASS); regmap_update_bits(regmap, pll->offset + PLL_MODE, PLL_RESET_N, PLL_RESET_N); @@ -513,7 +582,7 @@ static int clk_fabia_pll_enable(struct clk_hw *hw) return ret; /* Set operation mode to STANDBY */ - regmap_write(pll->clkr.regmap, off + FABIA_OPMODE, FABIA_PLL_STANDBY); + regmap_write(pll->clkr.regmap, off + FABIA_OPMODE, PLL_STANDBY); /* PLL should be in STANDBY mode before continuing */ mb(); @@ -525,7 +594,7 @@ static int clk_fabia_pll_enable(struct clk_hw *hw) return ret; /* Set operation mode to RUN */ - regmap_write(pll->clkr.regmap, off + FABIA_OPMODE, FABIA_PLL_RUN); + regmap_write(pll->clkr.regmap, off + FABIA_OPMODE, PLL_RUN); ret = wait_for_pll_enable(pll, PLL_LOCK_DET); if (ret) @@ -577,7 +646,7 @@ static void clk_fabia_pll_disable(struct clk_hw *hw) return; /* Place the PLL mode in STANDBY */ - regmap_write(pll->clkr.regmap, off + FABIA_OPMODE, FABIA_PLL_STANDBY); + regmap_write(pll->clkr.regmap, off + FABIA_OPMODE, PLL_STANDBY); } static unsigned long @@ -599,9 +668,9 @@ static int clk_fabia_pll_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); unsigned long rrate; - u32 regval, l, off = pll->offset; - u64 a; - int ret; + u32 regval = 0, l = 0, off = pll->offset; + u64 a = 0; + int ret = 0; ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, ®val); if (ret) @@ -612,43 +681,16 @@ static int clk_fabia_pll_set_rate(struct clk_hw *hw, unsigned long rate, * Due to limited number of bits for fractional rate programming, the * rounded up rate could be marginally higher than the requested rate. */ - if (rrate > (rate + FABIA_PLL_RATE_MARGIN) || rrate < rate) { + if (rrate > (rate + ALPHA_16_BIT_PLL_RATE_MARGIN) || rrate < rate) { pr_err("Call set rate on the PLL with rounded rates!\n"); return -EINVAL; } regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l); - /* - * pll_cal_l_val is set to pll_l_val on MOST targets. Set it - * explicitly here for PLL out-of-reset calibration to work - * without a glitch on ALL of them. - */ - regmap_write(pll->clkr.regmap, off + FABIA_CAL_L_VAL, l); regmap_write(pll->clkr.regmap, off + FABIA_FRAC_VAL, a); - /* Latch the PLL input */ - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, - FABIA_PLL_UPDATE, FABIA_PLL_UPDATE); - if (ret) - return ret; - - /* Wait for 2 reference cycles before checking the ACK bit. */ - udelay(1); - regmap_read(pll->clkr.regmap, off + PLL_MODE, ®val); - if (!(regval & FABIA_PLL_ACK_LATCH)) { - WARN(1, "PLL latch failed. Output may be unstable!\n"); - return -EINVAL; - } - - /* Return the latch input to 0 */ - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, - FABIA_PLL_UPDATE, 0); - if (ret) - return ret; - - /* Wait for PLL output to stabilize */ - udelay(100); - return 0; + ret = clk_fabia_pll_latch_input(pll, pll->clkr.regmap); + return ret; } static void clk_fabia_pll_list_registers(struct seq_file *f, struct clk_hw *hw) @@ -814,7 +856,7 @@ static long clk_generic_pll_postdiv_round_rate(struct clk_hw *hw, return -EINVAL; return divider_round_rate(hw, rate, prate, pll->post_div_table, - pll->width, CLK_DIVIDER_ROUND_CLOSEST); + pll->width, CLK_DIVIDER_ROUND_KHZ); } static int clk_generic_pll_postdiv_set_rate(struct clk_hw *hw, @@ -859,3 +901,436 @@ const struct clk_ops clk_generic_pll_postdiv_ops = { .set_rate = clk_generic_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_generic_pll_postdiv_ops); + +static int trion_pll_is_enabled(struct clk_alpha_pll *pll, + struct regmap *regmap) +{ + u32 mode_val, opmode_val, off = pll->offset; + int ret; + + ret = regmap_read(regmap, off + PLL_MODE, &mode_val); + ret |= regmap_read(regmap, off + TRION_PLL_OPMODE, &opmode_val); + if (ret) + return 0; + + return ((opmode_val & PLL_RUN) && (mode_val & PLL_OUTCTRL)); +} + +int clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct pll_config *config) +{ + int ret = 0; + + if (trion_pll_is_enabled(pll, regmap)) { + pr_debug("PLL is already enabled. Skipping configuration.\n"); + + /* + * Set the PLL_HW_UPDATE_LOGIC_BYPASS bit to latch the input + * before continuing. + */ + regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_HW_UPDATE_LOGIC_BYPASS, + PLL_HW_UPDATE_LOGIC_BYPASS); + + pll->inited = true; + return ret; + } + + /* + * Disable the PLL if it's already been initialized. Not doing so might + * lead to the PLL running with the old frequency configuration. + */ + if (pll->inited) { + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_RESET_N, 0); + if (ret) + return ret; + } + + if (config->l) + regmap_write(regmap, pll->offset + PLL_L_VAL, + config->l); + + regmap_write(regmap, pll->offset + TRION_PLL_CAL_L_VAL, + TRION_PLL_CAL_VAL); + + if (config->frac) + regmap_write(regmap, pll->offset + TRION_PLL_ALPHA_VAL, + config->frac); + + if (config->config_ctl_val) + regmap_write(regmap, pll->offset + PLL_CONFIG_CTL, + config->config_ctl_val); + + if (config->config_ctl_hi_val) + regmap_write(regmap, pll->offset + TRION_PLL_CONFIG_CTL_U, + config->config_ctl_hi_val); + + if (config->config_ctl_hi1_val) + regmap_write(regmap, pll->offset + TRION_PLL_CONFIG_CTL_U1, + config->config_ctl_hi1_val); + + if (config->post_div_mask) + regmap_update_bits(regmap, pll->offset + TRION_PLL_USER_CTL, + config->post_div_mask, config->post_div_val); + + /* Disable state read */ + regmap_update_bits(regmap, pll->offset + TRION_PLL_USER_CTL_U, + TRION_PLL_ENABLE_STATE_READ, 0); + + regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_HW_UPDATE_LOGIC_BYPASS, + PLL_HW_UPDATE_LOGIC_BYPASS); + + /* Set calibration control to Automatic */ + regmap_update_bits(regmap, pll->offset + TRION_PLL_USER_CTL_U, + PLL_CALIBRATION_MASK, PLL_CALIBRATION_CONTROL); + + /* Disable PLL output */ + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_OUTCTRL, 0); + if (ret) + return ret; + + /* Set operation mode to OFF */ + regmap_write(regmap, pll->offset + TRION_PLL_OPMODE, PLL_STANDBY); + + /* PLL should be in OFF mode before continuing */ + wmb(); + + /* Place the PLL in STANDBY mode */ + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_RESET_N, PLL_RESET_N); + if (ret) + return ret; + + pll->inited = true; + + return ret; +} + +static int clk_alpha_pll_latch_l_val(struct clk_alpha_pll *pll) +{ + int ret; + + /* Latch the input to the PLL */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + PLL_UPDATE, PLL_UPDATE); + if (ret) + return ret; + + /* Wait for 2 reference cycle before checking ACK bit */ + udelay(1); + + ret = wait_for_pll_latch_ack(pll, PLL_ACK_LATCH); + if (ret) + return ret; + + /* Return latch input to 0 */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + PLL_UPDATE, (u32)~PLL_UPDATE); + if (ret) + return ret; + + return 0; +} + +static int clk_trion_pll_enable(struct clk_hw *hw) +{ + int ret = 0; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val, off = pll->offset; + + ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + if (ret) + return ret; + + /* If in FSM mode, just vote for it */ + if (val & PLL_VOTE_FSM_ENA) { + ret = clk_enable_regmap(hw); + if (ret) + return ret; + return wait_for_pll_enable(pll, PLL_ACTIVE_FLAG); + } + + if (unlikely(!pll->inited)) { + ret = clk_trion_pll_configure(pll, pll->clkr.regmap, + pll->config); + if (ret) { + pr_err("Failed to configure %s\n", clk_hw_get_name(hw)); + return ret; + } + } + + /* Skip If PLL is already running */ + if (trion_pll_is_enabled(pll, pll->clkr.regmap)) + return ret; + + /* Set operation mode to RUN */ + regmap_write(pll->clkr.regmap, off + TRION_PLL_OPMODE, PLL_RUN); + + ret = wait_for_pll_enable(pll, PLL_LOCK_DET); + if (ret) + return ret; + + /* Enable PLL main output */ + ret = regmap_update_bits(pll->clkr.regmap, off + TRION_PLL_USER_CTL, + TRION_PLL_OUT_MASK, TRION_PLL_OUT_MASK); + if (ret) + return ret; + + /* Enable Global PLL outputs */ + ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + PLL_OUTCTRL, PLL_OUTCTRL); + if (ret) + return ret; + + /* Ensure that the write above goes through before returning. */ + mb(); + return ret; +} + +static void clk_trion_pll_disable(struct clk_hw *hw) +{ + int ret; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val, off = pll->offset; + + ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + if (ret) + return; + + /* If in FSM mode, just unvote it */ + if (val & PLL_VOTE_FSM_ENA) { + clk_disable_regmap(hw); + return; + } + + /* Disable Global PLL outputs */ + ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + PLL_OUTCTRL, 0); + if (ret) + return; + + /* Disable the main PLL output */ + ret = regmap_update_bits(pll->clkr.regmap, off + TRION_PLL_USER_CTL, + TRION_PLL_OUT_MASK, 0); + if (ret) + return; + + /* Place the PLL into STANDBY mode */ + regmap_write(pll->clkr.regmap, off + TRION_PLL_OPMODE, PLL_STANDBY); + + regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + PLL_RESET_N, PLL_RESET_N); +} + +static unsigned long +clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + u32 l, frac = 0; + u64 prate = parent_rate; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 off = pll->offset; + + regmap_read(pll->clkr.regmap, off + PLL_L_VAL, &l); + regmap_read(pll->clkr.regmap, off + TRION_PLL_ALPHA_VAL, &frac); + + return alpha_pll_calc_rate(pll, prate, l, frac); +} + +static int clk_trion_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + unsigned long rrate; + bool is_enabled; + int ret; + u32 l = 0, val = 0, off = pll->offset; + u64 a = 0; + + rrate = alpha_pll_round_rate(pll, rate, prate, &l, &a); + /* + * Due to limited number of bits for fractional rate programming, the + * rounded up rate could be marginally higher than the requested rate. + */ + if (rrate > (rate + ALPHA_16_BIT_PLL_RATE_MARGIN) || rrate < rate) { + pr_err("Trion_pll: Call clk_set_rate with rounded rates!\n"); + return -EINVAL; + } + + is_enabled = clk_hw_is_enabled(hw); + + if (is_enabled) + hw->init->ops->disable(hw); + + regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l); + regmap_write(pll->clkr.regmap, off + TRION_PLL_ALPHA_VAL, a); + + ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + if (ret) + return ret; + + /* + * If PLL is in Standby or RUN mode then only latch the L value + * Else PLL is in OFF mode and just configure L register - as per + * HPG no need to latch input. + */ + if (val & PLL_RESET_N) + clk_alpha_pll_latch_l_val(pll); + + if (is_enabled) + hw->init->ops->enable(hw); + + /* Wait for PLL output to stabilize */ + udelay(100); + + return ret; +} + +static int clk_trion_pll_is_enabled(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + + return trion_pll_is_enabled(pll, pll->clkr.regmap); +} + +static void clk_trion_pll_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + int size, i, val; + + static struct clk_register_data data[] = { + {"PLL_MODE", 0x0}, + {"PLL_L_VAL", 0x4}, + {"PLL_USER_CTL", 0xc}, + {"PLL_USER_CTL_U", 0x10}, + {"PLL_USER_CTL_U1", 0x14}, + {"PLL_CONFIG_CTL", 0x18}, + {"PLL_CONFIG_CTL_U", 0x1c}, + {"PLL_CONFIG_CTL_U1", 0x20}, + {"PLL_OPMODE", 0x38}, + }; + + static struct clk_register_data data1[] = { + {"APSS_PLL_VOTE", 0x0}, + }; + + size = ARRAY_SIZE(data); + + for (i = 0; i < size; i++) { + regmap_read(pll->clkr.regmap, pll->offset + data[i].offset, + &val); + seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); + } + + regmap_read(pll->clkr.regmap, pll->offset + data[0].offset, &val); + + if (val & PLL_VOTE_FSM_ENA) { + regmap_read(pll->clkr.regmap, pll->clkr.enable_reg + + data1[0].offset, &val); + seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val); + } +} + +const struct clk_ops clk_trion_pll_ops = { + .enable = clk_trion_pll_enable, + .disable = clk_trion_pll_disable, + .recalc_rate = clk_trion_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = clk_trion_pll_set_rate, + .is_enabled = clk_trion_pll_is_enabled, + .list_registers = clk_trion_pll_list_registers, +}; +EXPORT_SYMBOL(clk_trion_pll_ops); + +const struct clk_ops clk_trion_fixed_pll_ops = { + .enable = clk_trion_pll_enable, + .disable = clk_trion_pll_disable, + .recalc_rate = clk_trion_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .is_enabled = clk_trion_pll_is_enabled, + .list_registers = clk_trion_pll_list_registers, +}; +EXPORT_SYMBOL(clk_trion_fixed_pll_ops); + +static unsigned long clk_trion_pll_postdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + u32 i, cal_div = 1, val; + + if (!pll->post_div_table) { + pr_err("Missing the post_div_table for the PLL\n"); + return -EINVAL; + } + + regmap_read(pll->clkr.regmap, pll->offset + TRION_PLL_USER_CTL, &val); + + val >>= pll->post_div_shift; + val &= PLL_POST_DIV_MASK; + + for (i = 0; i < pll->num_post_div; i++) { + if (pll->post_div_table[i].val == val) { + cal_div = pll->post_div_table[i].div; + break; + } + } + + return (parent_rate / cal_div); +} + +static long clk_trion_pll_postdiv_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *prate) +{ + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + + if (!pll->post_div_table) + return -EINVAL; + + return divider_round_rate(hw, rate, prate, pll->post_div_table, + pll->width, CLK_DIVIDER_ROUND_CLOSEST); +} + +static int clk_trion_pll_postdiv_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + int i, val = 0, cal_div, ret; + + /* + * If the PLL is in FSM mode, then treat the set_rate callback + * as a no-operation. + */ + ret = regmap_read(pll->clkr.regmap, pll->offset + PLL_MODE, &val); + if (ret) + return ret; + + if (val & PLL_VOTE_FSM_ENA) + return 0; + + if (!pll->post_div_table) { + pr_err("Missing the post_div_table for the PLL\n"); + return -EINVAL; + } + + cal_div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); + for (i = 0; i < pll->num_post_div; i++) { + if (pll->post_div_table[i].div == cal_div) { + val = pll->post_div_table[i].val; + break; + } + } + + return regmap_update_bits(pll->clkr.regmap, + pll->offset + TRION_PLL_USER_CTL, + PLL_POST_DIV_MASK << pll->post_div_shift, + val << pll->post_div_shift); +} + +const struct clk_ops clk_trion_pll_postdiv_ops = { + .recalc_rate = clk_trion_pll_postdiv_recalc_rate, + .round_rate = clk_trion_pll_postdiv_round_rate, + .set_rate = clk_trion_pll_postdiv_set_rate, +}; +EXPORT_SYMBOL(clk_trion_pll_postdiv_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index 2656cd6314f61138aedaf1dd2892891371288fe3..c5fecb12cf6f5e946df43ac8bf48fb3562aada85 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -27,6 +27,7 @@ struct pll_vco { enum pll_type { ALPHA_PLL, FABIA_PLL, + TRION_PLL, }; /** @@ -35,7 +36,7 @@ enum pll_type { * @inited: flag that's set when the PLL is initialized * @vco_table: array of VCO settings * @clkr: regmap clock handle - * @is_fabia: Set if the PLL type is FABIA + * @pll_type: Specify the type of PLL */ struct clk_alpha_pll { u32 offset; @@ -79,10 +80,15 @@ extern const struct clk_ops clk_alpha_pll_postdiv_ops; extern const struct clk_ops clk_fabia_pll_ops; extern const struct clk_ops clk_fabia_fixed_pll_ops; extern const struct clk_ops clk_generic_pll_postdiv_ops; +extern const struct clk_ops clk_trion_pll_ops; +extern const struct clk_ops clk_trion_fixed_pll_ops; +extern const struct clk_ops clk_trion_pll_postdiv_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct pll_config *config); void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct pll_config *config); +int clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct pll_config *config); #endif diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c index f698a554da7714a492059e86bdfa1cdb743f18f0..e2bfe422f174b7c132993c89349ff99cbb2ce47e 100644 --- a/drivers/clk/qcom/clk-aop-qmp.c +++ b/drivers/clk/qcom/clk-aop-qmp.c @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ -#define pr_fmt(fmt) "%s: " fmt, __func__ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ #include #include @@ -30,7 +30,7 @@ struct qmp_pkt { void *data; }; -#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate) \ +#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate, _flags) \ static struct clk_aop_qmp _name = { \ .msg.class = #_class, \ .msg.res = #_res, \ @@ -40,7 +40,7 @@ struct qmp_pkt { .ops = &aop_qmp_clk_ops, \ .name = #_name, \ .num_parents = 0, \ - .flags = CLK_ENABLE_HAND_OFF, \ + .flags = _flags, \ }, \ } @@ -139,6 +139,12 @@ static int clk_aop_qmp_prepare(struct clk_hw *hw) struct clk_aop_qmp *clk = to_aop_qmp_clk(hw); mutex_lock(&clk_aop_lock); + /* + * Return early if the clock has been enabled already. This + * is to avoid issues with sending duplicate enable requests. + */ + if (clk->enabled) + goto err; if (clk->level) rate = clk->level; @@ -179,6 +185,9 @@ static void clk_aop_qmp_unprepare(struct clk_hw *hw) mutex_lock(&clk_aop_lock); + if (!clk->enabled) + goto err; + rate = clk->disable_state; snprintf(mbox_msg, MAX_LEN, "{class: %s, res: %s, val: %ld}", @@ -214,13 +223,25 @@ static const struct clk_ops aop_qmp_clk_ops = { .is_enabled = clk_aop_qmp_is_enabled, }; -DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss, - QDSS_CLK_LEVEL_DYNAMIC, QDSS_CLK_LEVEL_OFF); +DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss, QDSS_CLK_LEVEL_DYNAMIC, + QDSS_CLK_LEVEL_OFF, CLK_ENABLE_HAND_OFF); +DEFINE_CLK_AOP_QMP(qdss_ao_qmp_clk, clock, qdss_ao, QDSS_CLK_LEVEL_DYNAMIC, + QDSS_CLK_LEVEL_OFF, 0); static struct clk_hw *aop_qmp_clk_hws[] = { [QDSS_CLK] = &qdss_qmp_clk.hw, + [QDSS_AO_CLK] = &qdss_ao_qmp_clk.hw, }; +/* + * Due to HW limitations on v1, the qdss_ao clock was not supported by the clock + * driver on AOP. + */ +static void aop_qmp_fixup_v1(void) +{ + aop_qmp_clk_hws[QDSS_AO_CLK] = NULL; +} + static int qmp_update_client(struct clk_hw *hw, struct device *dev, struct mbox_chan *mbox) { @@ -250,7 +271,7 @@ static int qmp_update_client(struct clk_hw *hw, struct device *dev, static int aop_qmp_clk_probe(struct platform_device *pdev) { - struct clk *clk; + struct clk *clk = NULL; struct device_node *np = pdev->dev.of_node; struct mbox_chan *mbox = NULL; int num_clks = ARRAY_SIZE(aop_qmp_clk_hws); @@ -264,7 +285,12 @@ static int aop_qmp_clk_probe(struct platform_device *pdev) if (ret < 0) return ret; + if (of_device_is_compatible(pdev->dev.of_node, "qcom,aop-qmp-clk-v1")) + aop_qmp_fixup_v1(); + for (i = 1; i < num_clks; i++) { + if (!aop_qmp_clk_hws[i]) + continue; ret = qmp_update_client(aop_qmp_clk_hws[i], &pdev->dev, mbox); if (ret < 0) { dev_err(&pdev->dev, "Failed to update QMP client %d\n", @@ -273,13 +299,17 @@ static int aop_qmp_clk_probe(struct platform_device *pdev) } } - for (i = 0; i < num_clks; i++) { - ret = clk_aop_qmp_prepare(aop_qmp_clk_hws[i]); - if (ret < 0) - goto fail; - } + /* + * Proxy vote on the QDSS clock. This is needed to avoid issues with + * excessive requests on the QMP layer during the QDSS driver probe. + */ + ret = clk_aop_qmp_prepare(&qdss_qmp_clk.hw); + if (ret < 0) + goto fail; for (i = 0; i < num_clks; i++) { + if (!aop_qmp_clk_hws[i]) + continue; clk = devm_clk_register(&pdev->dev, aop_qmp_clk_hws[i]); if (IS_ERR(clk)) { ret = PTR_ERR(clk); @@ -303,7 +333,8 @@ static int aop_qmp_clk_probe(struct platform_device *pdev) } static const struct of_device_id aop_qmp_clk_of_match[] = { - { .compatible = "qcom,aop-qmp-clk", }, + { .compatible = "qcom,aop-qmp-clk-v1" }, + { .compatible = "qcom,aop-qmp-clk-v2" }, {} }; diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 51a5e0b1a53d1c4894be9423d90e4de025e6c137..fa0ca364c0234fbbbc939d9f57941fc5456fa281 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -90,14 +92,14 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling, } else if (br->halt_check == BRANCH_HALT_ENABLE || br->halt_check == BRANCH_HALT || (enabling && voted)) { - int count = 200; + int count = 500; while (count-- > 0) { if (check_halt(br, enabling)) return 0; udelay(1); } - WARN(1, "%s status stuck at 'o%s'", name, + WARN(1, "clk: %s status stuck at 'o%s'", name, enabling ? "ff" : "n"); return -EBUSY; } @@ -285,20 +287,30 @@ static int clk_branch2_enable(struct clk_hw *hw) static int clk_branch2_prepare(struct clk_hw *hw) { - struct clk_branch *branch = to_clk_branch(hw); - struct clk_hw *parent = clk_hw_get_parent(hw); - unsigned long curr_rate, branch_rate = branch->rate; + struct clk_branch *branch; + struct clk_hw *parent; + unsigned long curr_rate; int ret = 0; + if (!hw) + return -EINVAL; + + branch = to_clk_branch(hw); + parent = clk_hw_get_parent(hw); + if (!branch) + return -EINVAL; + /* * Do the rate aggregation and scaling of the RCG in the prepare/ * unprepare functions to avoid potential RPM(/h) communication due to * votes on the voltage rails. */ if (branch->aggr_sibling_rates) { + if (!parent) + return -EINVAL; curr_rate = clk_aggregate_rate(hw, parent->core); - if (branch_rate > curr_rate) { - ret = clk_set_rate(parent->clk, branch_rate); + if (branch->rate > curr_rate) { + ret = clk_set_rate(parent->clk, branch->rate); if (ret) goto exit; } @@ -314,13 +326,23 @@ static void clk_branch2_disable(struct clk_hw *hw) static void clk_branch2_unprepare(struct clk_hw *hw) { - struct clk_branch *branch = to_clk_branch(hw); - struct clk_hw *parent = clk_hw_get_parent(hw); - unsigned long curr_rate, new_rate, branch_rate = branch->rate; + struct clk_branch *branch; + struct clk_hw *parent; + unsigned long curr_rate, new_rate; + + if (!hw) + return; + + branch = to_clk_branch(hw); + parent = clk_hw_get_parent(hw); + if (!branch) + return; if (branch->aggr_sibling_rates) { + if (!parent) + return; new_rate = clk_aggregate_rate(hw, parent->core); - curr_rate = max(new_rate, branch_rate); + curr_rate = max(new_rate, branch->rate); if (new_rate < curr_rate) if (clk_set_rate(parent->clk, new_rate)) pr_err("Failed to scale %s to %lu\n", @@ -343,6 +365,72 @@ const struct clk_ops clk_branch2_ops = { }; EXPORT_SYMBOL_GPL(clk_branch2_ops); +static int clk_branch2_hw_ctl_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + if (!(hw->init->flags & CLK_SET_RATE_PARENT)) { + pr_err("SET_RATE_PARENT flag needs to be set for %s\n", + clk_hw_get_name(hw)); + return -EINVAL; + } + + return 0; +} + +static unsigned long clk_branch2_hw_ctl_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate; +} + +static int clk_branch2_hw_ctl_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *clkp; + + clkp = clk_hw_get_parent(hw); + if (!clkp) + return -EINVAL; + + req->best_parent_hw = clkp; + req->best_parent_rate = clk_round_rate(clkp->clk, req->rate); + + return 0; +} + +static int clk_branch2_hw_ctl_enable(struct clk_hw *hw) +{ + struct clk_hw *parent = clk_hw_get_parent(hw); + + /* The parent branch clock should have been prepared prior to this. */ + if (!parent || (parent && !clk_hw_is_prepared(parent))) + return -EINVAL; + + return clk_enable_regmap(hw); +} + +static void clk_branch2_hw_ctl_disable(struct clk_hw *hw) +{ + struct clk_hw *parent = clk_hw_get_parent(hw); + + if (!parent) + return; + + clk_disable_regmap(hw); +} + +const struct clk_ops clk_branch2_hw_ctl_ops = { + .enable = clk_branch2_hw_ctl_enable, + .disable = clk_branch2_hw_ctl_disable, + .is_enabled = clk_is_enabled_regmap, + .set_rate = clk_branch2_hw_ctl_set_rate, + .recalc_rate = clk_branch2_hw_ctl_recalc_rate, + .determine_rate = clk_branch2_hw_ctl_determine_rate, + .set_flags = clk_branch_set_flags, + .list_registers = clk_branch2_list_registers, +}; +EXPORT_SYMBOL_GPL(clk_branch2_hw_ctl_ops); + static int clk_gate_toggle(struct clk_hw *hw, bool en) { struct clk_gate2 *gt = to_clk_gate2(hw); diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 51209ea7a0a5178f4972271ba221d984b62b170f..f0fb6d58461b2a9d67f9c2da667bf250a02bb85b 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -64,6 +64,7 @@ struct clk_gate2 { extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; +extern const struct clk_ops clk_branch2_hw_ctl_ops; extern const struct clk_ops clk_gate2_ops; extern const struct clk_ops clk_branch_simple_ops; diff --git a/drivers/clk/qcom/clk-cpu-a7.c b/drivers/clk/qcom/clk-cpu-a7.c new file mode 100644 index 0000000000000000000000000000000000000000..3e8a75d974b84544dfd384b8888f3d18311d0603 --- /dev/null +++ b/drivers/clk/qcom/clk-cpu-a7.c @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2017, 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 +#include +#include +#include +#include +#include +#include +#include + +#include "clk-alpha-pll.h" +#include "clk-debug.h" +#include "clk-rcg.h" +#include "clk-regmap-mux-div.h" +#include "common.h" +#include "vdd-level-sdm845.h" + +#define SYS_APC0_AUX_CLK_SRC 1 + +#define PLL_MODE_REG 0x0 +#define PLL_OPMODE_RUN 0x1 +#define PLL_OPMODE_REG 0x38 +#define PLL_MODE_OUTCTRL BIT(0) + +#define to_clk_regmap_mux_div(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr) + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); +static DEFINE_VDD_REGS_INIT(vdd_cpu, 1); + +enum apcs_clk_parent_index { + XO_AO_INDEX, + SYS_APC0_AUX_CLK_INDEX, + APCS_CPU_PLL_INDEX, +}; + +enum { + P_SYS_APC0_AUX_CLK, + P_APCS_CPU_PLL, + P_BI_TCXO_AO, +}; + +static const struct parent_map apcs_clk_parent_map[] = { + [XO_AO_INDEX] = { P_BI_TCXO_AO, 0 }, + [SYS_APC0_AUX_CLK_INDEX] = { P_SYS_APC0_AUX_CLK, 1 }, + [APCS_CPU_PLL_INDEX] = { P_APCS_CPU_PLL, 5 }, +}; + +static const char *const apcs_clk_parent_name[] = { + [XO_AO_INDEX] = "bi_tcxo_ao", + [SYS_APC0_AUX_CLK_INDEX] = "sys_apc0_aux_clk", + [APCS_CPU_PLL_INDEX] = "apcs_cpu_pll", +}; + +static int a7cc_clk_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u8 index) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(cpuclk, cpuclk->parent_map[index].cfg, + cpuclk->div); +} + +static int a7cc_clk_set_parent(struct clk_hw *hw, u8 index) +{ + /* + * Since a7cc_clk_set_rate_and_parent() is defined and set_parent() + * will never gets called from clk_change_rate() so return 0. + */ + return 0; +} + +static int a7cc_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + + /* + * Parent is same as the last rate. + * Here just configure new div. + */ + return __mux_div_set_src_div(cpuclk, cpuclk->src, cpuclk->div); +} + +static int a7cc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int ret; + u32 div = 1; + struct clk_hw *xo, *apc0_auxclk_hw, *apcs_cpu_pll_hw; + unsigned long apc0_auxclk_rate, rate = req->rate; + struct clk_rate_request parent_req = { }; + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + unsigned long mask = BIT(cpuclk->hid_width) - 1; + + xo = clk_hw_get_parent_by_index(hw, XO_AO_INDEX); + if (rate == clk_hw_get_rate(xo)) { + req->best_parent_hw = xo; + req->best_parent_rate = rate; + cpuclk->div = div; + cpuclk->src = cpuclk->parent_map[XO_AO_INDEX].cfg; + return 0; + } + + apc0_auxclk_hw = clk_hw_get_parent_by_index(hw, SYS_APC0_AUX_CLK_INDEX); + apcs_cpu_pll_hw = clk_hw_get_parent_by_index(hw, APCS_CPU_PLL_INDEX); + + apc0_auxclk_rate = clk_hw_get_rate(apc0_auxclk_hw); + if (rate <= apc0_auxclk_rate) { + req->best_parent_hw = apc0_auxclk_hw; + req->best_parent_rate = apc0_auxclk_rate; + + div = DIV_ROUND_UP((2 * req->best_parent_rate), rate) - 1; + div = min_t(unsigned long, div, mask); + + req->rate = clk_rcg2_calc_rate(req->best_parent_rate, 0, + 0, 0, div); + cpuclk->src = cpuclk->parent_map[SYS_APC0_AUX_CLK_INDEX].cfg; + } else { + parent_req.rate = rate; + parent_req.best_parent_hw = apcs_cpu_pll_hw; + + req->best_parent_hw = apcs_cpu_pll_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; + + req->best_parent_rate = parent_req.rate; + cpuclk->src = cpuclk->parent_map[APCS_CPU_PLL_INDEX].cfg; + } + cpuclk->div = div; + + return 0; +} + +static void a7cc_clk_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + int i = 0, size = 0, val; + + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + }; + + size = ARRAY_SIZE(data); + for (i = 0; i < size; i++) { + regmap_read(cpuclk->clkr.regmap, + cpuclk->reg_offset + data[i].offset, &val); + seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); + } +} + +static unsigned long a7cc_clk_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + const char *name = clk_hw_get_name(hw); + struct clk_hw *parent; + int ret = 0; + unsigned long parent_rate; + u32 i, div, src = 0; + u32 num_parents = clk_hw_get_num_parents(hw); + + ret = mux_div_get_src_div(cpuclk, &src, &div); + if (ret) + return ret; + + for (i = 0; i < num_parents; i++) { + if (src == cpuclk->parent_map[i].cfg) { + parent = clk_hw_get_parent_by_index(hw, i); + parent_rate = clk_hw_get_rate(parent); + return clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div); + } + } + pr_err("%s: Can't find parent %d\n", name, src); + return ret; +} + +static int a7cc_clk_enable(struct clk_hw *hw) +{ + return clk_regmap_mux_div_ops.enable(hw); +} + +static void a7cc_clk_disable(struct clk_hw *hw) +{ + clk_regmap_mux_div_ops.disable(hw); +} + +static u8 a7cc_clk_get_parent(struct clk_hw *hw) +{ + return clk_regmap_mux_div_ops.get_parent(hw); +} + +/* + * We use the notifier function for switching to a temporary safe configuration + * (mux and divider), while the APSS pll is reconfigured. + */ +static int a7cc_notifier_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + int ret = 0; + struct clk_regmap_mux_div *cpuclk = container_of(nb, + struct clk_regmap_mux_div, clk_nb); + + if (event == PRE_RATE_CHANGE) + /* set the mux to safe source(sys_apc0_aux_clk) & div */ + ret = __mux_div_set_src_div(cpuclk, SYS_APC0_AUX_CLK_SRC, 1); + + if (event == ABORT_RATE_CHANGE) + pr_err("Error in configuring PLL - stay at safe src only\n"); + + return notifier_from_errno(ret); +} + +static const struct clk_ops a7cc_clk_ops = { + .enable = a7cc_clk_enable, + .disable = a7cc_clk_disable, + .get_parent = a7cc_clk_get_parent, + .set_rate = a7cc_clk_set_rate, + .set_parent = a7cc_clk_set_parent, + .set_rate_and_parent = a7cc_clk_set_rate_and_parent, + .determine_rate = a7cc_clk_determine_rate, + .recalc_rate = a7cc_clk_recalc_rate, + .debug_init = clk_debug_measure_add, + .list_registers = a7cc_clk_list_registers, +}; + +/* + * As per HW, sys_apc0_aux_clk runs at 300MHz and configured by BOOT + * So adding it as dummy clock. + */ + +static struct clk_dummy sys_apc0_aux_clk = { + .rrate = 300000000, + .hw.init = &(struct clk_init_data){ + .name = "sys_apc0_aux_clk", + .ops = &clk_dummy_ops, + }, +}; + +/* Initial configuration for 1497.6MHz(Turbo) */ +static const struct pll_config apcs_cpu_pll_config = { + .l = 0x4E, +}; + +static struct pll_vco trion_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +static struct clk_alpha_pll apcs_cpu_pll = { + .type = TRION_PLL, + .vco_table = trion_vco, + .num_vco = ARRAY_SIZE(trion_vco), + .clkr.hw.init = &(struct clk_init_data){ + .name = "apcs_cpu_pll", + .parent_names = (const char *[]){ "bi_tcxo_ao" }, + .num_parents = 1, + .ops = &clk_trion_pll_ops, + VDD_CX_FMAX_MAP4(LOWER, 345600000, + LOW, 576000000, + NOMINAL, 1094400000, + HIGH, 1497600000), + }, +}; + +static struct clk_regmap_mux_div apcs_clk = { + .hid_width = 5, + .hid_shift = 0, + .src_width = 3, + .src_shift = 8, + .safe_src = 1, + .safe_div = 1, + .parent_map = apcs_clk_parent_map, + .clk_nb.notifier_call = a7cc_notifier_cb, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apcs_clk", + .parent_names = apcs_clk_parent_name, + .num_parents = 3, + .vdd_class = &vdd_cpu, + .flags = CLK_SET_RATE_PARENT, + .ops = &a7cc_clk_ops, + }, +}; + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,cpu-sdxpoorwills" }, + {} +}; + +static const struct regmap_config cpu_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x7F10, + .fast_io = true, +}; + +static struct clk_hw *cpu_clks_hws[] = { + [SYS_APC0_AUX_CLK] = &sys_apc0_aux_clk.hw, + [APCS_CPU_PLL] = &apcs_cpu_pll.clkr.hw, + [APCS_CLK] = &apcs_clk.clkr.hw, +}; + +static void a7cc_clk_get_speed_bin(struct platform_device *pdev, int *bin, + int *version) +{ + struct resource *res; + void __iomem *base; + u32 pte_efuse, valid; + + *bin = 0; + *version = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse"); + if (!res) { + dev_info(&pdev->dev, + "No speed/PVS binning available. Defaulting to 0!\n"); + return; + } + + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!base) { + dev_info(&pdev->dev, + "Unable to read efuse data. Defaulting to 0!\n"); + return; + } + + pte_efuse = readl_relaxed(base); + devm_iounmap(&pdev->dev, base); + + *bin = pte_efuse & 0x7; + valid = (pte_efuse >> 3) & 0x1; + *version = (pte_efuse >> 4) & 0x3; + + if (!valid) { + dev_info(&pdev->dev, "Speed bin not set. Defaulting to 0!\n"); + *bin = 0; + } else { + dev_info(&pdev->dev, "Speed bin: %d\n", *bin); + } + + dev_info(&pdev->dev, "PVS version: %d\n", *version); +} + +static int a7cc_clk_get_fmax_vdd_class(struct platform_device *pdev, + struct clk_init_data *clk_intd, char *prop_name) +{ + struct device_node *of = pdev->dev.of_node; + int prop_len, i, j; + struct clk_vdd_class *vdd = clk_intd->vdd_class; + int num = vdd->num_regulators + 1; + u32 *array; + + if (!of_find_property(of, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % num) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + prop_len /= num; + vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int), + GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; + + vdd->vdd_uv = devm_kzalloc(&pdev->dev, + prop_len * sizeof(int) * (num - 1), GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; + + clk_intd->rate_max = devm_kzalloc(&pdev->dev, + prop_len * sizeof(unsigned long), GFP_KERNEL); + if (!clk_intd->rate_max) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, + prop_len * sizeof(u32) * num, GFP_KERNEL); + if (!array) + return -ENOMEM; + + of_property_read_u32_array(of, prop_name, array, prop_len * num); + for (i = 0; i < prop_len; i++) { + clk_intd->rate_max[i] = array[num * i]; + for (j = 1; j < num; j++) { + vdd->vdd_uv[(num - 1) * i + (j - 1)] = + array[num * i + j]; + } + } + + devm_kfree(&pdev->dev, array); + vdd->num_levels = prop_len; + vdd->cur_level = prop_len; + clk_intd->num_rate_max = prop_len; + + return 0; +} + +/* + * Find the voltage level required for a given clock rate. + */ +static int find_vdd_level(struct clk_init_data *clk_intd, unsigned long rate) +{ + int level; + + for (level = 0; level < clk_intd->num_rate_max; level++) + if (rate <= clk_intd->rate_max[level]) + break; + + if (level == clk_intd->num_rate_max) { + pr_err("Rate %lu for %s is greater than highest Fmax\n", rate, + clk_intd->name); + return -EINVAL; + } + + return level; +} + +static int +a7cc_clk_add_opp(struct clk_hw *hw, struct device *dev, unsigned long max_rate) +{ + unsigned long rate = 0; + int level, uv, j = 1; + long ret; + struct clk_init_data *clk_intd = (struct clk_init_data *)hw->init; + struct clk_vdd_class *vdd = clk_intd->vdd_class; + + if (IS_ERR_OR_NULL(dev)) { + pr_err("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + while (1) { + rate = clk_intd->rate_max[j++]; + level = find_vdd_level(clk_intd, rate); + if (level <= 0) { + pr_warn("clock-cpu: no corner for %lu.\n", rate); + return -EINVAL; + } + + uv = vdd->vdd_uv[level]; + if (uv < 0) { + pr_warn("clock-cpu: no uv for %lu.\n", rate); + return -EINVAL; + } + + ret = dev_pm_opp_add(dev, rate, uv); + if (ret) { + pr_warn("clock-cpu: failed to add OPP for %lu\n", rate); + return rate; + } + + if (rate >= max_rate) + break; + } + + return 0; +} + +static void a7cc_clk_print_opp_table(int a7_cpu) +{ + struct dev_pm_opp *oppfmax, *oppfmin; + unsigned long apc_fmax, apc_fmin; + u32 max_a7ss_index = apcs_clk.clkr.hw.init->num_rate_max; + + apc_fmax = apcs_clk.clkr.hw.init->rate_max[max_a7ss_index - 1]; + apc_fmin = apcs_clk.clkr.hw.init->rate_max[1]; + + rcu_read_lock(); + + oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu), + apc_fmax, true); + oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a7_cpu), + apc_fmin, true); + pr_info("Clock_cpu: OPP voltage for %lu: %ld\n", apc_fmin, + dev_pm_opp_get_voltage(oppfmin)); + pr_info("Clock_cpu: OPP voltage for %lu: %ld\n", apc_fmax, + dev_pm_opp_get_voltage(oppfmax)); + + rcu_read_unlock(); +} + +static void a7cc_clk_populate_opp_table(struct platform_device *pdev) +{ + unsigned long apc_fmax; + int cpu, a7_cpu = 0; + u32 max_a7ss_index = apcs_clk.clkr.hw.init->num_rate_max; + + apc_fmax = apcs_clk.clkr.hw.init->rate_max[max_a7ss_index - 1]; + + for_each_possible_cpu(cpu) { + a7_cpu = cpu; + WARN(a7cc_clk_add_opp(&apcs_clk.clkr.hw, get_cpu_device(cpu), + apc_fmax), + "Failed to add OPP levels for apcs_clk\n"); + } + /* One time print during bootup */ + dev_info(&pdev->dev, "OPP tables populated (cpu %d)\n", a7_cpu); + + a7cc_clk_print_opp_table(a7_cpu); +} + +static int a7cc_driver_probe(struct platform_device *pdev) +{ + struct clk *clk; + void __iomem *base; + u32 opmode_regval, mode_regval; + struct resource *res; + struct clk_onecell_data *data; + struct device *dev = &pdev->dev; + struct device_node *of = pdev->dev.of_node; + int i, ret, speed_bin, version, cpu; + int num_clks = ARRAY_SIZE(cpu_clks_hws); + u32 a7cc_clk_init_rate = 0; + char prop_name[] = "qcom,speedX-bin-vX"; + struct clk *ext_xo_clk; + + /* Require the RPMH-XO clock to be registered before */ + ext_xo_clk = devm_clk_get(dev, "xo_ao"); + if (IS_ERR(ext_xo_clk)) { + if (PTR_ERR(ext_xo_clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get xo clock\n"); + return PTR_ERR(ext_xo_clk); + } + + /* Get speed bin information */ + a7cc_clk_get_speed_bin(pdev, &speed_bin, &version); + + /* Rail Regulator for apcs_pll */ + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_ao"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_dig_ao regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + /* Rail Regulator for APSS a7ss mux */ + vdd_cpu.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd"); + if (IS_ERR(vdd_cpu.regulator[0])) { + if (!(PTR_ERR(vdd_cpu.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get cpu-vdd regulator\n"); + return PTR_ERR(vdd_cpu.regulator[0]); + } + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d", speed_bin, version); + + ret = a7cc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *)apcs_clk.clkr.hw.init, prop_name); + if (ret) { + dev_err(&pdev->dev, + "Can't get speed bin for apcs_clk. Falling back to zero\n"); + ret = a7cc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *)apcs_clk.clkr.hw.init, + "qcom,speed0-bin-v0"); + if (ret) { + dev_err(&pdev->dev, + "Unable to get speed bin for apcs_clk freq-corner mapping info\n"); + return ret; + } + } + + ret = of_property_read_u32(of, "qcom,a7cc-init-rate", + &a7cc_clk_init_rate); + if (ret) { + dev_err(&pdev->dev, + "unable to find qcom,a7cc_clk_init_rate property,ret=%d\n", + ret); + return -EINVAL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_pll"); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to map apcs_cpu_pll register base\n"); + return PTR_ERR(base); + } + + apcs_cpu_pll.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_cpu_pll.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs_cpu_pll\n"); + return PTR_ERR(apcs_cpu_pll.clkr.regmap); + } + + ret = of_property_read_u32(of, "qcom,rcg-reg-offset", + &apcs_clk.reg_offset); + if (ret) { + dev_err(&pdev->dev, + "unable to find qcom,rcg-reg-offset property,ret=%d\n", + ret); + return -EINVAL; + } + + apcs_clk.clkr.regmap = apcs_cpu_pll.clkr.regmap; + + /* Read PLLs OPMODE and mode register */ + ret = regmap_read(apcs_cpu_pll.clkr.regmap, PLL_OPMODE_REG, + &opmode_regval); + if (ret) + return ret; + + ret = regmap_read(apcs_cpu_pll.clkr.regmap, PLL_MODE_REG, + &mode_regval); + if (ret) + return ret; + + /* Configure APSS PLL only if it is not enabled and running */ + if (!(opmode_regval & PLL_OPMODE_RUN) && + !(mode_regval & PLL_MODE_OUTCTRL)) + clk_trion_pll_configure(&apcs_cpu_pll, + apcs_cpu_pll.clkr.regmap, &apcs_cpu_pll_config); + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->clk_num = num_clks; + + data->clks = devm_kzalloc(dev, num_clks * sizeof(struct clk *), + GFP_KERNEL); + if (!data->clks) + return -ENOMEM; + + /* Register clocks with clock framework */ + for (i = 0; i < num_clks; i++) { + clk = devm_clk_register(dev, cpu_clks_hws[i]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + data->clks[i] = clk; + } + + ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + if (ret) { + dev_err(&pdev->dev, "CPU clock driver registeration failed\n"); + return ret; + } + + ret = clk_notifier_register(apcs_cpu_pll.clkr.hw.clk, &apcs_clk.clk_nb); + if (ret) { + dev_err(dev, "failed to register clock notifier: %d\n", ret); + return ret; + } + + /* Put proxy vote for APSS PLL */ + clk_prepare_enable(apcs_cpu_pll.clkr.hw.clk); + + /* Reconfigure APSS RCG */ + ret = clk_set_rate(apcs_clk.clkr.hw.clk, sys_apc0_aux_clk.rrate); + if (ret) + dev_err(&pdev->dev, "Unable to set aux rate on apcs_clk\n"); + + /* Set to TURBO boot frequency */ + ret = clk_set_rate(apcs_clk.clkr.hw.clk, a7cc_clk_init_rate); + if (ret) + dev_err(&pdev->dev, "Unable to set init rate on apcs_clk\n"); + + /* + * We don't want the CPU clocks to be turned off at late init + * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the + * refcount of these clocks. Any cpufreq/hotplug manager can assume + * that the clocks have already been prepared and enabled by the time + * they take over. + */ + + get_online_cpus(); + for_each_online_cpu(cpu) + WARN(clk_prepare_enable(apcs_clk.clkr.hw.clk), + "Unable to turn on CPU clock\n"); + put_online_cpus(); + + /* Remove proxy vote for APSS PLL */ + clk_disable_unprepare(apcs_cpu_pll.clkr.hw.clk); + + a7cc_clk_populate_opp_table(pdev); + + dev_info(dev, "CPU clock Driver probed successfully\n"); + + return ret; +} + +static struct platform_driver a7_clk_driver = { + .probe = a7cc_driver_probe, + .driver = { + .name = "qcom-cpu-sdxpoorwills", + .of_match_table = match_table, + }, +}; + +static int __init a7_clk_init(void) +{ + return platform_driver_register(&a7_clk_driver); +} +subsys_initcall(a7_clk_init); + +static void __exit a7_clk_exit(void) +{ + platform_driver_unregister(&a7_clk_driver); +} +module_exit(a7_clk_exit); + +MODULE_ALIAS("platform:cpu"); +MODULE_DESCRIPTION("A7 CPU clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 035d3371e265938a7c709c7fe3e6fc3c65329ef4..b6204cb5a72ecdd03acd4f394410c1647feb1462 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -11,14 +11,13 @@ * GNU General Public License for more details. */ -#define pr_fmt(fmt) "%s: " fmt, __func__ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ #include #include #include #include #include -#include #include #include #include @@ -27,261 +26,100 @@ #include #include #include -#include #include -#include -#include #include #include -#include +#include +#include +#include #include +#include #include "common.h" #include "clk-regmap.h" -#include "clk-rcg.h" #include "clk-voter.h" +#include "clk-debug.h" +#define OSM_INIT_RATE 300000000UL +#define XO_RATE 19200000UL #define OSM_TABLE_SIZE 40 #define SINGLE_CORE 1 #define MAX_CLUSTER_CNT 3 #define MAX_MEM_ACC_VAL_PER_LEVEL 3 -#define MAX_CORE_COUNT 4 #define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16) -#define OSM_CYCLE_COUNTER_CTRL_REG 0x760 -#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8) - #define OSM_REG_SIZE 32 -#define L3_EFUSE_SHIFT 0 -#define L3_EFUSE_MASK 0 -#define PWRCL_EFUSE_SHIFT 0 -#define PWRCL_EFUSE_MASK 0 -#define PERFCL_EFUSE_SHIFT 29 -#define PERFCL_EFUSE_MASK 0x7 - #define ENABLE_REG 0x0 #define FREQ_REG 0x110 #define VOLT_REG 0x114 -#define OVERRIDE_REG 0x118 -#define SPM_CC_INC_HYSTERESIS 0x1c -#define SPM_CC_DEC_HYSTERESIS 0x20 -#define SPM_CORE_INACTIVE_MAPPING 0x28 -#define CC_ZERO_BEHAV_CTRL 0xc -#define ENABLE_OVERRIDE BIT(0) -#define SPM_CC_DCVS_DISABLE 0x24 -#define LLM_FREQ_VOTE_INC_HYSTERESIS 0x30 -#define LLM_FREQ_VOTE_DEC_HYSTERESIS 0x34 -#define LLM_INTF_DCVS_DISABLE 0x40 -#define LLM_VOLTAGE_VOTE_INC_HYSTERESIS 0x38 -#define LLM_VOLTAGE_VOTE_DEC_HYSTERESIS 0x3c -#define VMIN_REDUCTION_ENABLE_REG 0x48 -#define VMIN_REDUCTION_TIMER_REG 0x4c -#define PDN_FSM_CTRL_REG 0x54 -#define DELTA_DEX_VAL BVAL(31, 23, 0xa) -#define IGNORE_PLL_LOCK BIT(15) -#define CC_BOOST_FSM_EN BIT(0) -#define CC_BOOST_FSM_TIMERS_REG0 0x58 -#define CC_BOOST_FSM_TIMERS_REG1 0x5c -#define CC_BOOST_FSM_TIMERS_REG2 0x60 -#define DCVS_BOOST_FSM_EN_MASK BIT(2) -#define DCVS_BOOST_FSM_TIMERS_REG0 0x64 -#define DCVS_BOOST_FSM_TIMERS_REG1 0x68 -#define DCVS_BOOST_FSM_TIMERS_REG2 0x6c -#define PS_BOOST_FSM_EN_MASK BIT(1) -#define PS_BOOST_FSM_TIMERS_REG0 0x74 -#define PS_BOOST_FSM_TIMERS_REG1 0x78 -#define PS_BOOST_FSM_TIMERS_REG2 0x7c -#define BOOST_PROG_SYNC_DELAY_REG 0x80 -#define DCVS_DROOP_FSM_EN_MASK BIT(5) -#define DROOP_PROG_SYNC_DELAY_REG 0x9c -#define DROOP_RELEASE_TIMER_CTRL 0x88 -#define DROOP_CTRL_REG 0x84 -#define DCVS_DROOP_TIMER_CTRL 0x98 -#define PLL_SW_OVERRIDE_ENABLE 0xa0 -#define PLL_SW_OVERRIDE_DROOP_EN BIT(0) -#define SPM_CORE_COUNT_CTRL 0x2c #define CORE_DCVS_CTRL 0xbc -#define OVERRIDE_CLUSTER_IDLE_ACK 0x800 -#define REQ_GEN_FSM_STATUS 0x70c - -#define PLL_MIN_LVAL 0x21 -#define PLL_MIN_FREQ_REG 0x94 -#define PLL_POST_DIV1 0x1F -#define PLL_POST_DIV2 0x11F -#define PLL_MODE 0x0 -#define PLL_L_VAL 0x4 -#define PLL_USER_CTRL 0xc -#define PLL_CONFIG_CTL_LO 0x10 -#define PLL_CONFIG_CTL_HI 0x14 -#define MIN_VCO_VAL 0x2b - -#define MAX_VC 63 -#define MAX_MEM_ACC_LEVELS 3 -#define MAX_MEM_ACC_VAL_PER_LEVEL 3 -#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \ - MAX_MEM_ACC_VAL_PER_LEVEL) -#define MEM_ACC_ADDRS 3 - -#define ISENSE_ON_DATA 0xf -#define ISENSE_OFF_DATA 0x0 -#define CONSTANT_32 0x20 - -#define APM_MX_MODE 0x0 -#define APM_APC_MODE 0x2 -#define APM_READ_DATA_MASK 0xc -#define APM_MX_MODE_VAL 0x4 -#define APM_APC_READ_VAL 0x8 -#define APM_MX_READ_VAL 0x4 -#define APM_CROSSOVER_VC 0xb0 - -#define MEM_ACC_SEQ_CONST(n) (n) -#define MEM_ACC_APM_READ_MASK 0xff -#define MEMACC_CROSSOVER_VC 0xb8 - -#define PLL_WAIT_LOCK_TIME_US 10 -#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000) -#define SAFE_FREQ_WAIT_NS 5000 -#define DEXT_DECREMENT_WAIT_NS 1000 - -#define DATA_MEM(n) (0x400 + (n) * 4) - -#define DCVS_PERF_STATE_DESIRED_REG_0 0x780 -#define DCVS_PERF_STATE_DESIRED_REG(n) (DCVS_PERF_STATE_DESIRED_REG_0 + \ - (4 * n)) -#define OSM_CYCLE_COUNTER_STATUS_REG_0 0x7d0 -#define OSM_CYCLE_COUNTER_STATUS_REG(n) (OSM_CYCLE_COUNTER_STATUS_REG_0 + \ - (4 * n)) - -static const struct regmap_config osm_qcom_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .fast_io = true, -}; -enum clk_osm_bases { - OSM_BASE, - PLL_BASE, - EFUSE_BASE, - SEQ_BASE, - NUM_BASES, -}; +#define DCVS_PERF_STATE_DESIRED_REG_0_V1 0x780 +#define DCVS_PERF_STATE_DESIRED_REG_0_V2 0x920 +#define DCVS_PERF_STATE_DESIRED_REG(n, v1) \ + (((v1) ? DCVS_PERF_STATE_DESIRED_REG_0_V1 \ + : DCVS_PERF_STATE_DESIRED_REG_0_V2) + 4 * (n)) -enum clk_osm_lut_data { - FREQ, - FREQ_DATA, - PLL_OVERRIDES, - MEM_ACC_LEVEL, - VIRTUAL_CORNER, - NUM_FIELDS, -}; +#define OSM_CYCLE_COUNTER_STATUS_REG_0_V1 0x7d0 +#define OSM_CYCLE_COUNTER_STATUS_REG_0_V2 0x9c0 +#define OSM_CYCLE_COUNTER_STATUS_REG(n, v1) \ + (((v1) ? OSM_CYCLE_COUNTER_STATUS_REG_0_V1 \ + : OSM_CYCLE_COUNTER_STATUS_REG_0_V2) + 4 * (n)) + +static DEFINE_VDD_REGS_INIT(vdd_l3_mx_ao, 1); +static DEFINE_VDD_REGS_INIT(vdd_pwrcl_mx_ao, 1); struct osm_entry { u16 virtual_corner; u16 open_loop_volt; - u32 freq_data; - u32 override_data; - u32 mem_acc_level; long frequency; + u16 ccount; }; struct clk_osm { struct clk_hw hw; struct osm_entry osm_table[OSM_TABLE_SIZE]; struct dentry *debugfs; - struct regulator *vdd_reg; - struct platform_device *vdd_dev; - void *vbases[NUM_BASES]; - unsigned long pbases[NUM_BASES]; + void __iomem *vbase; + phys_addr_t pbase; spinlock_t lock; - - u32 cpu_reg_mask; + bool per_core_dcvs; u32 num_entries; u32 cluster_num; u32 core_num; - u32 apm_crossover_vc; - u32 apm_threshold_vc; - u32 mem_acc_crossover_vc; - u32 mem_acc_threshold_vc; - u32 min_cpr_vc; - u32 cycle_counter_reads; - u32 cycle_counter_delay; - u32 cycle_counter_factor; + unsigned long rate; u64 total_cycle_counter; u32 prev_cycle_counter; - u32 l_val_base; - u32 apcs_pll_user_ctl; - u32 apcs_pll_min_freq; - u32 cfg_gfmux_addr; - u32 apcs_cbc_addr; - u32 speedbin; - u32 mem_acc_crossover_vc_addr; - u32 mem_acc_addr[MEM_ACC_ADDRS]; - u32 ramp_ctl_addr; - u32 apm_mode_ctl; - u32 apm_status_ctl; - u32 osm_clk_rate; - u32 xo_clk_rate; - bool secure_init; - bool per_core_dcvs; - bool red_fsm_en; - bool boost_fsm_en; - bool safe_fsm_en; - bool ps_fsm_en; - bool droop_fsm_en; - - struct notifier_block panic_notifier; - u32 trace_periodic_timer; - bool trace_en; - bool wdog_trace_en; + u32 max_core_count; + u32 mx_turbo_freq; }; -static struct regulator *vdd_l3; -static struct regulator *vdd_pwrcl; -static struct regulator *vdd_perfcl; +static bool is_sdm845v1; static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw) { return container_of(_hw, struct clk_osm, hw); } -static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val, - u32 offset, u32 mask) -{ - u32 val2, orig_val; - - val2 = orig_val = readl_relaxed((char *)c->vbases[OSM_BASE] + offset); - val2 &= ~mask; - val2 |= val & mask; - - if (val2 != orig_val) - writel_relaxed(val2, (char *)c->vbases[OSM_BASE] + offset); -} - -static inline void clk_osm_write_seq_reg(struct clk_osm *c, u32 val, u32 offset) -{ - writel_relaxed(val, (char *)c->vbases[SEQ_BASE] + offset); -} - static inline void clk_osm_write_reg(struct clk_osm *c, u32 val, u32 offset) { - writel_relaxed(val, (char *)c->vbases[OSM_BASE] + offset); + writel_relaxed(val, c->vbase + offset); } static inline int clk_osm_read_reg(struct clk_osm *c, u32 offset) { - return readl_relaxed((char *)c->vbases[OSM_BASE] + offset); + return readl_relaxed(c->vbase + offset); } static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset) { - return readl_relaxed_no_log((char *)c->vbases[OSM_BASE] + offset); + return readl_relaxed_no_log(c->vbase + offset); } -static inline int clk_osm_mb(struct clk_osm *c, int base) +static inline int clk_osm_mb(struct clk_osm *c) { - return readl_relaxed_no_log((char *)c->vbases[base] + ENABLE_REG); + return readl_relaxed_no_log(c->vbase + ENABLE_REG); } static long clk_osm_list_rate(struct clk_hw *hw, unsigned int n, @@ -301,12 +139,45 @@ static inline bool is_better_rate(unsigned long req, unsigned long best, return (req <= new && new < best) || (best < req && best < new); } +static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) +{ + int index; + + for (index = 0; index < entries; index++) { + if (rate == table[index].frequency) + return index; + } + + return -EINVAL; +} + +static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_osm *c = to_clk_osm(hw); + + c->rate = rate; + + return 0; +} + +static unsigned long clk_osm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_osm *c = to_clk_osm(hw); + + return c->rate; +} + static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { int i; unsigned long rrate = 0; + if (!hw) + return -EINVAL; + /* * If the rate passed in is 0, return the first frequency in the * FMAX table. @@ -328,92 +199,61 @@ static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate, return rrate; } -static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) +static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - int quad_core_index, single_core_index = 0; - int core_count; - - for (quad_core_index = 0; quad_core_index < entries; - quad_core_index++) { - core_count = CORE_COUNT_VAL(table[quad_core_index].freq_data); - if (rate == table[quad_core_index].frequency && - core_count == SINGLE_CORE) { - single_core_index = quad_core_index; - continue; - } - if (rate == table[quad_core_index].frequency && - core_count == MAX_CORE_COUNT) - return quad_core_index; - } - if (single_core_index) - return single_core_index; + struct clk_osm *c = to_clk_osm(hw); + struct clk_hw *p_hw = clk_hw_get_parent(hw); + struct clk_osm *parent = to_clk_osm(p_hw); + int index = 0; - return -EINVAL; -} + if (!c || !parent) + return -EINVAL; -static int clk_osm_enable(struct clk_hw *hw) -{ - struct clk_osm *cpuclk = to_clk_osm(hw); + index = clk_osm_search_table(parent->osm_table, + parent->num_entries, rate); + if (index < 0) { + pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate); + return -EINVAL; + } - clk_osm_write_reg(cpuclk, 1, ENABLE_REG); + clk_osm_write_reg(parent, index, + DCVS_PERF_STATE_DESIRED_REG(c->core_num, + is_sdm845v1)); /* Make sure the write goes through before proceeding */ - clk_osm_mb(cpuclk, OSM_BASE); - - /* Wait for 5us for OSM hardware to enable */ - udelay(5); - - pr_debug("OSM clk enabled for cluster=%d\n", cpuclk->cluster_num); + clk_osm_mb(parent); return 0; } -const struct clk_ops clk_ops_cpu_osm = { - .enable = clk_osm_enable, - .round_rate = clk_osm_round_rate, - .list_rate = clk_osm_list_rate, -}; - -static struct clk_ops clk_ops_core; - -static int cpu_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - struct clk_osm *cpuclk = to_clk_osm(hw); + struct clk_osm *c = to_clk_osm(hw); struct clk_hw *p_hw = clk_hw_get_parent(hw); struct clk_osm *parent = to_clk_osm(p_hw); int index = 0; - unsigned long r_rate; - if (!cpuclk || !parent) + if (!c || !parent) return -EINVAL; - r_rate = clk_osm_round_rate(p_hw, rate, NULL); + index = clk_osm_read_reg(parent, + DCVS_PERF_STATE_DESIRED_REG(c->core_num, + is_sdm845v1)); + return parent->osm_table[index].frequency; +} - if (rate != r_rate) { - pr_err("invalid requested rate=%ld\n", rate); - return -EINVAL; - } +static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_hw *parent_hw = clk_hw_get_parent(hw); - /* Convert rate to table index */ - index = clk_osm_search_table(parent->osm_table, - parent->num_entries, r_rate); - if (index < 0) { - pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate); + if (!parent_hw) return -EINVAL; - } - pr_debug("rate: %lu --> index %d\n", rate, index); - /* - * Choose index and send request to OSM hardware. - * TODO: Program INACTIVE_OS_REQUEST if needed. - */ - clk_osm_write_reg(parent, index, - DCVS_PERF_STATE_DESIRED_REG(cpuclk->core_num)); - - /* Make sure the write goes through before proceeding */ - clk_osm_mb(parent, OSM_BASE); - return 0; + *parent_rate = rate; + return clk_hw_round_rate(parent_hw, rate); } static int l3_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -442,46 +282,15 @@ static int l3_clk_set_rate(struct clk_hw *hw, unsigned long rate, } pr_debug("rate: %lu --> index %d\n", rate, index); - clk_osm_write_reg(cpuclk, index, DCVS_PERF_STATE_DESIRED_REG_0); + clk_osm_write_reg(cpuclk, index, + DCVS_PERF_STATE_DESIRED_REG(0, is_sdm845v1)); /* Make sure the write goes through before proceeding */ - clk_osm_mb(cpuclk, OSM_BASE); + clk_osm_mb(cpuclk); return 0; } -static long cpu_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - struct clk_hw *parent_hw = clk_hw_get_parent(hw); - - if (!parent_hw) - return -EINVAL; - - return clk_hw_round_rate(parent_hw, rate); -} - -static unsigned long cpu_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_osm *cpuclk = to_clk_osm(hw); - struct clk_hw *p_hw = clk_hw_get_parent(hw); - struct clk_osm *parent = to_clk_osm(p_hw); - int index = 0; - - if (!cpuclk || !parent) - return -EINVAL; - - index = clk_osm_read_reg(parent, - DCVS_PERF_STATE_DESIRED_REG(cpuclk->core_num)); - - pr_debug("%s: Index %d, freq %ld\n", __func__, index, - parent->osm_table[index].frequency); - - /* Convert index to frequency */ - return parent->osm_table[index].frequency; -} - static unsigned long l3_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -491,7 +300,8 @@ static unsigned long l3_clk_recalc_rate(struct clk_hw *hw, if (!cpuclk) return -EINVAL; - index = clk_osm_read_reg(cpuclk, DCVS_PERF_STATE_DESIRED_REG_0); + index = clk_osm_read_reg(cpuclk, + DCVS_PERF_STATE_DESIRED_REG(0, is_sdm845v1)); pr_debug("%s: Index %d, freq %ld\n", __func__, index, cpuclk->osm_table[index].frequency); @@ -500,13 +310,27 @@ static unsigned long l3_clk_recalc_rate(struct clk_hw *hw, return cpuclk->osm_table[index].frequency; } - -const struct clk_ops clk_ops_l3_osm = { - .enable = clk_osm_enable, +static const struct clk_ops clk_ops_l3_osm = { .round_rate = clk_osm_round_rate, .list_rate = clk_osm_list_rate, .recalc_rate = l3_clk_recalc_rate, .set_rate = l3_clk_set_rate, + .debug_init = clk_debug_measure_add, +}; + +static const struct clk_ops clk_ops_core = { + .set_rate = clk_cpu_set_rate, + .round_rate = clk_cpu_round_rate, + .recalc_rate = clk_cpu_recalc_rate, + .debug_init = clk_debug_measure_add, +}; + +static const struct clk_ops clk_ops_cpu_osm = { + .set_rate = clk_osm_set_rate, + .round_rate = clk_osm_round_rate, + .recalc_rate = clk_osm_recalc_rate, + .list_rate = clk_osm_list_rate, + .debug_init = clk_debug_measure_add, }; static struct clk_init_data osm_clks_init[] = { @@ -515,12 +339,14 @@ static struct clk_init_data osm_clks_init[] = { .parent_names = (const char *[]){ "bi_tcxo_ao" }, .num_parents = 1, .ops = &clk_ops_l3_osm, + .vdd_class = &vdd_l3_mx_ao, }, [1] = { .name = "pwrcl_clk", .parent_names = (const char *[]){ "bi_tcxo_ao" }, .num_parents = 1, .ops = &clk_ops_cpu_osm, + .vdd_class = &vdd_pwrcl_mx_ao, }, [2] = { .name = "perfcl_clk", @@ -532,16 +358,17 @@ static struct clk_init_data osm_clks_init[] = { static struct clk_osm l3_clk = { .cluster_num = 0, - .cpu_reg_mask = 0x0, + .max_core_count = 4, .hw.init = &osm_clks_init[0], }; static DEFINE_CLK_VOTER(l3_cluster0_vote_clk, l3_clk, 0); static DEFINE_CLK_VOTER(l3_cluster1_vote_clk, l3_clk, 0); +static DEFINE_CLK_VOTER(l3_misc_vote_clk, l3_clk, 0); static struct clk_osm pwrcl_clk = { .cluster_num = 1, - .cpu_reg_mask = 0x300, + .max_core_count = 4, .hw.init = &osm_clks_init[1], }; @@ -553,6 +380,7 @@ static struct clk_osm cpu0_pwrcl_clk = { .name = "cpu0_pwrcl_clk", .parent_names = (const char *[]){ "pwrcl_clk" }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_ops_core, }, }; @@ -596,9 +424,35 @@ static struct clk_osm cpu3_pwrcl_clk = { }, }; +static struct clk_osm cpu4_pwrcl_clk = { + .core_num = 4, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu4_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_core, + }, +}; + +static struct clk_osm cpu5_pwrcl_clk = { + .core_num = 5, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu5_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_core, + }, +}; + static struct clk_osm perfcl_clk = { .cluster_num = 2, - .cpu_reg_mask = 0x700, + .max_core_count = 4, .hw.init = &osm_clks_init[2], }; @@ -611,6 +465,7 @@ static struct clk_osm cpu4_perfcl_clk = { .name = "cpu4_perfcl_clk", .parent_names = (const char *[]){ "perfcl_clk" }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_ops_core, }, }; @@ -654,16 +509,11 @@ static struct clk_osm cpu7_perfcl_clk = { }, }; -/* - * Use the cpu* clocks only for writing to the PERF_STATE_DESIRED registers. - * Note that we are currently NOT programming the APSS_LMH_GFMUX_CFG & - * APSS_OSM_GFMUX_CFG registers. - */ - static struct clk_hw *osm_qcom_clk_hws[] = { [L3_CLK] = &l3_clk.hw, [L3_CLUSTER0_VOTE_CLK] = &l3_cluster0_vote_clk.hw, [L3_CLUSTER1_VOTE_CLK] = &l3_cluster1_vote_clk.hw, + [L3_MISC_VOTE_CLK] = &l3_misc_vote_clk.hw, [PWRCL_CLK] = &pwrcl_clk.hw, [CPU0_PWRCL_CLK] = &cpu0_pwrcl_clk.hw, [CPU1_PWRCL_CLK] = &cpu1_pwrcl_clk.hw, @@ -674,6 +524,19 @@ static struct clk_hw *osm_qcom_clk_hws[] = { [CPU5_PERFCL_CLK] = &cpu5_perfcl_clk.hw, [CPU6_PERFCL_CLK] = &cpu6_perfcl_clk.hw, [CPU7_PERFCL_CLK] = &cpu7_perfcl_clk.hw, + [CPU4_PWRCL_CLK] = NULL, + [CPU5_PWRCL_CLK] = NULL, +}; + +static struct clk_osm *clk_cpu_map[] = { + &cpu0_pwrcl_clk, + &cpu1_pwrcl_clk, + &cpu2_pwrcl_clk, + &cpu3_pwrcl_clk, + &cpu4_perfcl_clk, + &cpu5_perfcl_clk, + &cpu6_perfcl_clk, + &cpu7_perfcl_clk, }; static struct clk_osm *logical_cpu_to_clk(int cpu) @@ -683,757 +546,232 @@ static struct clk_osm *logical_cpu_to_clk(int cpu) u64 hwid; static struct clk_osm *cpu_clk_map[NR_CPUS]; - if (cpu_clk_map[cpu]) - return cpu_clk_map[cpu]; - - cpu_node = of_get_cpu_node(cpu, NULL); - if (!cpu_node) - goto fail; - - cell = of_get_property(cpu_node, "reg", NULL); - if (!cell) { - pr_err("%s: missing reg property\n", cpu_node->full_name); - goto fail; - } + if (!cpu_clk_map[cpu]) { + cpu_node = of_get_cpu_node(cpu, NULL); + if (!cpu_node) + return NULL; - hwid = of_read_number(cell, of_n_addr_cells(cpu_node)); - if ((hwid | pwrcl_clk.cpu_reg_mask) == pwrcl_clk.cpu_reg_mask) { - switch (cpu) { - case 0: - cpu_clk_map[cpu] = &cpu0_pwrcl_clk; - break; - case 1: - cpu_clk_map[cpu] = &cpu1_pwrcl_clk; - break; - case 2: - cpu_clk_map[cpu] = &cpu2_pwrcl_clk; - break; - case 3: - cpu_clk_map[cpu] = &cpu3_pwrcl_clk; - break; - default: - pr_err("unsupported CPU number for power cluster\n"); + cell = of_get_property(cpu_node, "reg", NULL); + if (!cell) { + pr_err("%s: missing reg property\n", + cpu_node->full_name); + of_node_put(cpu_node); return NULL; } - return cpu_clk_map[cpu]; - } - if ((hwid | perfcl_clk.cpu_reg_mask) == perfcl_clk.cpu_reg_mask) { - switch (cpu) { - case 4: - cpu_clk_map[cpu] = &cpu4_perfcl_clk; - break; - case 5: - cpu_clk_map[cpu] = &cpu5_perfcl_clk; - break; - case 6: - cpu_clk_map[cpu] = &cpu6_perfcl_clk; - break; - case 7: - cpu_clk_map[cpu] = &cpu7_perfcl_clk; - break; - default: - pr_err("unsupported CPU number for perf cluster\n"); + hwid = of_read_number(cell, of_n_addr_cells(cpu_node)); + hwid = (hwid >> 8) & 0xff; + of_node_put(cpu_node); + if (hwid >= ARRAY_SIZE(clk_cpu_map)) { + pr_err("unsupported CPU number - %d (hw_id - %llu)\n", + cpu, hwid); return NULL; } - return cpu_clk_map[cpu]; + + cpu_clk_map[cpu] = clk_cpu_map[hwid]; } -fail: - return NULL; + return cpu_clk_map[cpu]; } -static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec) +static struct clk_osm *osm_configure_policy(struct cpufreq_policy *policy) { - u64 temp; + int cpu; + struct clk_hw *parent, *c_parent; + struct clk_osm *first; + struct clk_osm *c, *n; - temp = (u64)c->osm_clk_rate * nsec; - do_div(temp, 1000000000); + c = logical_cpu_to_clk(policy->cpu); + if (!c) + return NULL; - return temp; -} + c_parent = clk_hw_get_parent(&c->hw); + if (!c_parent) + return NULL; -static void clk_osm_program_mem_acc_regs(struct clk_osm *c) -{ - int curr_level, i, j = 0; - int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {MAX_VC, MAX_VC, MAX_VC}; + /* + * Don't put any other CPUs into the policy if we're doing + * per_core_dcvs + */ + if (to_clk_osm(c_parent)->per_core_dcvs) + return c; - curr_level = c->osm_table[0].mem_acc_level; - for (i = 0; i < c->num_entries; i++) { - if (curr_level == MAX_MEM_ACC_LEVELS) - break; + first = c; + /* Find CPUs that share the same clock domain */ + for_each_possible_cpu(cpu) { + n = logical_cpu_to_clk(cpu); + if (!n) + continue; - if (c->osm_table[i].mem_acc_level != curr_level) { - mem_acc_level_map[j++] = - c->osm_table[i].virtual_corner; - curr_level = c->osm_table[i].mem_acc_level; - } - } + parent = clk_hw_get_parent(&n->hw); + if (!parent) + return NULL; + if (parent != c_parent) + continue; - if (c->secure_init) { - clk_osm_write_seq_reg(c, - c->pbases[OSM_BASE] + MEMACC_CROSSOVER_VC, - DATA_MEM(57)); - clk_osm_write_seq_reg(c, c->mem_acc_addr[0], DATA_MEM(48)); - clk_osm_write_seq_reg(c, c->mem_acc_addr[1], DATA_MEM(49)); - clk_osm_write_seq_reg(c, c->mem_acc_addr[2], DATA_MEM(50)); - clk_osm_write_seq_reg(c, c->mem_acc_crossover_vc, - DATA_MEM(78)); - clk_osm_write_seq_reg(c, mem_acc_level_map[0], DATA_MEM(79)); - if (c == &perfcl_clk) - clk_osm_write_seq_reg(c, c->mem_acc_threshold_vc, - DATA_MEM(80)); - else - clk_osm_write_seq_reg(c, mem_acc_level_map[1], - DATA_MEM(80)); - /* - * Note that DATA_MEM[81] -> DATA_MEM[89] values will be - * confirmed post-si. Use a value of 1 for DATA_MEM[89] and - * leave the rest of them as 0. - */ - clk_osm_write_seq_reg(c, 1, DATA_MEM(89)); - } else { - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(78), - c->mem_acc_crossover_vc); - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(79), - mem_acc_level_map[0]); - if (c == &perfcl_clk) - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80), - c->mem_acc_threshold_vc); - else - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(80), - mem_acc_level_map[1]); + cpumask_set_cpu(cpu, policy->cpus); + if (n->core_num == 0) + first = n; } + + return first; } -static void clk_osm_program_apm_regs(struct clk_osm *c) +static void +osm_set_index(struct clk_osm *c, unsigned int index) { - if (c == &l3_clk || c == &pwrcl_clk) - return; - - /* - * Program address of the control register used to configure - * the Array Power Mux controller - */ - clk_osm_write_seq_reg(c, c->apm_mode_ctl, DATA_MEM(41)); - - /* Program address of controller status register */ - clk_osm_write_seq_reg(c, c->apm_status_ctl, DATA_MEM(43)); + struct clk_hw *p_hw = clk_hw_get_parent(&c->hw); + struct clk_osm *parent = to_clk_osm(p_hw); + unsigned long rate = 0; - /* Program address of crossover register */ - clk_osm_write_seq_reg(c, c->pbases[OSM_BASE] + APM_CROSSOVER_VC, - DATA_MEM(44)); + if (index >= OSM_TABLE_SIZE) { + pr_err("Passing an index (%u) that's greater than max (%d)\n", + index, OSM_TABLE_SIZE - 1); + return; + } - /* Program mode value to switch APM to VDD_APC */ - clk_osm_write_seq_reg(c, APM_APC_MODE, DATA_MEM(72)); + rate = parent->osm_table[index].frequency; + if (!rate) + return; - /* Program mode value to switch APM to VDD_MX */ - clk_osm_write_seq_reg(c, APM_MX_MODE, DATA_MEM(73)); + clk_set_rate(c->hw.clk, clk_round_rate(c->hw.clk, rate)); +} - /* Program mask used to move into read_mask port */ - clk_osm_write_seq_reg(c, APM_READ_DATA_MASK, DATA_MEM(74)); +static int +osm_cpufreq_target_index(struct cpufreq_policy *policy, unsigned int index) +{ + struct clk_osm *c = policy->driver_data; - /* Value used to move into read_exp port */ - clk_osm_write_seq_reg(c, APM_APC_READ_VAL, DATA_MEM(75)); - clk_osm_write_seq_reg(c, APM_MX_READ_VAL, DATA_MEM(76)); + osm_set_index(c, index); + return 0; } -static void clk_osm_do_additional_setup(struct clk_osm *c, - struct platform_device *pdev) +static unsigned int osm_cpufreq_get(unsigned int cpu) { - if (!c->secure_init) - return; - - dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n", - c->cluster_num); - - /* PLL L_VAL & post-div programming */ - clk_osm_write_seq_reg(c, c->apcs_pll_min_freq, DATA_MEM(32)); - clk_osm_write_seq_reg(c, c->l_val_base, DATA_MEM(33)); - clk_osm_write_seq_reg(c, c->apcs_pll_user_ctl, DATA_MEM(34)); - clk_osm_write_seq_reg(c, PLL_POST_DIV1, DATA_MEM(35)); - clk_osm_write_seq_reg(c, PLL_POST_DIV2, DATA_MEM(36)); - - /* APM Programming */ - clk_osm_program_apm_regs(c); - - /* GFMUX Programming */ - clk_osm_write_seq_reg(c, c->cfg_gfmux_addr, DATA_MEM(37)); - clk_osm_write_seq_reg(c, 0x1, DATA_MEM(65)); - clk_osm_write_seq_reg(c, 0x2, DATA_MEM(66)); - clk_osm_write_seq_reg(c, 0x3, DATA_MEM(67)); - clk_osm_write_seq_reg(c, 0x40000000, DATA_MEM(68)); - clk_osm_write_seq_reg(c, 0x20000000, DATA_MEM(69)); - clk_osm_write_seq_reg(c, 0x10000000, DATA_MEM(70)); - clk_osm_write_seq_reg(c, 0x70000000, DATA_MEM(71)); - - /* Override programming */ - clk_osm_write_seq_reg(c, c->pbases[OSM_BASE] + - OVERRIDE_CLUSTER_IDLE_ACK, DATA_MEM(54)); - clk_osm_write_seq_reg(c, 0x3, DATA_MEM(55)); - clk_osm_write_seq_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG, - DATA_MEM(40)); - clk_osm_write_seq_reg(c, c->pbases[OSM_BASE] + REQ_GEN_FSM_STATUS, - DATA_MEM(60)); - clk_osm_write_seq_reg(c, 0x10, DATA_MEM(61)); - clk_osm_write_seq_reg(c, 0x70, DATA_MEM(62)); - clk_osm_write_seq_reg(c, c->apcs_cbc_addr, DATA_MEM(112)); - clk_osm_write_seq_reg(c, 0x2, DATA_MEM(113)); - - if (c == &perfcl_clk) { - int rc; - u32 isense_addr; - - /* Performance cluster isense programming */ - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,perfcl-isense-addr", &isense_addr); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,perfcl-isense-addr property, rc=%d\n", - rc); - return; - } - clk_osm_write_seq_reg(c, isense_addr, DATA_MEM(45)); - clk_osm_write_seq_reg(c, ISENSE_ON_DATA, DATA_MEM(46)); - clk_osm_write_seq_reg(c, ISENSE_OFF_DATA, DATA_MEM(47)); - } + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct clk_osm *c; + u32 index; - clk_osm_write_seq_reg(c, c->ramp_ctl_addr, DATA_MEM(105)); - clk_osm_write_seq_reg(c, CONSTANT_32, DATA_MEM(92)); + if (!policy) + return 0; - /* Enable/disable CPR ramp settings */ - clk_osm_write_seq_reg(c, 0x101C031, DATA_MEM(106)); - clk_osm_write_seq_reg(c, 0x1010031, DATA_MEM(107)); + c = policy->driver_data; + index = clk_osm_read_reg(c, + DCVS_PERF_STATE_DESIRED_REG(c->core_num, is_sdm845v1)); + return policy->freq_table[index].frequency; } -static void clk_osm_setup_fsms(struct clk_osm *c) +static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy) { - u32 val; - - /* Voltage Reduction FSM */ - if (c->red_fsm_en) { - val = clk_osm_read_reg(c, VMIN_REDUCTION_ENABLE_REG) | BIT(0); - val |= BVAL(6, 1, c->min_cpr_vc); - clk_osm_write_reg(c, val, VMIN_REDUCTION_ENABLE_REG); + struct cpufreq_frequency_table *table; + struct clk_osm *c, *parent; + struct clk_hw *p_hw; + int ret; + unsigned int i, prev_cc = 0; + unsigned int xo_kHz; - clk_osm_write_reg(c, clk_osm_count_ns(c, 10000), - VMIN_REDUCTION_TIMER_REG); + c = osm_configure_policy(policy); + if (!c) { + pr_err("no clock for CPU%d\n", policy->cpu); + return -ENODEV; } - /* Boost FSM */ - if (c->boost_fsm_en) { - val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); - val |= DELTA_DEX_VAL | CC_BOOST_FSM_EN | IGNORE_PLL_LOCK; - clk_osm_write_reg(c, val, PDN_FSM_CTRL_REG); - - val = clk_osm_read_reg(c, CC_BOOST_FSM_TIMERS_REG0); - val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); - val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); - clk_osm_write_reg(c, val, CC_BOOST_FSM_TIMERS_REG0); - - val = clk_osm_read_reg(c, CC_BOOST_FSM_TIMERS_REG1); - val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); - val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS)); - clk_osm_write_reg(c, val, CC_BOOST_FSM_TIMERS_REG1); - - val = clk_osm_read_reg(c, CC_BOOST_FSM_TIMERS_REG2); - val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); - clk_osm_write_reg(c, val, CC_BOOST_FSM_TIMERS_REG2); + p_hw = clk_hw_get_parent(&c->hw); + if (!p_hw) { + pr_err("no parent clock for CPU%d\n", policy->cpu); + return -ENODEV; } - /* Safe Freq FSM */ - if (c->safe_fsm_en) { - val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); - clk_osm_write_reg(c, val | DCVS_BOOST_FSM_EN_MASK, - PDN_FSM_CTRL_REG); + parent = to_clk_osm(p_hw); + c->vbase = parent->vbase; - val = clk_osm_read_reg(c, DCVS_BOOST_FSM_TIMERS_REG0); - val |= BVAL(31, 16, clk_osm_count_ns(c, 1000)); - clk_osm_write_reg(c, val, DCVS_BOOST_FSM_TIMERS_REG0); - - val = clk_osm_read_reg(c, DCVS_BOOST_FSM_TIMERS_REG1); - val |= BVAL(15, 0, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); - clk_osm_write_reg(c, val, DCVS_BOOST_FSM_TIMERS_REG1); + p_hw = clk_hw_get_parent(p_hw); + if (!p_hw) { + pr_err("no xo clock for CPU%d\n", policy->cpu); + return -ENODEV; + } + xo_kHz = clk_hw_get_rate(p_hw) / 1000; - val = clk_osm_read_reg(c, DCVS_BOOST_FSM_TIMERS_REG2); - val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); - clk_osm_write_reg(c, val, DCVS_BOOST_FSM_TIMERS_REG2); + table = kcalloc(OSM_TABLE_SIZE + 1, sizeof(*table), GFP_KERNEL); + if (!table) + return -ENOMEM; - } + for (i = 0; i < OSM_TABLE_SIZE; i++) { + u32 data, src, div, lval, core_count; - /* Pulse Swallowing FSM */ - if (c->ps_fsm_en) { - val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); - clk_osm_write_reg(c, val | PS_BOOST_FSM_EN_MASK, - PDN_FSM_CTRL_REG); - - val = clk_osm_read_reg(c, PS_BOOST_FSM_TIMERS_REG0); - val |= BVAL(15, 0, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); - val |= BVAL(31, 16, clk_osm_count_ns(c, 1000)); - clk_osm_write_reg(c, val, PS_BOOST_FSM_TIMERS_REG0); - - val = clk_osm_read_reg(c, PS_BOOST_FSM_TIMERS_REG1); - val |= BVAL(15, 0, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS)); - val |= BVAL(31, 16, clk_osm_count_ns(c, 1000)); - clk_osm_write_reg(c, val, PS_BOOST_FSM_TIMERS_REG1); - - val = clk_osm_read_reg(c, PS_BOOST_FSM_TIMERS_REG2); - val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS)); - clk_osm_write_reg(c, val, PS_BOOST_FSM_TIMERS_REG2); - } + data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE); + src = (data & GENMASK(31, 30)) >> 30; + div = (data & GENMASK(29, 28)) >> 28; + lval = data & GENMASK(7, 0); + core_count = CORE_COUNT_VAL(data); - /* PLL signal timing control */ - if (c->boost_fsm_en || c->safe_fsm_en || c->ps_fsm_en) - clk_osm_write_reg(c, 0x2, BOOST_PROG_SYNC_DELAY_REG); + if (!src) + table[i].frequency = OSM_INIT_RATE / 1000; + else + table[i].frequency = xo_kHz * lval; + table[i].driver_data = table[i].frequency; - /* DCVS droop FSM - only if RCGwRC is not used for di/dt control */ - if (c->droop_fsm_en) { - val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); - clk_osm_write_reg(c, val | DCVS_DROOP_FSM_EN_MASK, - PDN_FSM_CTRL_REG); - } + if (core_count != parent->max_core_count) + table[i].frequency = CPUFREQ_ENTRY_INVALID; - if (c->ps_fsm_en || c->droop_fsm_en) { - clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG); - clk_osm_write_reg(c, clk_osm_count_ns(c, 100), - DROOP_RELEASE_TIMER_CTRL); - clk_osm_write_reg(c, clk_osm_count_ns(c, 150), - DCVS_DROOP_TIMER_CTRL); /* - * TODO: Check if DCVS_DROOP_CODE used is correct. Also check - * if RESYNC_CTRL should be set for L3. + * Two of the same frequencies with the same core counts means + * end of table. */ - val = BIT(31) | BVAL(22, 16, 0x2) | BVAL(6, 0, 0x8); - clk_osm_write_reg(c, val, DROOP_CTRL_REG); - } -} - -static int clk_osm_set_llm_volt_policy(struct platform_device *pdev) -{ - struct device_node *of = pdev->dev.of_node; - u32 *array; - int rc = 0, val, regval; + if (i > 0 && table[i - 1].driver_data == table[i].driver_data + && prev_cc == core_count) { + struct cpufreq_frequency_table *prev = &table[i - 1]; - array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), - GFP_KERNEL); - if (!array) - return -ENOMEM; + if (prev->frequency == CPUFREQ_ENTRY_INVALID) { + prev->flags = CPUFREQ_BOOST_FREQ; + prev->frequency = prev->driver_data; + } - /* - * Setup Timer to control how long OSM should wait before performing - * DCVS when a LLM up voltage request is received. - * Time is specified in us. - */ - rc = of_property_read_u32_array(of, "qcom,llm-volt-up-timer", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "No LLM voltage up timer value, rc=%d\n", - rc); - } else { - val = clk_osm_count_ns(&l3_clk, array[l3_clk.cluster_num]); - clk_osm_write_reg(&l3_clk, val, - LLM_VOLTAGE_VOTE_INC_HYSTERESIS); - - val = clk_osm_count_ns(&pwrcl_clk, - array[pwrcl_clk.cluster_num]); - clk_osm_write_reg(&pwrcl_clk, val, - LLM_VOLTAGE_VOTE_INC_HYSTERESIS); - - val = clk_osm_count_ns(&perfcl_clk, - array[perfcl_clk.cluster_num]); - clk_osm_write_reg(&perfcl_clk, val, - LLM_VOLTAGE_VOTE_INC_HYSTERESIS); + break; + } + prev_cc = core_count; } + table[i].frequency = CPUFREQ_TABLE_END; - /* - * Setup Timer to control how long OSM should wait before performing - * DCVS when a LLM down voltage request is received. - * Time is specified in us. - */ - rc = of_property_read_u32_array(of, "qcom,llm-volt-down-timer", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "No LLM Voltage down timer value: %d\n", - rc); - } else { - val = clk_osm_count_ns(&l3_clk, array[l3_clk.cluster_num]); - clk_osm_write_reg(&l3_clk, val, - LLM_VOLTAGE_VOTE_DEC_HYSTERESIS); - - val = clk_osm_count_ns(&pwrcl_clk, - array[pwrcl_clk.cluster_num]); - clk_osm_write_reg(&pwrcl_clk, val, - LLM_VOLTAGE_VOTE_DEC_HYSTERESIS); - - val = clk_osm_count_ns(&perfcl_clk, - array[perfcl_clk.cluster_num]); - clk_osm_write_reg(&perfcl_clk, val, - LLM_VOLTAGE_VOTE_DEC_HYSTERESIS); + ret = cpufreq_table_validate_and_show(policy, table); + if (ret) { + pr_err("%s: invalid frequency table: %d\n", __func__, ret); + goto err; } - /* Enable or disable honoring of LLM Voltage requests */ - rc = of_property_read_bool(pdev->dev.of_node, - "qcom,enable-llm-volt-vote"); - if (rc) { - dev_dbg(&pdev->dev, "Honoring LLM Voltage requests\n"); - val = 0; - } else - val = 1; - - /* Enable or disable LLM VOLT DVCS */ - regval = val | clk_osm_read_reg(&l3_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&l3_clk, regval, LLM_INTF_DCVS_DISABLE); - regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE); - regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE); - - /* Wait for the writes to complete */ - clk_osm_mb(&perfcl_clk, OSM_BASE); - - devm_kfree(&pdev->dev, array); + policy->driver_data = c; return 0; + +err: + kfree(table); + return ret; } -static int clk_osm_set_llm_freq_policy(struct platform_device *pdev) +static int osm_cpufreq_cpu_exit(struct cpufreq_policy *policy) { - struct device_node *of = pdev->dev.of_node; - u32 *array; - int rc = 0, val, regval; + kfree(policy->freq_table); + policy->freq_table = NULL; + return 0; +} - array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), - GFP_KERNEL); - if (!array) - return -ENOMEM; +static struct freq_attr *osm_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpufreq_freq_attr_scaling_boost_freqs, + NULL +}; - /* - * Setup Timer to control how long OSM should wait before performing - * DCVS when a LLM up frequency request is received. - * Time is specified in us. - */ - rc = of_property_read_u32_array(of, "qcom,llm-freq-up-timer", array, - MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "Unable to get CC up timer value: %d\n", - rc); - } else { - val = clk_osm_count_ns(&l3_clk, array[l3_clk.cluster_num]); - clk_osm_write_reg(&l3_clk, val, LLM_FREQ_VOTE_INC_HYSTERESIS); - - val = clk_osm_count_ns(&pwrcl_clk, - array[pwrcl_clk.cluster_num]); - clk_osm_write_reg(&pwrcl_clk, val, - LLM_FREQ_VOTE_INC_HYSTERESIS); - - val = clk_osm_count_ns(&perfcl_clk, - array[perfcl_clk.cluster_num]); - clk_osm_write_reg(&perfcl_clk, val, - LLM_FREQ_VOTE_INC_HYSTERESIS); - } - - /* - * Setup Timer to control how long OSM should wait before performing - * DCVS when a LLM down frequency request is received. - * Time is specified in us. - */ - rc = of_property_read_u32_array(of, "qcom,llm-freq-down-timer", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "No LLM Frequency down timer value: %d\n", - rc); - } else { - val = clk_osm_count_ns(&l3_clk, array[l3_clk.cluster_num]); - clk_osm_write_reg(&l3_clk, val, LLM_FREQ_VOTE_DEC_HYSTERESIS); - - val = clk_osm_count_ns(&pwrcl_clk, - array[pwrcl_clk.cluster_num]); - clk_osm_write_reg(&pwrcl_clk, val, - LLM_FREQ_VOTE_DEC_HYSTERESIS); - - val = clk_osm_count_ns(&perfcl_clk, - array[perfcl_clk.cluster_num]); - clk_osm_write_reg(&perfcl_clk, val, - LLM_FREQ_VOTE_DEC_HYSTERESIS); - } - - /* Enable or disable honoring of LLM frequency requests */ - rc = of_property_read_bool(pdev->dev.of_node, - "qcom,enable-llm-freq-vote"); - if (rc) { - dev_dbg(&pdev->dev, "Honoring LLM Frequency requests\n"); - val = 0; - } else - val = BIT(1); - - /* Enable or disable LLM FREQ DVCS */ - regval = val | clk_osm_read_reg(&l3_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&l3_clk, regval, LLM_INTF_DCVS_DISABLE); - regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE); - regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE); - clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE); - - /* Wait for the write to complete */ - clk_osm_mb(&perfcl_clk, OSM_BASE); - - devm_kfree(&pdev->dev, array); - return 0; -} - -static int clk_osm_set_cc_policy(struct platform_device *pdev) -{ - int rc = 0, val; - u32 *array; - struct device_node *of = pdev->dev.of_node; - - array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), - GFP_KERNEL); - if (!array) - return -ENOMEM; - - rc = of_property_read_u32_array(of, "qcom,up-timer", array, - MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "No up timer value, rc=%d\n", - rc); - } else { - val = clk_osm_count_ns(&l3_clk, - array[l3_clk.cluster_num]); - clk_osm_write_reg(&l3_clk, val, SPM_CC_INC_HYSTERESIS); - - val = clk_osm_count_ns(&pwrcl_clk, - array[pwrcl_clk.cluster_num]); - clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_INC_HYSTERESIS); - - val = clk_osm_count_ns(&perfcl_clk, - array[perfcl_clk.cluster_num]); - clk_osm_write_reg(&perfcl_clk, val, SPM_CC_INC_HYSTERESIS); - } - - rc = of_property_read_u32_array(of, "qcom,down-timer", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "No down timer value, rc=%d\n", rc); - } else { - val = clk_osm_count_ns(&l3_clk, - array[l3_clk.cluster_num]); - clk_osm_write_reg(&l3_clk, val, SPM_CC_DEC_HYSTERESIS); - - val = clk_osm_count_ns(&pwrcl_clk, - array[pwrcl_clk.cluster_num]); - clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_DEC_HYSTERESIS); - - clk_osm_count_ns(&perfcl_clk, - array[perfcl_clk.cluster_num]); - clk_osm_write_reg(&perfcl_clk, val, SPM_CC_DEC_HYSTERESIS); - } - - /* OSM index override for cluster PC */ - rc = of_property_read_u32_array(of, "qcom,pc-override-index", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_dbg(&pdev->dev, "No PC override index value, rc=%d\n", - rc); - clk_osm_write_reg(&pwrcl_clk, 0, CC_ZERO_BEHAV_CTRL); - clk_osm_write_reg(&perfcl_clk, 0, CC_ZERO_BEHAV_CTRL); - } else { - val = BVAL(6, 1, array[pwrcl_clk.cluster_num]) - | ENABLE_OVERRIDE; - clk_osm_write_reg(&pwrcl_clk, val, CC_ZERO_BEHAV_CTRL); - val = BVAL(6, 1, array[perfcl_clk.cluster_num]) - | ENABLE_OVERRIDE; - clk_osm_write_reg(&perfcl_clk, val, CC_ZERO_BEHAV_CTRL); - } - - /* Wait for the writes to complete */ - clk_osm_mb(&perfcl_clk, OSM_BASE); - - rc = of_property_read_bool(pdev->dev.of_node, "qcom,set-c3-active"); - if (rc) { - dev_dbg(&pdev->dev, "Treat cores in C3 as active\n"); - - val = clk_osm_read_reg(&l3_clk, SPM_CORE_INACTIVE_MAPPING); - val &= ~BIT(2); - clk_osm_write_reg(&l3_clk, val, SPM_CORE_INACTIVE_MAPPING); - - val = clk_osm_read_reg(&pwrcl_clk, SPM_CORE_INACTIVE_MAPPING); - val &= ~BIT(2); - clk_osm_write_reg(&pwrcl_clk, val, SPM_CORE_INACTIVE_MAPPING); - - val = clk_osm_read_reg(&perfcl_clk, SPM_CORE_INACTIVE_MAPPING); - val &= ~BIT(2); - clk_osm_write_reg(&perfcl_clk, val, SPM_CORE_INACTIVE_MAPPING); - } - - rc = of_property_read_bool(pdev->dev.of_node, "qcom,set-c2-active"); - if (rc) { - dev_dbg(&pdev->dev, "Treat cores in C2 as active\n"); - - val = clk_osm_read_reg(&l3_clk, SPM_CORE_INACTIVE_MAPPING); - val &= ~BIT(1); - clk_osm_write_reg(&l3_clk, val, SPM_CORE_INACTIVE_MAPPING); - - val = clk_osm_read_reg(&pwrcl_clk, SPM_CORE_INACTIVE_MAPPING); - val &= ~BIT(1); - clk_osm_write_reg(&pwrcl_clk, val, SPM_CORE_INACTIVE_MAPPING); - - val = clk_osm_read_reg(&perfcl_clk, SPM_CORE_INACTIVE_MAPPING); - val &= ~BIT(1); - clk_osm_write_reg(&perfcl_clk, val, SPM_CORE_INACTIVE_MAPPING); - } - - rc = of_property_read_bool(pdev->dev.of_node, "qcom,disable-cc-dvcs"); - if (rc) { - dev_dbg(&pdev->dev, "Disabling CC based DCVS\n"); - val = 1; - } else - val = 0; - - clk_osm_write_reg(&l3_clk, val, SPM_CC_DCVS_DISABLE); - clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_DCVS_DISABLE); - clk_osm_write_reg(&perfcl_clk, val, SPM_CC_DCVS_DISABLE); - - /* Wait for the writes to complete */ - clk_osm_mb(&perfcl_clk, OSM_BASE); - - devm_kfree(&pdev->dev, array); - return 0; -} - -static void clk_osm_setup_cluster_pll(struct clk_osm *c) -{ - writel_relaxed(0x0, c->vbases[PLL_BASE] + PLL_MODE); - writel_relaxed(0x26, c->vbases[PLL_BASE] + PLL_L_VAL); - writel_relaxed(0x8, c->vbases[PLL_BASE] + - PLL_USER_CTRL); - writel_relaxed(0x20000AA8, c->vbases[PLL_BASE] + - PLL_CONFIG_CTL_LO); - writel_relaxed(0x000003D2, c->vbases[PLL_BASE] + - PLL_CONFIG_CTL_HI); - writel_relaxed(0x2, c->vbases[PLL_BASE] + - PLL_MODE); - - /* Ensure writes complete before delaying */ - clk_osm_mb(c, PLL_BASE); - - udelay(PLL_WAIT_LOCK_TIME_US); - - writel_relaxed(0x6, c->vbases[PLL_BASE] + PLL_MODE); - - /* Ensure write completes before delaying */ - clk_osm_mb(c, PLL_BASE); - - usleep_range(50, 75); - - writel_relaxed(0x7, c->vbases[PLL_BASE] + PLL_MODE); -} - -static void clk_osm_misc_programming(struct clk_osm *c) -{ - u32 lval = 0xFF, val; - int i; - - clk_osm_write_reg(c, BVAL(23, 16, 0xF), SPM_CORE_COUNT_CTRL); - clk_osm_write_reg(c, PLL_MIN_LVAL, PLL_MIN_FREQ_REG); - - /* Pattern to set/clear PLL lock in PDN_FSM_CTRL_REG */ - val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG); - if (c->secure_init) { - val |= IGNORE_PLL_LOCK; - clk_osm_write_seq_reg(c, val, DATA_MEM(108)); - val &= ~IGNORE_PLL_LOCK; - clk_osm_write_seq_reg(c, val, DATA_MEM(109)); - clk_osm_write_seq_reg(c, MIN_VCO_VAL, DATA_MEM(110)); - } else { - val |= IGNORE_PLL_LOCK; - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(108), val); - val &= ~IGNORE_PLL_LOCK; - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(109), val); - } - - /* Program LVAL corresponding to first turbo VC */ - for (i = 0; i < c->num_entries; i++) { - if (c->osm_table[i].mem_acc_level == MAX_MEM_ACC_LEVELS) { - lval = c->osm_table[i].freq_data & GENMASK(7, 0); - break; - } - } - - if (c->secure_init) - clk_osm_write_seq_reg(c, lval, DATA_MEM(114)); - else - scm_io_write(c->pbases[SEQ_BASE] + DATA_MEM(114), lval); - -} - -static int clk_osm_setup_hw_table(struct clk_osm *c) -{ - struct osm_entry *entry = c->osm_table; - int i; - u32 freq_val = 0, volt_val = 0, override_val = 0; - u32 table_entry_offset, last_mem_acc_level, last_virtual_corner = 0; - - for (i = 0; i < OSM_TABLE_SIZE; i++) { - if (i < c->num_entries) { - freq_val = entry[i].freq_data; - volt_val = BVAL(27, 24, entry[i].mem_acc_level) - | BVAL(21, 16, entry[i].virtual_corner) - | BVAL(11, 0, entry[i].open_loop_volt); - override_val = entry[i].override_data; - - if (last_virtual_corner && last_virtual_corner == - entry[i].virtual_corner && last_mem_acc_level != - entry[i].mem_acc_level) { - pr_err("invalid LUT entry at row=%d virtual_corner=%d, mem_acc_level=%d\n", - i, entry[i].virtual_corner, - entry[i].mem_acc_level); - return -EINVAL; - } - last_virtual_corner = entry[i].virtual_corner; - last_mem_acc_level = entry[i].mem_acc_level; - } - - table_entry_offset = i * OSM_REG_SIZE; - clk_osm_write_reg(c, freq_val, FREQ_REG + table_entry_offset); - clk_osm_write_reg(c, volt_val, VOLT_REG + table_entry_offset); - clk_osm_write_reg(c, override_val, OVERRIDE_REG + - table_entry_offset); - } - - /* Make sure all writes go through */ - clk_osm_mb(c, OSM_BASE); - - return 0; -} - -static void clk_osm_print_osm_table(struct clk_osm *c) -{ - int i; - struct osm_entry *table = c->osm_table; - u32 pll_src, pll_div, lval, core_count; - - pr_debug("Index, Frequency, VC, OLV (mv), Core Count, PLL Src, PLL Div, L-Val, ACC Level\n"); - for (i = 0; i < c->num_entries; i++) { - pll_src = (table[i].freq_data & GENMASK(31, 30)) >> 30; - pll_div = (table[i].freq_data & GENMASK(29, 28)) >> 28; - lval = table[i].freq_data & GENMASK(7, 0); - core_count = (table[i].freq_data & GENMASK(18, 16)) >> 16; - - pr_debug("%3d, %11lu, %2u, %5u, %2u, %6u, %8u, %7u, %5u\n", - i, - table[i].frequency, - table[i].virtual_corner, - table[i].open_loop_volt, - core_count, - pll_src, - pll_div, - lval, - table[i].mem_acc_level); - } - pr_debug("APM threshold corner=%d, crossover corner=%d\n", - c->apm_threshold_vc, c->apm_crossover_vc); - pr_debug("MEM-ACC threshold corner=%d, crossover corner=%d\n", - c->mem_acc_threshold_vc, c->mem_acc_crossover_vc); -} +static struct cpufreq_driver qcom_osm_cpufreq_driver = { + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | + CPUFREQ_HAVE_GOVERNOR_PER_POLICY, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = osm_cpufreq_target_index, + .get = osm_cpufreq_get, + .init = osm_cpufreq_cpu_init, + .exit = osm_cpufreq_cpu_exit, + .name = "osm-cpufreq", + .attr = osm_cpufreq_attr, + .boost_enabled = true, +}; static u32 find_voltage(struct clk_osm *c, unsigned long rate) { @@ -1450,12 +788,12 @@ static u32 find_voltage(struct clk_osm *c, unsigned long rate) return -EINVAL; } -static int add_opp(struct clk_osm *c, struct device *dev) +static int add_opp(struct clk_osm *c, struct device **device_list, int count) { unsigned long rate = 0; u32 uv; long rc; - int j = 0; + int i, j = 0; unsigned long min_rate = c->hw.init->rate_max[0]; unsigned long max_rate = c->hw.init->rate_max[c->hw.init->num_rate_max - 1]; @@ -1468,10 +806,12 @@ static int add_opp(struct clk_osm *c, struct device *dev) return -EINVAL; } - rc = dev_pm_opp_add(dev, rate, uv); - if (rc) { - pr_warn("failed to add OPP for %lu\n", rate); - return rc; + for (i = 0; i < count; i++) { + rc = dev_pm_opp_add(device_list[i], rate, uv); + if (rc) { + pr_warn("failed to add OPP for %lu\n", rate); + return rc; + } } /* @@ -1480,13 +820,18 @@ static int add_opp(struct clk_osm *c, struct device *dev) * this information will be used by thermal mitigation and the * scheduler. */ - if (rate == min_rate) - pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", - rate, uv, dev_name(dev)); + if (rate == min_rate) { + for (i = 0; i < count; i++) { + pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", + rate, uv, dev_name(device_list[i])); + } + } if (rate == max_rate && max_rate != min_rate) { - pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", - rate, uv, dev_name(dev)); + for (i = 0; i < count; i++) { + pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", + rate, uv, dev_name(device_list[i])); + } break; } @@ -1496,12 +841,70 @@ static int add_opp(struct clk_osm *c, struct device *dev) return 0; } +static int derive_device_list(struct device **device_list, + struct device_node *np, + char *phandle_name, int count) +{ + int i; + struct platform_device *pdev; + struct device_node *dev_node; + + for (i = 0; i < count; i++) { + dev_node = of_parse_phandle(np, phandle_name, i); + if (!dev_node) { + pr_err("Unable to get device_node pointer for opp-handle (%s)\n", + phandle_name); + return -ENODEV; + } + + pdev = of_find_device_by_node(dev_node); + if (!pdev) { + pr_err("Unable to find platform_device node for opp-handle (%s)\n", + phandle_name); + return -ENODEV; + } + device_list[i] = &pdev->dev; + } + return 0; +} + +static void populate_l3_opp_table(struct device_node *np, char *phandle_name) +{ + struct device **device_list; + int len, count, ret = 0; + + if (of_find_property(np, phandle_name, &len)) { + count = len / sizeof(u32); + + device_list = kcalloc(count, sizeof(struct device *), + GFP_KERNEL); + if (!device_list) + return; + + ret = derive_device_list(device_list, np, phandle_name, count); + if (ret < 0) { + pr_err("Failed to fill device_list for %s\n", + phandle_name); + return; + } + } else { + pr_debug("Unable to find %s\n", phandle_name); + return; + } + + if (add_opp(&l3_clk, device_list, count)) + pr_err("Failed to add OPP levels for %s\n", phandle_name); + + kfree(device_list); +} + static void populate_opp_table(struct platform_device *pdev) { int cpu; struct device *cpu_dev; struct clk_osm *c, *parent; struct clk_hw *hw_parent; + struct device_node *np = pdev->dev.of_node; for_each_possible_cpu(cpu) { c = logical_cpu_to_clk(cpu); @@ -1514,18 +917,20 @@ static void populate_opp_table(struct platform_device *pdev) parent = to_clk_osm(hw_parent); cpu_dev = get_cpu_device(cpu); if (cpu_dev) - if (add_opp(parent, cpu_dev)) + if (add_opp(parent, &cpu_dev, 1)) pr_err("Failed to add OPP levels for %s\n", dev_name(cpu_dev)); } - /*TODO: Figure out which device to tag the L3 table to */ + populate_l3_opp_table(np, "l3-devs"); } static u64 clk_osm_get_cpu_cycle_counter(int cpu) { u32 val; + int core_num; unsigned long flags; + u64 cycle_counter_ret; struct clk_osm *parent, *c = logical_cpu_to_clk(cpu); if (IS_ERR_OR_NULL(c)) { @@ -1540,12 +945,9 @@ static u64 clk_osm_get_cpu_cycle_counter(int cpu) * Use core 0's copy as proxy for the whole cluster when per * core DCVS is disabled. */ - if (parent->per_core_dcvs) - val = clk_osm_read_reg_no_log(parent, - OSM_CYCLE_COUNTER_STATUS_REG(c->core_num)); - else - val = clk_osm_read_reg_no_log(parent, - OSM_CYCLE_COUNTER_STATUS_REG(0)); + core_num = parent->per_core_dcvs ? c->core_num : 0; + val = clk_osm_read_reg_no_log(parent, + OSM_CYCLE_COUNTER_STATUS_REG(core_num, is_sdm845v1)); if (val < c->prev_cycle_counter) { /* Handle counter overflow */ @@ -1556,492 +958,84 @@ static u64 clk_osm_get_cpu_cycle_counter(int cpu) c->total_cycle_counter += val - c->prev_cycle_counter; c->prev_cycle_counter = val; } + cycle_counter_ret = c->total_cycle_counter; spin_unlock_irqrestore(&parent->lock, flags); - return c->total_cycle_counter; + return cycle_counter_ret; } -static void clk_osm_setup_cycle_counters(struct clk_osm *c) +static int clk_osm_read_lut(struct platform_device *pdev, struct clk_osm *c) { - u32 ratio = c->osm_clk_rate; - u32 val = 0; - - /* Enable cycle counter */ - val = BIT(0); - /* Setup OSM clock to XO ratio */ - do_div(ratio, c->xo_clk_rate); - val |= BVAL(5, 1, ratio - 1) | OSM_CYCLE_COUNTER_USE_XO_EDGE_EN; - - clk_osm_write_reg(c, val, OSM_CYCLE_COUNTER_CTRL_REG); - pr_debug("OSM to XO clock ratio: %d\n", ratio); -} - -static int clk_osm_resolve_crossover_corners(struct clk_osm *c, - struct platform_device *pdev) -{ - struct regulator *regulator = c->vdd_reg; - int count, vc, i, memacc_threshold, apm_threshold; - int rc = 0; - u32 corner_volt; - - if (c == &l3_clk || c == &pwrcl_clk) - return rc; - - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,perfcl-apcs-apm-threshold-voltage", - &apm_threshold); - if (rc) { - pr_err("qcom,perfcl-apcs-apm-threshold-voltage property not specified\n"); - return rc; - } - - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,perfcl-apcs-mem-acc-threshold-voltage", - &memacc_threshold); - if (rc) { - pr_err("qcom,perfcl-apcs-mem-acc-threshold-voltage property not specified\n"); - return rc; - } - - /* - * Initialize VC settings in case none of them go above the voltage - * limits - */ - c->apm_threshold_vc = c->apm_crossover_vc = c->mem_acc_crossover_vc = - c->mem_acc_threshold_vc = MAX_VC; - - count = regulator_count_voltages(regulator); - if (count < 0) { - pr_err("Failed to get the number of virtual corners supported\n"); - return count; - } - - c->apm_crossover_vc = count - 2; - c->mem_acc_crossover_vc = count - 1; + u32 data, src, lval, i, j = OSM_TABLE_SIZE; + struct clk_vdd_class *vdd = osm_clks_init[c->cluster_num].vdd_class; for (i = 0; i < OSM_TABLE_SIZE; i++) { - vc = c->osm_table[i].virtual_corner + 1; - corner_volt = regulator_list_corner_voltage(regulator, vc); - - if (c->apm_threshold_vc == MAX_VC && - corner_volt >= apm_threshold) - c->apm_threshold_vc = c->osm_table[i].virtual_corner; - - if (c->mem_acc_threshold_vc == MAX_VC && - corner_volt >= memacc_threshold) - c->mem_acc_threshold_vc = - c->osm_table[i].virtual_corner; - } - - return rc; -} + data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE); + src = ((data & GENMASK(31, 30)) >> 30); + lval = (data & GENMASK(7, 0)); + c->osm_table[i].ccount = CORE_COUNT_VAL(data); -static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c) -{ - struct regulator *regulator = c->vdd_reg; - u32 vc, mv; - int i; - - for (i = 0; i < OSM_TABLE_SIZE; i++) { - vc = c->osm_table[i].virtual_corner + 1; - /* Voltage is in uv. Convert to mv */ - mv = regulator_list_corner_voltage(regulator, vc) / 1000; - c->osm_table[i].open_loop_volt = mv; - } - - return 0; -} - -static int clk_osm_get_lut(struct platform_device *pdev, - struct clk_osm *c, char *prop_name) -{ - struct device_node *of = pdev->dev.of_node; - int prop_len, total_elems, num_rows, i, j, k; - int rc = 0; - u32 *array; - u32 *fmax_temp; - u32 data; - unsigned long abs_fmax = 0; - bool last_entry = false; - - if (!of_find_property(of, prop_name, &prop_len)) { - dev_err(&pdev->dev, "missing %s\n", prop_name); - return -EINVAL; - } - - total_elems = prop_len / sizeof(u32); - if (total_elems % NUM_FIELDS) { - dev_err(&pdev->dev, "bad length %d\n", prop_len); - return -EINVAL; - } - - num_rows = total_elems / NUM_FIELDS; - - fmax_temp = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long), - GFP_KERNEL); - if (!fmax_temp) - return -ENOMEM; - - array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL); - if (!array) - return -ENOMEM; + if (!src) + c->osm_table[i].frequency = OSM_INIT_RATE; + else + c->osm_table[i].frequency = XO_RATE * lval; - rc = of_property_read_u32_array(of, prop_name, array, total_elems); - if (rc) { - dev_err(&pdev->dev, "Unable to parse OSM table, rc=%d\n", rc); - goto exit; - } + data = clk_osm_read_reg(c, VOLT_REG + i * OSM_REG_SIZE); + c->osm_table[i].virtual_corner = + ((data & GENMASK(21, 16)) >> 16); + c->osm_table[i].open_loop_volt = (data & GENMASK(11, 0)); - pr_debug("%s: Entries in Table: %d\n", __func__, num_rows); - c->num_entries = num_rows; - if (c->num_entries > OSM_TABLE_SIZE) { - pr_err("LUT entries %d exceed maximum size %d\n", - c->num_entries, OSM_TABLE_SIZE); - return -EINVAL; - } + pr_debug("index=%d freq=%ld virtual_corner=%d open_loop_voltage=%u\n", + i, c->osm_table[i].frequency, + c->osm_table[i].virtual_corner, + c->osm_table[i].open_loop_volt); - for (i = 0, j = 0, k = 0; j < OSM_TABLE_SIZE; j++) { - c->osm_table[j].frequency = array[i + FREQ]; - c->osm_table[j].freq_data = array[i + FREQ_DATA]; - c->osm_table[j].override_data = array[i + PLL_OVERRIDES]; - c->osm_table[j].mem_acc_level = array[i + MEM_ACC_LEVEL]; - /* Voltage corners are 0 based in the OSM LUT */ - c->osm_table[j].virtual_corner = array[i + VIRTUAL_CORNER] - 1; - pr_debug("index=%d freq=%ld virtual_corner=%d freq_data=0x%x override_data=0x%x mem_acc_level=0x%x\n", - j, c->osm_table[j].frequency, - c->osm_table[j].virtual_corner, - c->osm_table[j].freq_data, - c->osm_table[j].override_data, - c->osm_table[j].mem_acc_level); - - data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16; - if (!last_entry && data == MAX_CORE_COUNT) { - fmax_temp[k] = array[i]; - k++; - } - - if (i < total_elems - NUM_FIELDS) - i += NUM_FIELDS; - else { - abs_fmax = array[i]; - last_entry = true; - } + if (i > 0 && j == OSM_TABLE_SIZE && + c->osm_table[i].frequency == + c->osm_table[i - 1].frequency && + c->osm_table[i].ccount == c->osm_table[i - 1].ccount) + j = i; } - fmax_temp[k] = abs_fmax; - osm_clks_init[c->cluster_num].rate_max = devm_kzalloc(&pdev->dev, - k * sizeof(unsigned long), + osm_clks_init[c->cluster_num].rate_max = devm_kcalloc(&pdev->dev, + j, sizeof(unsigned long), GFP_KERNEL); - if (!osm_clks_init[c->cluster_num].rate_max) { - rc = -ENOMEM; - goto exit; - } - - for (i = 0; i < k; i++) - osm_clks_init[c->cluster_num].rate_max[i] = fmax_temp[i]; - - osm_clks_init[c->cluster_num].num_rate_max = k; -exit: - devm_kfree(&pdev->dev, fmax_temp); - devm_kfree(&pdev->dev, array); - return rc; -} - -static int clk_osm_parse_dt_configs(struct platform_device *pdev) -{ - struct device_node *of = pdev->dev.of_node; - u32 *array; - int rc = 0; - struct resource *res; - char l3_min_cpr_vc_str[] = "qcom,l3-min-cpr-vc-bin0"; - char pwrcl_min_cpr_vc_str[] = "qcom,pwrcl-min-cpr-vc-bin0"; - char perfcl_min_cpr_vc_str[] = "qcom,perfcl-min-cpr-vc-bin0"; - - array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32), - GFP_KERNEL); - if (!array) + if (!osm_clks_init[c->cluster_num].rate_max) return -ENOMEM; - rc = of_property_read_u32_array(of, "qcom,l-val-base", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,l-val-base property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.l_val_base = array[l3_clk.cluster_num]; - pwrcl_clk.l_val_base = array[pwrcl_clk.cluster_num]; - perfcl_clk.l_val_base = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,apcs-pll-user-ctl", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,apcs-pll-user-ctl property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.apcs_pll_user_ctl = array[l3_clk.cluster_num]; - pwrcl_clk.apcs_pll_user_ctl = array[pwrcl_clk.cluster_num]; - perfcl_clk.apcs_pll_user_ctl = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,apcs-pll-min-freq", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,apcs-pll-min-freq property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.apcs_pll_min_freq = array[l3_clk.cluster_num]; - pwrcl_clk.apcs_pll_min_freq = array[pwrcl_clk.cluster_num]; - perfcl_clk.apcs_pll_min_freq = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,apm-mode-ctl", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,apm-mode-ctl property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.apm_mode_ctl = array[l3_clk.cluster_num]; - pwrcl_clk.apm_mode_ctl = array[pwrcl_clk.cluster_num]; - perfcl_clk.apm_mode_ctl = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,apm-status-ctrl", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,apm-status-ctrl property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.apm_status_ctl = array[l3_clk.cluster_num]; - pwrcl_clk.apm_status_ctl = array[pwrcl_clk.cluster_num]; - perfcl_clk.apm_status_ctl = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,cfg-gfmux-addr", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,cfg-gfmux-addr property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.cfg_gfmux_addr = array[l3_clk.cluster_num]; - pwrcl_clk.cfg_gfmux_addr = array[pwrcl_clk.cluster_num]; - perfcl_clk.cfg_gfmux_addr = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,apcs-cbc-addr", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,apcs-cbc-addr property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.apcs_cbc_addr = array[l3_clk.cluster_num]; - pwrcl_clk.apcs_cbc_addr = array[pwrcl_clk.cluster_num]; - perfcl_clk.apcs_cbc_addr = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32_array(of, "qcom,apcs-ramp-ctl-addr", - array, MAX_CLUSTER_CNT); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,apcs-ramp-ctl-addr property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.ramp_ctl_addr = array[l3_clk.cluster_num]; - pwrcl_clk.ramp_ctl_addr = array[pwrcl_clk.cluster_num]; - perfcl_clk.ramp_ctl_addr = array[perfcl_clk.cluster_num]; - - rc = of_property_read_u32(of, "qcom,xo-clk-rate", - &pwrcl_clk.xo_clk_rate); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,xo-clk-rate property, rc=%d\n", - rc); - return -EINVAL; - } - - l3_clk.xo_clk_rate = perfcl_clk.xo_clk_rate = pwrcl_clk.xo_clk_rate; - - rc = of_property_read_u32(of, "qcom,osm-clk-rate", - &pwrcl_clk.osm_clk_rate); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,osm-clk-rate property, rc=%d\n", - rc); - return -EINVAL; - } - l3_clk.osm_clk_rate = perfcl_clk.osm_clk_rate = pwrcl_clk.osm_clk_rate; - - rc = of_property_read_u32(of, "qcom,cc-reads", - &pwrcl_clk.cycle_counter_reads); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,cc-reads property, rc=%d\n", - rc); - return -EINVAL; - } - l3_clk.cycle_counter_reads = perfcl_clk.cycle_counter_reads = - pwrcl_clk.cycle_counter_reads; - - rc = of_property_read_u32(of, "qcom,cc-delay", - &pwrcl_clk.cycle_counter_delay); - if (rc) - dev_dbg(&pdev->dev, "no delays between cycle counter reads\n"); - else - l3_clk.cycle_counter_delay = perfcl_clk.cycle_counter_delay = - pwrcl_clk.cycle_counter_delay; - - rc = of_property_read_u32(of, "qcom,cc-factor", - &pwrcl_clk.cycle_counter_factor); - if (rc) - dev_dbg(&pdev->dev, "no factor specified for cycle counter estimation\n"); - else - l3_clk.cycle_counter_factor = perfcl_clk.cycle_counter_factor = - pwrcl_clk.cycle_counter_factor; - - l3_clk.red_fsm_en = perfcl_clk.red_fsm_en = pwrcl_clk.red_fsm_en = - of_property_read_bool(of, "qcom,red-fsm-en"); - - l3_clk.boost_fsm_en = perfcl_clk.boost_fsm_en = - pwrcl_clk.boost_fsm_en = - of_property_read_bool(of, "qcom,boost-fsm-en"); - - l3_clk.safe_fsm_en = perfcl_clk.safe_fsm_en = pwrcl_clk.safe_fsm_en = - of_property_read_bool(of, "qcom,safe-fsm-en"); - - l3_clk.ps_fsm_en = perfcl_clk.ps_fsm_en = pwrcl_clk.ps_fsm_en = - of_property_read_bool(of, "qcom,ps-fsm-en"); - - l3_clk.droop_fsm_en = perfcl_clk.droop_fsm_en = - pwrcl_clk.droop_fsm_en = - of_property_read_bool(of, "qcom,droop-fsm-en"); - - devm_kfree(&pdev->dev, array); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "l3_sequencer"); - if (!res) { - dev_err(&pdev->dev, - "Unable to get platform resource for l3_sequencer\n"); - return -ENOMEM; - } - - l3_clk.pbases[SEQ_BASE] = (unsigned long)res->start; - l3_clk.vbases[SEQ_BASE] = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - - if (!l3_clk.vbases[SEQ_BASE]) { - dev_err(&pdev->dev, "Unable to map in l3_sequencer base\n"); - return -ENOMEM; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "pwrcl_sequencer"); - if (!res) { - dev_err(&pdev->dev, - "Unable to get platform resource for pwrcl_sequencer\n"); - return -ENOMEM; - } - - pwrcl_clk.pbases[SEQ_BASE] = (unsigned long)res->start; - pwrcl_clk.vbases[SEQ_BASE] = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - - if (!pwrcl_clk.vbases[SEQ_BASE]) { - dev_err(&pdev->dev, "Unable to map in pwrcl_sequencer base\n"); - return -ENOMEM; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "perfcl_sequencer"); - if (!res) { - dev_err(&pdev->dev, - "Unable to get platform resource for perfcl_sequencer\n"); - return -ENOMEM; - } - - perfcl_clk.pbases[SEQ_BASE] = (unsigned long)res->start; - perfcl_clk.vbases[SEQ_BASE] = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - - if (!perfcl_clk.vbases[SEQ_BASE]) { - dev_err(&pdev->dev, "Unable to map in perfcl_sequencer base\n"); - return -ENOMEM; - } - - snprintf(l3_min_cpr_vc_str, ARRAY_SIZE(l3_min_cpr_vc_str), - "qcom,l3-min-cpr-vc-bin%d", l3_clk.speedbin); - rc = of_property_read_u32(of, l3_min_cpr_vc_str, &l3_clk.min_cpr_vc); - if (rc) { - dev_err(&pdev->dev, "unable to find %s property, rc=%d\n", - l3_min_cpr_vc_str, rc); - return -EINVAL; - } - - snprintf(pwrcl_min_cpr_vc_str, ARRAY_SIZE(pwrcl_min_cpr_vc_str), - "qcom,pwrcl-min-cpr-vc-bin%d", pwrcl_clk.speedbin); - rc = of_property_read_u32(of, pwrcl_min_cpr_vc_str, - &pwrcl_clk.min_cpr_vc); - if (rc) { - dev_err(&pdev->dev, "unable to find %s property, rc=%d\n", - pwrcl_min_cpr_vc_str, rc); - return -EINVAL; - } - - snprintf(perfcl_min_cpr_vc_str, ARRAY_SIZE(perfcl_min_cpr_vc_str), - "qcom,perfcl-min-cpr-vc-bin%d", perfcl_clk.speedbin); - rc = of_property_read_u32(of, perfcl_min_cpr_vc_str, - &perfcl_clk.min_cpr_vc); - if (rc) { - dev_err(&pdev->dev, "unable to find %s property, rc=%d\n", - perfcl_min_cpr_vc_str, rc); - return -EINVAL; - } - - l3_clk.secure_init = perfcl_clk.secure_init = pwrcl_clk.secure_init = - of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz"); - - if (!pwrcl_clk.secure_init) - return rc; + if (vdd) { + vdd->level_votes = devm_kcalloc(&pdev->dev, j, + sizeof(*vdd->level_votes), GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; - rc = of_property_read_u32_array(of, "qcom,l3-mem-acc-addr", - l3_clk.mem_acc_addr, MEM_ACC_ADDRS); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,l3-mem-acc-addr property, rc=%d\n", - rc); - return -EINVAL; - } + vdd->vdd_uv = devm_kcalloc(&pdev->dev, j, sizeof(*vdd->vdd_uv), + GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; - rc = of_property_read_u32_array(of, "qcom,pwrcl-mem-acc-addr", - pwrcl_clk.mem_acc_addr, MEM_ACC_ADDRS); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,pwrcl-mem-acc-addr property, rc=%d\n", - rc); - return -EINVAL; + for (i = 0; i < j; i++) { + if (c->osm_table[i].frequency < c->mx_turbo_freq) + vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_NOM; + else + vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_TURBO; + } + vdd->num_levels = j; + vdd->cur_level = j; + vdd->use_max_uV = true; } - rc = of_property_read_u32_array(of, "qcom,perfcl-mem-acc-addr", - perfcl_clk.mem_acc_addr, MEM_ACC_ADDRS); - if (rc) { - dev_err(&pdev->dev, "unable to find qcom,perfcl-mem-acc-addr property, rc=%d\n", - rc); - return -EINVAL; - } + for (i = 0; i < j; i++) + osm_clks_init[c->cluster_num].rate_max[i] = + c->osm_table[i].frequency; - return rc; + c->num_entries = osm_clks_init[c->cluster_num].num_rate_max = j; + return 0; } static int clk_osm_resources_init(struct platform_device *pdev) { - struct device_node *node; struct resource *res; - unsigned long pbase; - int rc = 0; - void *vbase; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osm_l3_base"); @@ -2051,12 +1045,11 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } - l3_clk.pbases[OSM_BASE] = (unsigned long)res->start; - l3_clk.vbases[OSM_BASE] = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + l3_clk.pbase = (unsigned long)res->start; + l3_clk.vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!l3_clk.vbases[OSM_BASE]) { - dev_err(&pdev->dev, "Unable to map in osm_l3_base base\n"); + if (!l3_clk.vbase) { + dev_err(&pdev->dev, "Unable to map osm_l3_base base\n"); return -ENOMEM; } @@ -2068,11 +1061,11 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } - pwrcl_clk.pbases[OSM_BASE] = (unsigned long)res->start; - pwrcl_clk.vbases[OSM_BASE] = devm_ioremap(&pdev->dev, res->start, + pwrcl_clk.pbase = (unsigned long)res->start; + pwrcl_clk.vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!pwrcl_clk.vbases[OSM_BASE]) { - dev_err(&pdev->dev, "Unable to map in osm_pwrcl_base base\n"); + if (!pwrcl_clk.vbase) { + dev_err(&pdev->dev, "Unable to map osm_pwrcl_base base\n"); return -ENOMEM; } @@ -2084,179 +1077,97 @@ static int clk_osm_resources_init(struct platform_device *pdev) return -ENOMEM; } - perfcl_clk.pbases[OSM_BASE] = (unsigned long)res->start; - perfcl_clk.vbases[OSM_BASE] = devm_ioremap(&pdev->dev, res->start, + perfcl_clk.pbase = (unsigned long)res->start; + perfcl_clk.vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!perfcl_clk.vbases[OSM_BASE]) { - dev_err(&pdev->dev, "Unable to map in osm_perfcl_base base\n"); + if (!perfcl_clk.vbase) { + dev_err(&pdev->dev, "Unable to map osm_perfcl_base base\n"); return -ENOMEM; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l3_pll"); - if (!res) { - dev_err(&pdev->dev, - "Unable to get platform resource for l3_pll\n"); - return -ENOMEM; - } - pbase = (unsigned long)res->start; - vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - - if (!vbase) { - dev_err(&pdev->dev, "Unable to map l3_pll base\n"); - return -ENOMEM; - } - - l3_clk.pbases[PLL_BASE] = pbase; - l3_clk.vbases[PLL_BASE] = vbase; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrcl_pll"); - if (!res) { - dev_err(&pdev->dev, - "Unable to get platform resource for pwrcl_pll\n"); - return -ENOMEM; - } - pbase = (unsigned long)res->start; - vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - - if (!vbase) { - dev_err(&pdev->dev, "Unable to map pwrcl_pll base\n"); - return -ENOMEM; - } - - pwrcl_clk.pbases[PLL_BASE] = pbase; - pwrcl_clk.vbases[PLL_BASE] = vbase; + return 0; +} - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "perfcl_pll"); - if (!res) { - dev_err(&pdev->dev, - "Unable to get platform resource for perfcl_pll\n"); - return -ENOMEM; - } - pbase = (unsigned long)res->start; - vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); +static void clk_cpu_osm_driver_sdm670_fixup(void) +{ + osm_qcom_clk_hws[CPU4_PERFCL_CLK] = NULL; + osm_qcom_clk_hws[CPU5_PERFCL_CLK] = NULL; + osm_qcom_clk_hws[CPU4_PWRCL_CLK] = &cpu4_pwrcl_clk.hw; + osm_qcom_clk_hws[CPU5_PWRCL_CLK] = &cpu5_pwrcl_clk.hw; - if (!vbase) { - dev_err(&pdev->dev, "Unable to map perfcl_pll base\n"); - return -ENOMEM; - } + clk_cpu_map[4] = &cpu4_pwrcl_clk; + clk_cpu_map[5] = &cpu5_pwrcl_clk; - perfcl_clk.pbases[PLL_BASE] = pbase; - perfcl_clk.vbases[PLL_BASE] = vbase; + cpu6_perfcl_clk.core_num = 0; + cpu7_perfcl_clk.core_num = 1; - /* efuse speed bin fuses are optional */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "pwrcl_efuse"); - if (res) { - pbase = (unsigned long)res->start; - vbase = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!vbase) { - dev_err(&pdev->dev, "Unable to map in pwrcl_efuse base\n"); - return -ENOMEM; - } - pwrcl_clk.pbases[EFUSE_BASE] = pbase; - pwrcl_clk.vbases[EFUSE_BASE] = vbase; - } + pwrcl_clk.max_core_count = 6; + perfcl_clk.max_core_count = 2; +} - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "perfcl_efuse"); - if (res) { - pbase = (unsigned long)res->start; - vbase = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!vbase) { - dev_err(&pdev->dev, "Unable to map in perfcl_efuse base\n"); - return -ENOMEM; - } - perfcl_clk.pbases[EFUSE_BASE] = pbase; - perfcl_clk.vbases[EFUSE_BASE] = vbase; - } +/* Request MX supply if configured in device tree */ +static int clk_cpu_osm_request_mx_supply(struct device *dev) +{ + u32 *array; + int rc; - vdd_l3 = devm_regulator_get(&pdev->dev, "vdd-l3"); - if (IS_ERR(vdd_l3)) { - rc = PTR_ERR(vdd_l3); - if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "Unable to get the l3 vreg, rc=%d\n", - rc); - return rc; + if (!of_find_property(dev->of_node, "qcom,mx-turbo-freq", NULL)) { + osm_clks_init[l3_clk.cluster_num].vdd_class = NULL; + osm_clks_init[pwrcl_clk.cluster_num].vdd_class = NULL; + return 0; } - l3_clk.vdd_reg = vdd_l3; - vdd_pwrcl = devm_regulator_get(&pdev->dev, "vdd-pwrcl"); - if (IS_ERR(vdd_pwrcl)) { - rc = PTR_ERR(vdd_pwrcl); + vdd_l3_mx_ao.regulator[0] = devm_regulator_get(dev, "vdd_l3_mx_ao"); + if (IS_ERR(vdd_l3_mx_ao.regulator[0])) { + rc = PTR_ERR(vdd_l3_mx_ao.regulator[0]); if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "Unable to get the pwrcl vreg, rc=%d\n", + dev_err(dev, "Unable to get vdd_l3_mx_ao regulator, rc=%d\n", rc); return rc; } - pwrcl_clk.vdd_reg = vdd_pwrcl; - vdd_perfcl = devm_regulator_get(&pdev->dev, "vdd-perfcl"); - if (IS_ERR(vdd_perfcl)) { - rc = PTR_ERR(vdd_perfcl); + vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(dev, + "vdd_pwrcl_mx_ao"); + if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) { + rc = PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]); if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "Unable to get the perfcl vreg, rc=%d\n", + dev_err(dev, "Unable to get vdd_pwrcl_mx_ao regulator, rc=%d\n", rc); return rc; } - perfcl_clk.vdd_reg = vdd_perfcl; - - node = of_parse_phandle(pdev->dev.of_node, "vdd-l3-supply", 0); - if (!node) { - pr_err("Unable to find vdd-l3-supply\n"); - return -EINVAL; - } - l3_clk.vdd_dev = of_find_device_by_node(node->parent->parent); - if (!l3_clk.vdd_dev) { - pr_err("Unable to find device for vdd-l3-supply node\n"); - return -EINVAL; - } - - node = of_parse_phandle(pdev->dev.of_node, "vdd-pwrcl-supply", 0); - if (!node) { - pr_err("Unable to find vdd-pwrcl-supply\n"); - return -EINVAL; - } + array = kcalloc(MAX_CLUSTER_CNT, sizeof(*array), GFP_KERNEL); + if (!array) + return -ENOMEM; - pwrcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent); - if (!pwrcl_clk.vdd_dev) { - pr_err("Unable to find device for vdd-pwrcl-supply node\n"); - return -EINVAL; + rc = of_property_read_u32_array(dev->of_node, "qcom,mx-turbo-freq", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(dev, "unable to read qcom,mx-turbo-freq property, rc=%d\n", + rc); + kfree(array); + return rc; } - node = of_parse_phandle(pdev->dev.of_node, "vdd-perfcl-supply", 0); - if (!node) { - pr_err("Unable to find vdd-perfcl-supply\n"); - return -EINVAL; - } + l3_clk.mx_turbo_freq = array[l3_clk.cluster_num]; + pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num]; + perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num]; - perfcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent); - if (!perfcl_clk.vdd_dev) { - pr_err("Unable to find device for vdd-perfcl-supply\n"); - return -EINVAL; - } + kfree(array); return 0; } -static unsigned long init_rate = 300000000; - static int clk_cpu_osm_driver_probe(struct platform_device *pdev) { - int rc = 0, cpu, i; - int speedbin = 0, pvs_ver = 0; - u32 pte_efuse, val; + int rc = 0, i, cpu; + u32 val; int num_clks = ARRAY_SIZE(osm_qcom_clk_hws); struct clk *ext_xo_clk, *clk; - struct clk_osm *c; + struct clk_osm *osm_clk; struct device *dev = &pdev->dev; struct clk_onecell_data *clk_data; - char l3speedbinstr[] = "qcom,l3-speedbin0-v0"; - char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0"; - char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0"; struct cpu_cycle_counter_cb cb = { .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter, }; @@ -2272,6 +1183,17 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev) return PTR_ERR(ext_xo_clk); } + is_sdm845v1 = of_device_is_compatible(pdev->dev.of_node, + "qcom,clk-cpu-osm"); + + if (of_device_is_compatible(pdev->dev.of_node, + "qcom,clk-cpu-osm-sdm670")) + clk_cpu_osm_driver_sdm670_fixup(); + + rc = clk_cpu_osm_request_mx_supply(dev); + if (rc) + return rc; + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), GFP_KERNEL); if (!clk_data) @@ -2284,231 +1206,53 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev) clk_data->clk_num = num_clks; - rc = clk_osm_parse_dt_configs(pdev); - if (rc) { - dev_err(&pdev->dev, "Unable to parse device tree configurations\n"); - return rc; - } - rc = clk_osm_resources_init(pdev); if (rc) { if (rc != -EPROBE_DEFER) - dev_err(&pdev->dev, "resources init failed, rc=%d\n", - rc); - return rc; - } - - if (l3_clk.vbases[EFUSE_BASE]) { - /* Multiple speed-bins are supported */ - pte_efuse = readl_relaxed(l3_clk.vbases[EFUSE_BASE]); - l3_clk.speedbin = ((pte_efuse >> L3_EFUSE_SHIFT) & - L3_EFUSE_MASK); - snprintf(l3speedbinstr, ARRAY_SIZE(l3speedbinstr), - "qcom,l3-speedbin%d-v%d", speedbin, pvs_ver); - } - - dev_info(&pdev->dev, "using L3 speed bin %u and pvs_ver %d\n", - speedbin, pvs_ver); - - rc = clk_osm_get_lut(pdev, &l3_clk, l3speedbinstr); - if (rc) { - dev_err(&pdev->dev, "Unable to get OSM LUT for L3, rc=%d\n", - rc); - return rc; - } - - if (pwrcl_clk.vbases[EFUSE_BASE]) { - /* Multiple speed-bins are supported */ - pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]); - pwrcl_clk.speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) & - PWRCL_EFUSE_MASK); - snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr), - "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver); - } - - dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n", - speedbin, pvs_ver); - - rc = clk_osm_get_lut(pdev, &pwrcl_clk, pwrclspeedbinstr); - if (rc) { - dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n", - rc); + dev_err(&pdev->dev, "OSM resources init failed, rc=%d\n", + rc); return rc; } - if (perfcl_clk.vbases[EFUSE_BASE]) { - /* Multiple speed-bins are supported */ - pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]); - perfcl_clk.speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) & - PERFCL_EFUSE_MASK); - snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr), - "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver); - } + /* Check if per-core DCVS is enabled/not */ + val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL); + if (val & BIT(0)) + pwrcl_clk.per_core_dcvs = true; - dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n", - speedbin, pvs_ver); - - rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr); - if (rc) { - dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n", - rc); - return rc; - } + val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL); + if (val & BIT(0)) + perfcl_clk.per_core_dcvs = true; - rc = clk_osm_resolve_open_loop_voltages(&l3_clk); + rc = clk_osm_read_lut(pdev, &l3_clk); if (rc) { - if (rc == -EPROBE_DEFER) - return rc; - dev_err(&pdev->dev, "Unable to determine open-loop voltages for L3, rc=%d\n", + dev_err(&pdev->dev, "Unable to read OSM LUT for L3, rc=%d\n", rc); return rc; } - rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk); + rc = clk_osm_read_lut(pdev, &pwrcl_clk); if (rc) { - if (rc == -EPROBE_DEFER) - return rc; - dev_err(&pdev->dev, "Unable to determine open-loop voltages for power cluster, rc=%d\n", + dev_err(&pdev->dev, "Unable to read OSM LUT for power cluster, rc=%d\n", rc); return rc; } - rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk); + rc = clk_osm_read_lut(pdev, &perfcl_clk); if (rc) { - if (rc == -EPROBE_DEFER) - return rc; - dev_err(&pdev->dev, "Unable to determine open-loop voltages for perf cluster, rc=%d\n", + dev_err(&pdev->dev, "Unable to read OSM LUT for perf cluster, rc=%d\n", rc); return rc; } - rc = clk_osm_resolve_crossover_corners(&l3_clk, pdev); - if (rc) - dev_info(&pdev->dev, - "No APM crossover corner programmed for L3\n"); - - rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev); - if (rc) - dev_info(&pdev->dev, - "No APM crossover corner programmed for pwrcl_clk\n"); - - rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev); - if (rc) - dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n"); - - clk_osm_setup_cycle_counters(&l3_clk); - clk_osm_setup_cycle_counters(&pwrcl_clk); - clk_osm_setup_cycle_counters(&perfcl_clk); - - clk_osm_print_osm_table(&l3_clk); - clk_osm_print_osm_table(&pwrcl_clk); - clk_osm_print_osm_table(&perfcl_clk); - - rc = clk_osm_setup_hw_table(&l3_clk); - if (rc) { - dev_err(&pdev->dev, "failed to setup l3 hardware table\n"); - goto exit; - } - rc = clk_osm_setup_hw_table(&pwrcl_clk); - if (rc) { - dev_err(&pdev->dev, "failed to setup power cluster hardware table\n"); - goto exit; - } - rc = clk_osm_setup_hw_table(&perfcl_clk); - if (rc) { - dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n"); - goto exit; - } - - /* Policy tuning */ - rc = clk_osm_set_cc_policy(pdev); - if (rc < 0) { - dev_err(&pdev->dev, "cc policy setup failed"); - goto exit; - } - - /* LLM Freq Policy Tuning */ - rc = clk_osm_set_llm_freq_policy(pdev); - if (rc < 0) { - dev_err(&pdev->dev, "LLM Frequency Policy setup failed"); - goto exit; - } - - /* LLM Voltage Policy Tuning */ - rc = clk_osm_set_llm_volt_policy(pdev); - if (rc < 0) { - dev_err(&pdev->dev, "Failed to set LLM voltage Policy"); - goto exit; - } - - clk_osm_setup_fsms(&l3_clk); - clk_osm_setup_fsms(&pwrcl_clk); - clk_osm_setup_fsms(&perfcl_clk); - - /* Program VC at which the array power supply needs to be switched */ - clk_osm_write_reg(&perfcl_clk, perfcl_clk.apm_threshold_vc, - APM_CROSSOVER_VC); - if (perfcl_clk.secure_init) { - clk_osm_write_seq_reg(&perfcl_clk, perfcl_clk.apm_crossover_vc, - DATA_MEM(77)); - clk_osm_write_seq_reg(&perfcl_clk, - (0x39 | (perfcl_clk.apm_threshold_vc << 6)), - DATA_MEM(111)); - } else { - scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(77), - perfcl_clk.apm_crossover_vc); - scm_io_write(perfcl_clk.pbases[SEQ_BASE] + DATA_MEM(111), - (0x39 | (perfcl_clk.apm_threshold_vc << 6))); - } - - /* - * Perform typical secure-world HW initialization - * as necessary. - */ - clk_osm_do_additional_setup(&l3_clk, pdev); - clk_osm_do_additional_setup(&pwrcl_clk, pdev); - clk_osm_do_additional_setup(&perfcl_clk, pdev); - - /* MEM-ACC Programming */ - clk_osm_program_mem_acc_regs(&l3_clk); - clk_osm_program_mem_acc_regs(&pwrcl_clk); - clk_osm_program_mem_acc_regs(&perfcl_clk); - - if (of_property_read_bool(pdev->dev.of_node, "qcom,osm-pll-setup")) { - clk_osm_setup_cluster_pll(&l3_clk); - clk_osm_setup_cluster_pll(&pwrcl_clk); - clk_osm_setup_cluster_pll(&perfcl_clk); - } - - /* Misc programming */ - clk_osm_misc_programming(&l3_clk); - clk_osm_misc_programming(&pwrcl_clk); - clk_osm_misc_programming(&perfcl_clk); - - pwrcl_clk.per_core_dcvs = perfcl_clk.per_core_dcvs = - of_property_read_bool(pdev->dev.of_node, - "qcom,enable-per-core-dcvs"); - if (pwrcl_clk.per_core_dcvs) { - val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL); - val |= BIT(0); - clk_osm_write_reg(&pwrcl_clk, val, CORE_DCVS_CTRL); - - val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL); - val |= BIT(0); - clk_osm_write_reg(&perfcl_clk, val, CORE_DCVS_CTRL); - } - - clk_ops_core = clk_dummy_ops; - clk_ops_core.set_rate = cpu_clk_set_rate; - clk_ops_core.round_rate = cpu_clk_round_rate; - clk_ops_core.recalc_rate = cpu_clk_recalc_rate; - spin_lock_init(&l3_clk.lock); spin_lock_init(&pwrcl_clk.lock); spin_lock_init(&perfcl_clk.lock); /* Register OSM l3, pwr and perf clocks with Clock Framework */ for (i = 0; i < num_clks; i++) { + if (!osm_qcom_clk_hws[i]) + continue; + clk = devm_clk_register(&pdev->dev, osm_qcom_clk_hws[i]); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register CPU clock at index %d\n", @@ -2527,55 +1271,51 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev) get_online_cpus(); - /* Enable OSM */ + WARN(clk_prepare_enable(l3_cluster0_vote_clk.hw.clk), + "clk: Failed to enable cluster0 clock for L3\n"); + WARN(clk_prepare_enable(l3_cluster1_vote_clk.hw.clk), + "clk: Failed to enable cluster1 clock for L3\n"); + WARN(clk_prepare_enable(l3_misc_vote_clk.hw.clk), + "clk: Failed to enable misc clock for L3\n"); + + /* + * Call clk_prepare_enable for the silver clock explicitly in order to + * place an implicit vote on MX + */ for_each_online_cpu(cpu) { - c = logical_cpu_to_clk(cpu); - if (!c) { - pr_err("no clock device for CPU=%d\n", cpu); + osm_clk = logical_cpu_to_clk(cpu); + if (!osm_clk) return -EINVAL; - } - - rc = clk_set_rate(c->hw.clk, init_rate); - if (rc) { - dev_err(&pdev->dev, "Unable to set init rate on CPU %d, rc=%d\n", - cpu, rc); - goto provider_err; - } - WARN(clk_prepare_enable(c->hw.clk), - "Failed to enable clock for cpu %d\n", cpu); - udelay(300); + clk_prepare_enable(osm_clk->hw.clk); } - - rc = clk_set_rate(l3_clk.hw.clk, init_rate); - if (rc) { - dev_err(&pdev->dev, "Unable to set init rate on L3 cluster, rc=%d\n", - rc); - goto provider_err; - } - WARN(clk_prepare_enable(l3_clk.hw.clk), - "Failed to enable clock for L3\n"); - udelay(300); - populate_opp_table(pdev); of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); register_cpu_cycle_counter_cb(&cb); - pr_info("OSM driver inited\n"); put_online_cpus(); + rc = cpufreq_register_driver(&qcom_osm_cpufreq_driver); + if (rc) + goto provider_err; + + pr_info("OSM CPUFreq driver inited\n"); return 0; + provider_err: if (clk_data) devm_kfree(&pdev->dev, clk_data->clks); clk_err: devm_kfree(&pdev->dev, clk_data); exit: - dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", rc); - panic("Unable to Setup OSM"); + dev_err(&pdev->dev, "OSM CPUFreq driver failed to initialize, rc=%d\n", + rc); + panic("Unable to Setup OSM CPUFreq"); } static const struct of_device_id match_table[] = { { .compatible = "qcom,clk-cpu-osm" }, + { .compatible = "qcom,clk-cpu-osm-v2" }, + { .compatible = "qcom,clk-cpu-osm-sdm670" }, {} }; @@ -2592,7 +1332,7 @@ static int __init clk_cpu_osm_init(void) { return platform_driver_register(&clk_cpu_osm_driver); } -arch_initcall(clk_cpu_osm_init); +subsys_initcall(clk_cpu_osm_init); static void __exit clk_cpu_osm_exit(void) { diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c index 53288f74b49cd400209cc858bc0f5d15621faec5..d366ad4879aadaa92f4ea2d393ee616f35e83f10 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -133,12 +135,16 @@ 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); + struct clk_hw *hw_clk = clk_hw_get_parent(hw); + + if (!hw_clk) + return 0; 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); + clk_hw_get_name(hw_clk))) { + pr_debug("clock parent - %s, index %d\n", + meas->parent[i].parents, i); return i; } } @@ -158,8 +164,8 @@ static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index) /* Update the recursive debug mux */ regmap_read(meas->regmap[dbg_cc], meas->parent[index].mux_offset, ®val); - regval &= ~meas->parent[index].mux_sel_mask << - meas->parent[index].mux_sel_shift; + regval &= ~(meas->parent[index].mux_sel_mask << + meas->parent[index].mux_sel_shift); regval |= (meas->parent[index].dbg_cc_mux_sel & meas->parent[index].mux_sel_mask) << meas->parent[index].mux_sel_shift; @@ -168,31 +174,34 @@ static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index) regmap_read(meas->regmap[dbg_cc], meas->parent[index].post_div_offset, ®val); - regval &= ~meas->parent[index].post_div_mask << - meas->parent[index].post_div_shift; + regval &= ~(meas->parent[index].post_div_mask << + meas->parent[index].post_div_shift); regval |= ((meas->parent[index].post_div_val - 1) & meas->parent[index].post_div_mask) << meas->parent[index].post_div_shift; regmap_write(meas->regmap[dbg_cc], meas->parent[index].post_div_offset, regval); - regmap_read(meas->regmap[dbg_cc], + /* Not all recursive muxes have a DEBUG clock. */ + if (meas->parent[index].cbcr_offset != U32_MAX) { + regmap_read(meas->regmap[dbg_cc], meas->parent[index].cbcr_offset, ®val); - regval |= BIT(0); - regmap_write(meas->regmap[dbg_cc], + regval |= BIT(0); + regmap_write(meas->regmap[dbg_cc], meas->parent[index].cbcr_offset, regval); + } } /* Update the debug sel for GCC */ regmap_read(meas->regmap[GCC], meas->debug_offset, ®val); - regval &= ~meas->src_sel_mask << meas->src_sel_shift; + regval &= ~(meas->src_sel_mask << meas->src_sel_shift); regval |= (meas->parent[index].prim_mux_sel & meas->src_sel_mask) << meas->src_sel_shift; regmap_write(meas->regmap[GCC], meas->debug_offset, regval); /* Set the GCC mux's post divider bits */ regmap_read(meas->regmap[GCC], meas->post_div_offset, ®val); - regval &= ~meas->post_div_mask << meas->post_div_shift; + regval &= ~(meas->post_div_mask << meas->post_div_shift); regval |= ((meas->parent[index].prim_mux_div_val - 1) & meas->post_div_mask) << meas->post_div_shift; regmap_write(meas->regmap[GCC], meas->post_div_offset, regval); @@ -234,6 +243,10 @@ static int clk_debug_measure_get(void *data, u64 *val) if (meas->parent[index].dbg_cc != GCC) *val *= meas->parent[index].post_div_val; *val *= meas->parent[index].prim_mux_div_val; + + /* Accommodate for any pre-set dividers */ + if (meas->parent[index].misc_div_val) + *val *= meas->parent[index].misc_div_val; } meas_rate = clk_get_rate(hw->clk); @@ -244,7 +257,6 @@ static int clk_debug_measure_get(void *data, u64 *val) sw_rate = clk_get_rate(par->clk); if (sw_rate && meas_rate >= (sw_rate * 2)) *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); - mutex_unlock(&clk_debug_lock); return ret; diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h index 280704e43255e7f966a7f9faba06fba989c41dc3..aa8d97b2d4171f87b65791d9567abe5f17f81fcb 100644 --- a/drivers/clk/qcom/clk-debug.h +++ b/drivers/clk/qcom/clk-debug.h @@ -66,6 +66,7 @@ enum debug_cc { * @mux_offset: the debug mux offset. * @post_div_offset: register with post-divider settings for the debug mux. * @cbcr_offset: branch register to turn on debug mux. + * @misc_div_val: includes any pre-set dividers in the measurement logic. */ struct clk_src { const char *parents; @@ -81,6 +82,7 @@ struct clk_src { u32 mux_offset; u32 post_div_offset; u32 cbcr_offset; + u32 misc_div_val; }; #define MUX_SRC_LIST(...) \ diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c index 3435999019faeabd49ce6582fc51ee78e9c50ea8..07991b1d96a044ab2d8d2c8485737731e33a17e5 100644 --- a/drivers/clk/qcom/clk-dummy.c +++ b/drivers/clk/qcom/clk-dummy.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -68,14 +70,14 @@ EXPORT_SYMBOL_GPL(clk_dummy_ops); static int dummy_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { - pr_debug("%s\n", __func__); + pr_debug("\n"); return 0; } static int dummy_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - pr_debug("%s\n", __func__); + pr_debug("\n"); return 0; } diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h index 9682799a3e86b1271a474a7b89f3dc0b380fc214..70f761212ad939d9467bcdd92194d5ab6de934ec 100644 --- a/drivers/clk/qcom/clk-pll.h +++ b/drivers/clk/qcom/clk-pll.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -83,6 +83,8 @@ struct pll_config { u32 aux2_output_mask; u32 early_output_mask; u32 config_ctl_val; + u32 config_ctl_hi_val; + u32 config_ctl_hi1_val; }; void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap, diff --git a/drivers/clk/qcom/clk-qpnp-div.c b/drivers/clk/qcom/clk-qpnp-div.c index 1c3eacb56702b19d12bdca62f91c7fa6ad42a765..2ee1c182e45d791956a0a96bcb00672a0f99f015 100644 --- a/drivers/clk/qcom/clk-qpnp-div.c +++ b/drivers/clk/qcom/clk-qpnp-div.c @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 3a38d37e44adb03b480f506b731b707c1505d650..aaf2324c0e05858e3d5b8fbdeff3c696fbf5139c 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -23,8 +23,6 @@ struct freq_tbl { u8 pre_div; u16 m; u16 n; - unsigned long src_freq; -#define FIXED_FREQ_SRC 0 }; /** @@ -174,6 +172,7 @@ struct clk_rcg2 { struct clk_regmap clkr; u8 flags; #define FORCE_ENABLE_RCG BIT(0) +#define DFS_ENABLE_RCG BIT(1) }; #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) @@ -187,4 +186,8 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_dp_ops; +extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk, + struct device *dev, u8 rcg_flags); +extern unsigned long +clk_rcg2_calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div); #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 2f9cfdfac815f8a8ce995e9eb405c26f46456ea5..35bcf5aec32630eba579dbb15246afe840f2b51d 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +53,14 @@ #define N_REG 0xc #define D_REG 0x10 +/* Dynamic Frequency Scaling */ +#define MAX_PERF_LEVEL 16 +#define SE_CMD_DFSR_OFFSET 0x14 +#define SE_CMD_DFS_EN BIT(0) +#define SE_PERF_DFSR(level) (0x1c + 0x4 * (level)) +#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level)) +#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level)) + static struct freq_tbl cxo_f = { .freq = 19200000, .src = 0, @@ -90,8 +101,8 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw) return i; err: - pr_debug("%s: Clock %s has invalid parent, using default.\n", - __func__, clk_hw_get_name(hw)); + pr_debug("Clock %s has invalid parent, using default.\n", + clk_hw_get_name(hw)); return 0; } @@ -117,7 +128,7 @@ static int update_config(struct clk_rcg2 *rcg) udelay(1); } - WARN(1, "%s: rcg didn't update its configuration.", name); + WARN(1, "clk: %s: rcg didn't update its configuration.", name); return 0; } @@ -152,7 +163,7 @@ static int clk_rcg2_set_force_enable(struct clk_hw *hw) udelay(1); } - WARN(1, "%s: rcg didn't turn on.", clk_hw_get_name(hw)); + WARN(1, "clk: %s: rcg didn't turn on.", clk_hw_get_name(hw)); return ret; } @@ -212,8 +223,8 @@ static void disable_unprepare_rcg_srcs(struct clk *curr, struct clk *new) * rate = ----------- x --- * hid_div n */ -static unsigned long -calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) +unsigned long +clk_rcg2_calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) { if (hid_div) { rate *= 2; @@ -229,6 +240,7 @@ calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) return rate; } +EXPORT_SYMBOL(clk_rcg2_calc_rate); static unsigned long clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -236,6 +248,9 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_rcg2 *rcg = to_clk_rcg2(hw); u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask; + if (rcg->flags & DFS_ENABLE_RCG) + return rcg->current_freq; + if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { if (!rcg->current_freq) rcg->current_freq = cxo_f.freq; @@ -260,17 +275,16 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) hid_div = cfg >> CFG_SRC_DIV_SHIFT; hid_div &= mask; - return calc_rate(parent_rate, m, n, mode, hid_div); + return clk_rcg2_calc_rate(parent_rate, m, n, mode, hid_div); } static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, struct clk_rate_request *req) { unsigned long clk_flags, rate = req->rate; - struct clk_rate_request parent_req = { }; struct clk_hw *p; struct clk_rcg2 *rcg = to_clk_rcg2(hw); - int index, ret = 0; + int index; f = qcom_find_freq(f, rate); if (!f) @@ -301,21 +315,6 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, req->best_parent_rate = rate; req->rate = f->freq; - if (f->src_freq != FIXED_FREQ_SRC) { - rate = parent_req.rate = f->src_freq; - parent_req.best_parent_hw = p; - ret = __clk_determine_rate(p, &parent_req); - if (ret) - return ret; - - ret = clk_set_rate(p->clk, parent_req.rate); - if (ret) { - pr_err("Failed set rate(%lu) on parent for non-fixed source\n", - parent_req.rate); - return ret; - } - } - return 0; } @@ -333,6 +332,10 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) struct clk_hw *hw = &rcg->clkr.hw; int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src); + /* Skip configuration if DFS control has been enabled for the RCG. */ + if (rcg->flags & DFS_ENABLE_RCG) + return 0; + if (index < 0) return index; @@ -762,7 +765,7 @@ static int clk_edp_pixel_determine_rate(struct clk_hw *hw, hid_div >>= CFG_SRC_DIV_SHIFT; hid_div &= mask; - req->rate = calc_rate(req->best_parent_rate, + req->rate = clk_rcg2_calc_rate(req->best_parent_rate, frac->num, frac->den, !!frac->den, hid_div); return 0; @@ -802,7 +805,7 @@ static int clk_byte_determine_rate(struct clk_hw *hw, div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1; div = min_t(u32, div, mask); - req->rate = calc_rate(parent_rate, 0, 0, 0, div); + req->rate = clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div); return 0; } @@ -860,7 +863,7 @@ static int clk_byte2_determine_rate(struct clk_hw *hw, div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; div = min_t(u32, div, mask); - req->rate = calc_rate(parent_rate, 0, 0, 0, div); + req->rate = clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div); return 0; } @@ -914,10 +917,11 @@ const struct clk_ops clk_byte2_ops = { EXPORT_SYMBOL_GPL(clk_byte2_ops); static const struct frac_entry frac_table_pixel[] = { + { 1, 1 }, + { 2, 3 }, + { 4, 9 }, { 3, 8 }, { 2, 9 }, - { 4, 9 }, - { 1, 1 }, { } }; @@ -1008,6 +1012,7 @@ static int clk_dp_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct clk_hw *parent = clk_hw_get_parent(hw); struct freq_tbl f = { 0 }; unsigned long src_rate; unsigned long num, den; @@ -1015,7 +1020,12 @@ static int clk_dp_set_rate(struct clk_hw *hw, unsigned long rate, u32 hid_div, cfg; int i, num_parents = clk_hw_get_num_parents(hw); - src_rate = clk_get_rate(clk_hw_get_parent(hw)->clk); + if (!parent) { + pr_err("RCG parent isn't initialized\n"); + return -EINVAL; + } + + src_rate = clk_get_rate(parent->clk); if (src_rate <= 0) { pr_err("Invalid RCG parent rate\n"); return -EINVAL; @@ -1064,17 +1074,10 @@ static int clk_dp_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, } static int clk_dp_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) + struct clk_rate_request *req) { - if (!hw) - return -EINVAL; - - if (!clk_hw_get_parent(hw)) { - pr_err("Missing the parent for the DP RCG\n"); - return -EINVAL; - } - - req->best_parent_rate = clk_get_rate(clk_hw_get_parent(hw)->clk); + req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw, + req->best_parent_rate); return 0; } @@ -1177,3 +1180,171 @@ const struct clk_ops clk_gfx3d_ops = { .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_gfx3d_ops); + +/* Common APIs to be used for DFS based RCGR */ +static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset, + u32 *mode, u32 *pre_div) +{ + struct clk_rcg2 *rcg; + int num_parents; + u32 cfg, mask; + int i, ret; + + if (!hw) + return -EINVAL; + + num_parents = clk_hw_get_num_parents(hw); + + rcg = to_clk_rcg2(hw); + + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg); + if (ret) + goto err; + + mask = BIT(rcg->hid_width) - 1; + *pre_div = cfg & mask ? (cfg & mask) : 1; + + *mode = cfg & CFG_MODE_MASK; + *mode >>= CFG_MODE_SHIFT; + + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + for (i = 0; i < num_parents; i++) + if (cfg == rcg->parent_map[i].cfg) + return i; +err: + pr_debug("Clock %s has invalid parent, using default.\n", + clk_hw_get_name(hw)); + return 0; +} + +static int calculate_m_and_n(struct clk_hw *hw, u32 m_offset, u32 n_offset, + u32 mode, u32 *m, u32 *n) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + u32 val, mask; + int ret = 0; + + if (!hw) + return -EINVAL; + + *m = *n = 0; + + if (mode) { + /* Calculate M & N values */ + mask = BIT(rcg->mnd_width) - 1; + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_offset, + &val); + if (ret) { + pr_err("Failed to read M offset register\n"); + goto err; + } + + val &= mask; + *m = val; + + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_offset, + &val); + if (ret) { + pr_err("Failed to read N offset register\n"); + goto err; + } + + /* val ~(N-M) */ + val = ~val; + val &= mask; + val += *m; + *n = val; + } +err: + return ret; +} + +int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk, struct device *dev, + u8 rcg_flags) +{ + int i, j, index, ret = 0; + unsigned long calc_freq, prate; + u32 val, pre_div = 0, mode = 0, m = 0, n = 0; + struct freq_tbl *dfs_freq_tbl; + struct clk_hw *phw; + + if (!clk) + return -EINVAL; + + /* Check for DFS_EN */ + ret = regmap_read(clk->clkr.regmap, clk->cmd_rcgr + SE_CMD_DFSR_OFFSET, + &val); + if (ret) { + dev_err(dev, "Failed to read DFS enable register\n"); + return -EINVAL; + } + + if (!(val & SE_CMD_DFS_EN)) + return ret; + + dfs_freq_tbl = devm_kzalloc(dev, MAX_PERF_LEVEL * + sizeof(struct freq_tbl), GFP_KERNEL); + if (!dfs_freq_tbl) + return -ENOMEM; + + /* Populate the Perf Level */ + for (i = 0; i < MAX_PERF_LEVEL; i++) { + /* Get parent index and mode */ + index = clk_parent_index_pre_div_and_mode(&clk->clkr.hw, + SE_PERF_DFSR(i), &mode, + &pre_div); + if (index < 0) { + pr_err("Failed to get parent index & mode %d\n", index); + return index; + } + + /* clock pre_div */ + dfs_freq_tbl[i].pre_div = pre_div; + + /* Fill the parent src */ + dfs_freq_tbl[i].src = clk->parent_map[index].src; + + /* Get the parent clock and parent rate */ + phw = clk_hw_get_parent_by_index(&clk->clkr.hw, index); + prate = clk_hw_get_rate(phw); + + ret = calculate_m_and_n(&clk->clkr.hw, SE_PERF_M_DFSR(i), + SE_PERF_N_DFSR(i), mode, &m, &n); + if (ret) + goto err; + + dfs_freq_tbl[i].m = m; + dfs_freq_tbl[i].n = n; + + /* calculate the final frequency */ + calc_freq = clk_rcg2_calc_rate(prate, dfs_freq_tbl[i].m, + dfs_freq_tbl[i].n, mode, + dfs_freq_tbl[i].pre_div); + + /* Check for duplicate frequencies */ + for (j = 0; j < i; j++) { + if (dfs_freq_tbl[j].freq == calc_freq) + goto done; + } + + dfs_freq_tbl[i].freq = calc_freq; + } +done: + j = i; + + for (i = 0; i < j; i++) + pr_debug("Index[%d]\tfreq_table.freq %ld\tfreq_table.src %d\t" + "freq_table.pre_div %d\tfreq_table.m %d\tfreq_table.n %d\t" + "RCG flags %x\n", i, dfs_freq_tbl[i].freq, dfs_freq_tbl[i].src, + dfs_freq_tbl[i].pre_div, dfs_freq_tbl[i].m, + dfs_freq_tbl[i].n, rcg_flags); + /* Skip the safe configuration if DFS has been enabled for the RCG. */ + if (clk->enable_safe_config) + clk->enable_safe_config = false; + clk->flags |= rcg_flags; + clk->freq_tbl = dfs_freq_tbl; +err: + return ret; +} diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 53484912301eeed5d0d43012af1e2474d1c40d65..c314d2c406b7bd0591b31bb7b954bdac0716c1a2 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -28,8 +28,10 @@ static long div_round_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap_div *divider = to_clk_regmap_div(hw); - return divider_round_rate(hw, rate, prate, NULL, divider->width, - CLK_DIVIDER_ROUND_CLOSEST); + return divider_round_rate(hw, rate, prate, divider->table, + divider->width, + CLK_DIVIDER_ROUND_CLOSEST | + divider->flags); } static int div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -39,8 +41,9 @@ static int div_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_regmap *clkr = ÷r->clkr; u32 div; - div = divider_get_val(rate, parent_rate, NULL, divider->width, - CLK_DIVIDER_ROUND_CLOSEST); + div = divider_get_val(rate, parent_rate, divider->table, + divider->width, CLK_DIVIDER_ROUND_CLOSEST | + divider->flags); return regmap_update_bits(clkr->regmap, divider->reg, (BIT(divider->width) - 1) << divider->shift, @@ -58,8 +61,8 @@ static unsigned long div_recalc_rate(struct clk_hw *hw, div >>= divider->shift; div &= BIT(divider->width) - 1; - return divider_recalc_rate(hw, parent_rate, div, NULL, - CLK_DIVIDER_ROUND_CLOSEST); + return divider_recalc_rate(hw, parent_rate, div, divider->table, + CLK_DIVIDER_ROUND_CLOSEST | divider->flags); } const struct clk_ops clk_regmap_div_ops = { diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h index fc4492e3a82731cb88e76e81b1fe93bc2bfe9cd2..1c5e087e2bb8c4e16fc8dad597186b3de6e846c8 100644 --- a/drivers/clk/qcom/clk-regmap-divider.h +++ b/drivers/clk/qcom/clk-regmap-divider.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -18,10 +18,12 @@ #include "clk-regmap.h" struct clk_regmap_div { - u32 reg; - u32 shift; - u32 width; - struct clk_regmap clkr; + u32 reg; + u32 shift; + u32 width; + u32 flags; + const struct clk_div_table *table; + struct clk_regmap clkr; }; extern const struct clk_ops clk_regmap_div_ops; diff --git a/drivers/clk/qcom/clk-regmap-mux-div.c b/drivers/clk/qcom/clk-regmap-mux-div.c new file mode 100644 index 0000000000000000000000000000000000000000..942a68e2a6509238de03a9217900398ffc021b85 --- /dev/null +++ b/drivers/clk/qcom/clk-regmap-mux-div.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2015, Linaro Limited + * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "clk-regmap-mux-div.h" + +#define CMD_RCGR 0x0 +#define CMD_RCGR_UPDATE BIT(0) +#define CMD_RCGR_DIRTY_CFG BIT(4) +#define CMD_RCGR_ROOT_OFF BIT(31) +#define CFG_RCGR 0x4 + +#define to_clk_regmap_mux_div(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr) + +int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div) +{ + int ret, count; + u32 val, mask; + const char *name = clk_hw_get_name(&md->clkr.hw); + + val = (div << md->hid_shift) | (src << md->src_shift); + mask = ((BIT(md->hid_width) - 1) << md->hid_shift) | + ((BIT(md->src_width) - 1) << md->src_shift); + + ret = regmap_update_bits(md->clkr.regmap, CFG_RCGR + md->reg_offset, + mask, val); + if (ret) + return ret; + + ret = regmap_update_bits(md->clkr.regmap, CMD_RCGR + md->reg_offset, + CMD_RCGR_UPDATE, CMD_RCGR_UPDATE); + if (ret) + return ret; + + /* Wait for update to take effect */ + for (count = 500; count > 0; count--) { + ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, + &val); + if (ret) + return ret; + if (!(val & CMD_RCGR_UPDATE)) + return 0; + udelay(1); + } + + pr_err("%s: RCG did not update its configuration", name); + return -EBUSY; +} + +int mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src, + u32 *div) +{ + int ret = 0; + u32 val, __div, __src; + const char *name = clk_hw_get_name(&md->clkr.hw); + + ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, &val); + if (ret) + return ret; + + if (val & CMD_RCGR_DIRTY_CFG) { + pr_err("%s: RCG configuration is pending\n", name); + return -EBUSY; + } + + ret = regmap_read(md->clkr.regmap, CFG_RCGR + md->reg_offset, &val); + if (ret) + return ret; + + __src = (val >> md->src_shift); + __src &= BIT(md->src_width) - 1; + *src = __src; + + __div = (val >> md->hid_shift); + __div &= BIT(md->hid_width) - 1; + *div = __div; + + return ret; +} + +static int mux_div_enable(struct clk_hw *hw) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(md, md->src, md->div); +} + +static inline bool is_better_rate(unsigned long req, unsigned long best, + unsigned long new) +{ + return (req <= new && new < best) || (best < req && best < new); +} + +static int mux_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + unsigned int i, div, max_div; + unsigned long actual_rate, best_rate = 0; + unsigned long req_rate = req->rate; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i); + unsigned long parent_rate = clk_hw_get_rate(parent); + + max_div = BIT(md->hid_width) - 1; + for (div = 1; div < max_div; div++) { + parent_rate = mult_frac(req_rate, div, 2); + parent_rate = clk_hw_round_rate(parent, parent_rate); + actual_rate = mult_frac(parent_rate, 2, div); + + if (is_better_rate(req_rate, best_rate, actual_rate)) { + best_rate = actual_rate; + req->rate = best_rate; + req->best_parent_rate = parent_rate; + req->best_parent_hw = parent; + } + + if (actual_rate < req_rate || best_rate <= req_rate) + break; + } + } + + if (!best_rate) + return -EINVAL; + + return 0; +} + +static int __mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u32 src) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + int ret; + u32 div, max_div, best_src = 0, best_div = 0; + unsigned int i; + unsigned long actual_rate, best_rate = 0; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i); + unsigned long parent_rate = clk_hw_get_rate(parent); + + max_div = BIT(md->hid_width) - 1; + for (div = 1; div < max_div; div++) { + parent_rate = mult_frac(rate, div, 2); + parent_rate = clk_hw_round_rate(parent, parent_rate); + actual_rate = mult_frac(parent_rate, 2, div); + + if (is_better_rate(rate, best_rate, actual_rate)) { + best_rate = actual_rate; + best_src = md->parent_map[i].cfg; + best_div = div - 1; + } + + if (actual_rate < rate || best_rate <= rate) + break; + } + } + + ret = __mux_div_set_src_div(md, best_src, best_div); + if (!ret) { + md->div = best_div; + md->src = best_src; + } + + return ret; +} + +static u8 mux_div_get_parent(struct clk_hw *hw) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + const char *name = clk_hw_get_name(hw); + u32 i, div, src = 0; + + mux_div_get_src_div(md, &src, &div); + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) + if (src == md->parent_map[i].cfg) + return i; + + pr_err("%s: Can't find parent with src %d\n", name, src); + return 0; +} + +static int mux_div_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(md, md->parent_map[index].cfg, md->div); +} + +static int mux_div_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long prate) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return __mux_div_set_rate_and_parent(hw, rate, prate, md->src); +} + +static int mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u8 index) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return __mux_div_set_rate_and_parent(hw, rate, prate, + md->parent_map[index].cfg); +} + +static unsigned long mux_div_recalc_rate(struct clk_hw *hw, unsigned long prate) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + u32 div, src; + int i, num_parents = clk_hw_get_num_parents(hw); + const char *name = clk_hw_get_name(hw); + + mux_div_get_src_div(md, &src, &div); + for (i = 0; i < num_parents; i++) + if (src == md->parent_map[i].cfg) { + struct clk_hw *p = clk_hw_get_parent_by_index(hw, i); + unsigned long parent_rate = clk_hw_get_rate(p); + + return mult_frac(parent_rate, 2, div + 1); + } + + pr_err("%s: Can't find parent %d\n", name, src); + return 0; +} + +static void mux_div_disable(struct clk_hw *hw) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + __mux_div_set_src_div(md, md->safe_src, md->safe_div); +} + +const struct clk_ops clk_regmap_mux_div_ops = { + .enable = mux_div_enable, + .disable = mux_div_disable, + .get_parent = mux_div_get_parent, + .set_parent = mux_div_set_parent, + .set_rate = mux_div_set_rate, + .set_rate_and_parent = mux_div_set_rate_and_parent, + .determine_rate = mux_div_determine_rate, + .recalc_rate = mux_div_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_div_ops); diff --git a/drivers/clk/qcom/clk-regmap-mux-div.h b/drivers/clk/qcom/clk-regmap-mux-div.h new file mode 100644 index 0000000000000000000000000000000000000000..6cd8d4fa121861829b0ba866d925136527e285d2 --- /dev/null +++ b/drivers/clk/qcom/clk-regmap-mux-div.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Linaro Limited + * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __QCOM_CLK_REGMAP_MUX_DIV_H__ +#define __QCOM_CLK_REGMAP_MUX_DIV_H__ + +#include +#include "clk-rcg.h" +#include "clk-regmap.h" + +/** + * struct mux_div_clk - combined mux/divider clock + * @reg_offset: offset of the mux/divider register + * @hid_width: number of bits in half integer divider + * @hid_shift: lowest bit of hid value field + * @src_width: number of bits in source select + * @src_shift: lowest bit of source select field + * @div: the divider raw configuration value + * @src: the mux index which will be used if the clock is enabled + * @safe_src: the safe source mux value we switch to, while the main PLL is + * reconfigured + * @safe_div: the safe divider value that we set, while the main PLL is + * reconfigured + * @safe_freq: When switching rates from A to B, the mux div clock will + * instead switch from A -> safe_freq -> B. This allows the + * mux_div clock to change rates while enabled, even if this + * behavior is not supported by the parent clocks. + * If changing the rate of parent A also causes the rate of + * parent B to change, then safe_freq must be defined. + * safe_freq is expected to have a source clock which is always + * on and runs at only one rate. + * @parent_map: pointer to parent_map struct + * @clkr: handle between common and hardware-specific interfaces + * @clk_nb: clock notifier registered for clock rate change + */ + +struct clk_regmap_mux_div { + u32 reg_offset; + u32 hid_width; + u32 hid_shift; + u32 src_width; + u32 src_shift; + u32 div; + u32 src; + u32 safe_src; + u32 safe_div; + unsigned long safe_freq; + const struct parent_map *parent_map; + struct clk_regmap clkr; + struct notifier_block clk_nb; +}; + +extern const struct clk_ops clk_regmap_mux_div_ops; +int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div); +int mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src, u32 *div); + +#endif diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c index 1c856d330733f160041a695a4aa205430e05a840..aa024c2dd9938f594d70aee450530e997826cbb5 100644 --- a/drivers/clk/qcom/clk-regmap.c +++ b/drivers/clk/qcom/clk-regmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -103,9 +103,12 @@ EXPORT_SYMBOL_GPL(clk_disable_regmap); */ int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk) { - if (dev && dev_get_regmap(dev, NULL)) + if (!dev || !rclk) + return -EINVAL; + + if (dev_get_regmap(dev, NULL)) rclk->regmap = dev_get_regmap(dev, NULL); - else if (dev && dev->parent) + else if (dev->parent) rclk->regmap = dev_get_regmap(dev->parent, NULL); return devm_clk_hw_register(dev, &rclk->hw); diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 5e11485f0859e0e48672261267bcaf2ef7021b1c..1f90d46a5ec688bf23f605efee5836bf800a00e2 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -243,7 +245,7 @@ static void clk_rpmh_unprepare(struct clk_hw *hw) if (ret) { c->state = c->valid_state_mask; - WARN(1, "%s failed to disable\n", c->res_name); + WARN(1, "clk: %s failed to disable\n", c->res_name); } out: @@ -315,10 +317,47 @@ static const struct clk_rpmh_desc clk_rpmh_sdm845 = { static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,rpmh-clk-sdm845", .data = &clk_rpmh_sdm845}, + { .compatible = "qcom,rpmh-clk-sdm670", .data = &clk_rpmh_sdm845}, + { .compatible = "qcom,rpmh-clk-sdxpoorwills", .data = &clk_rpmh_sdm845}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); +static void clk_rpmh_sdm670_fixup(void) +{ + sdm845_rpmh_clocks[RPMH_RF_CLK3] = NULL; + sdm845_rpmh_clocks[RPMH_RF_CLK3_A] = NULL; +} + +static void clk_rpmh_sdxpoorwills_fixup(void) +{ + sdm845_rpmh_clocks[RPMH_LN_BB_CLK2] = NULL; + sdm845_rpmh_clocks[RPMH_LN_BB_CLK2_A] = NULL; + sdm845_rpmh_clocks[RPMH_LN_BB_CLK3] = NULL; + sdm845_rpmh_clocks[RPMH_LN_BB_CLK3_A] = NULL; + sdm845_rpmh_clocks[RPMH_RF_CLK2] = NULL; + sdm845_rpmh_clocks[RPMH_RF_CLK2_A] = NULL; + sdm845_rpmh_clocks[RPMH_RF_CLK3] = NULL; + sdm845_rpmh_clocks[RPMH_RF_CLK3_A] = NULL; +} + +static int clk_rpmh_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,rpmh-clk-sdm670")) + clk_rpmh_sdm670_fixup(); + else if (!strcmp(compat, "qcom,rpmh-clk-sdxpoorwills")) + clk_rpmh_sdxpoorwills_fixup(); + + return 0; +} + static int clk_rpmh_probe(struct platform_device *pdev) { struct clk **clks; @@ -386,6 +425,10 @@ static int clk_rpmh_probe(struct platform_device *pdev) goto err2; } + ret = clk_rpmh_fixup(pdev); + if (ret) + return ret; + hw_clks = desc->clks; num_clks = desc->num_clks; @@ -402,6 +445,11 @@ static int clk_rpmh_probe(struct platform_device *pdev) data->clk_num = num_clks; for (i = 0; i < num_clks; i++) { + if (!hw_clks[i]) { + clks[i] = ERR_PTR(-ENOENT); + continue; + } + rpmh_clk = to_clk_rpmh(hw_clks[i]); rpmh_clk->res_addr = cmd_db_get_addr(rpmh_clk->res_name); if (!rpmh_clk->res_addr) { @@ -449,7 +497,7 @@ static int __init clk_rpmh_init(void) { return platform_driver_register(&clk_rpmh_driver); } -core_initcall(clk_rpmh_init); +subsys_initcall(clk_rpmh_init); static void __exit clk_rpmh_exit(void) { diff --git a/drivers/clk/qcom/clk-voter.c b/drivers/clk/qcom/clk-voter.c index b0c7e4a09703c83fe7379280b11447b0c9c674c9..1a8f0ca6f51534c5637ca4730e60ee1bfb8f7fe9 100644 --- a/drivers/clk/qcom/clk-voter.c +++ b/drivers/clk/qcom/clk-voter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include "clk-voter.h" diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index fffcbaf0fba74b3fad90ea48c25761aa7873ab43..d426691d8c64b35350369eab9c1f7ddda99ac587 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -181,7 +183,7 @@ static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec, unsigned int idx = clkspec->args[0]; if (idx >= cc->num_rclks) { - pr_err("%s: invalid index %u\n", __func__, idx); + pr_err("invalid index %u\n", idx); return ERR_PTR(-EINVAL); } @@ -275,4 +277,26 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) } EXPORT_SYMBOL_GPL(qcom_cc_probe); +int qcom_cc_register_rcg_dfs(struct platform_device *pdev, + const struct qcom_cc_dfs_desc *desc) +{ + struct clk_dfs *clks = desc->clks; + size_t num_clks = desc->num_clks; + int i, ret = 0; + + for (i = 0; i < num_clks; i++) { + ret = clk_rcg2_get_dfs_clock_rate(clks[i].rcg, &pdev->dev, + clks[i].rcg_flags); + if (ret) { + dev_err(&pdev->dev, + "Failed calculating DFS frequencies for %s\n", + clk_hw_get_name(&(clks[i].rcg)->clkr.hw)); + break; + } + } + + return ret; +} +EXPORT_SYMBOL(qcom_cc_register_rcg_dfs); + MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index e728decf7d9db2a1630ac46a31414ffd5be3a4a1..5e26763d153f74ed77b6fc9fd428c05c83be2d13 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -14,6 +14,7 @@ #define __QCOM_CLK_COMMON_H__ #include +#include "clk-rcg.h" struct platform_device; struct regmap_config; @@ -40,6 +41,16 @@ struct clk_dummy { unsigned long rrate; }; +struct clk_dfs { + struct clk_rcg2 *rcg; + u8 rcg_flags; +}; + +struct qcom_cc_dfs_desc { + struct clk_dfs *clks; + size_t num_clks; +}; + extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate); extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, @@ -56,6 +67,10 @@ extern int qcom_cc_really_probe(struct platform_device *pdev, struct regmap *regmap); extern int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc); + +extern int qcom_cc_register_rcg_dfs(struct platform_device *pdev, + const struct qcom_cc_dfs_desc *desc); + extern struct clk_ops clk_dummy_ops; #define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c index d30675c4125dab3f73ac8fd58c1fc38bb9168915..45bd55686ac6f8ec73f174aca792e1c794a8cc81 100644 --- a/drivers/clk/qcom/debugcc-sdm845.c +++ b/drivers/clk/qcom/debugcc-sdm845.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -45,6 +47,7 @@ static const char *const debug_mux_parent_names[] = { "cam_cc_csiphy0_clk", "cam_cc_csiphy1_clk", "cam_cc_csiphy2_clk", + "cam_cc_csiphy3_clk", "cam_cc_fd_core_clk", "cam_cc_fd_core_uar_clk", "cam_cc_icp_apb_clk", @@ -104,14 +107,6 @@ static const char *const debug_mux_parent_names[] = { "disp_cc_mdss_rot_clk", "disp_cc_mdss_rscc_ahb_clk", "disp_cc_mdss_rscc_vsync_clk", - "disp_cc_mdss_spdm_debug_clk", - "disp_cc_mdss_spdm_dp_crypto_clk", - "disp_cc_mdss_spdm_dp_pixel1_clk", - "disp_cc_mdss_spdm_dp_pixel_clk", - "disp_cc_mdss_spdm_mdp_clk", - "disp_cc_mdss_spdm_pclk0_clk", - "disp_cc_mdss_spdm_pclk1_clk", - "disp_cc_mdss_spdm_rot_clk", "disp_cc_mdss_vsync_clk", "measure_only_snoc_clk", "measure_only_cnoc_clk", @@ -122,6 +117,7 @@ static const char *const debug_mux_parent_names[] = { "gcc_aggre_ufs_phy_axi_clk", "gcc_aggre_usb3_prim_axi_clk", "gcc_aggre_usb3_sec_axi_clk", + "gcc_apc_vs_clk", "gcc_boot_rom_ahb_clk", "gcc_camera_ahb_clk", "gcc_camera_axi_clk", @@ -149,12 +145,14 @@ static const char *const debug_mux_parent_names[] = { "gcc_gpu_gpll0_div_clk_src", "gcc_gpu_memnoc_gfx_clk", "gcc_gpu_snoc_dvm_gfx_clk", + "gcc_gpu_vs_clk", "gcc_mss_axis2_clk", "gcc_mss_cfg_ahb_clk", "gcc_mss_gpll0_div_clk_src", "gcc_mss_mfab_axis_clk", "gcc_mss_q6_memnoc_axi_clk", "gcc_mss_snoc_axi_clk", + "gcc_mss_vs_clk", "gcc_pcie_0_aux_clk", "gcc_pcie_0_cfg_ahb_clk", "gcc_pcie_0_mstr_axi_clk", @@ -237,11 +235,18 @@ static const char *const debug_mux_parent_names[] = { "gcc_usb3_sec_phy_com_aux_clk", "gcc_usb3_sec_phy_pipe_clk", "gcc_usb_phy_cfg_ahb2phy_clk", + "gcc_vdda_vs_clk", + "gcc_vddcx_vs_clk", + "gcc_vddmx_vs_clk", "gcc_video_ahb_clk", "gcc_video_axi_clk", "gcc_video_xo_clk", + "gcc_vs_ctrl_ahb_clk", + "gcc_vs_ctrl_clk", + "gcc_sdcc1_ahb_clk", + "gcc_sdcc1_apps_clk", + "gcc_sdcc1_ice_core_clk", "gpu_cc_acd_cxo_clk", - "gpu_cc_ahb_clk", "gpu_cc_crc_ahb_clk", "gpu_cc_cx_apb_clk", "gpu_cc_cx_gfx3d_clk", @@ -253,14 +258,13 @@ static const char *const debug_mux_parent_names[] = { "gpu_cc_cx_snoc_dvm_clk", "gpu_cc_cxo_aon_clk", "gpu_cc_cxo_clk", - "gpu_cc_gx_cxo_clk", + "gpu_cc_gx_gfx3d_clk", "gpu_cc_gx_gmu_clk", "gpu_cc_gx_qdss_tsctr_clk", "gpu_cc_gx_vsense_clk", "gpu_cc_rbcpr_ahb_clk", "gpu_cc_rbcpr_clk", "gpu_cc_sleep_clk", - "gpu_cc_spdm_gx_gfx3d_div_clk", "video_cc_apb_clk", "video_cc_at_clk", "video_cc_qdss_trig_clk", @@ -272,6 +276,9 @@ static const char *const debug_mux_parent_names[] = { "video_cc_venus_ahb_clk", "video_cc_venus_ctl_axi_clk", "video_cc_venus_ctl_core_clk", + "l3_clk", + "pwrcl_clk", + "perfcl_clk", }; static struct clk_debug_mux gcc_debug_mux = { @@ -312,6 +319,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x8, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, { "cam_cc_csiphy2_clk", 0x46, 4, CAM_CC, 0xA, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csiphy3_clk", 0x46, 4, CAM_CC, + 0x36, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, { "cam_cc_fd_core_clk", 0x46, 4, CAM_CC, 0x28, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, { "cam_cc_fd_core_uar_clk", 0x46, 4, CAM_CC, @@ -430,22 +439,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x17, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, { "disp_cc_mdss_rscc_vsync_clk", 0x47, 4, DISP_CC, 0x18, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_debug_clk", 0x47, 4, DISP_CC, - 0x20, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_dp_crypto_clk", 0x47, 4, DISP_CC, - 0x1D, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_dp_pixel1_clk", 0x47, 4, DISP_CC, - 0x1F, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_dp_pixel_clk", 0x47, 4, DISP_CC, - 0x1E, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_mdp_clk", 0x47, 4, DISP_CC, - 0x1B, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_pclk0_clk", 0x47, 4, DISP_CC, - 0x19, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_pclk1_clk", 0x47, 4, DISP_CC, - 0x1A, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, - { "disp_cc_mdss_spdm_rot_clk", 0x47, 4, DISP_CC, - 0x1C, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, { "disp_cc_mdss_vsync_clk", 0x47, 4, DISP_CC, 0x6, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, { "measure_only_snoc_clk", 0x7, 4, GCC, @@ -466,6 +459,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x11B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_aggre_usb3_sec_axi_clk", 0x11C, 4, GCC, 0x11C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_apc_vs_clk", 0x113, 4, GCC, + 0x113, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_boot_rom_ahb_clk", 0x94, 4, GCC, 0x94, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_camera_ahb_clk", 0x3A, 4, GCC, @@ -520,6 +515,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x145, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_gpu_snoc_dvm_gfx_clk", 0x147, 4, GCC, 0x147, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_vs_clk", 0x112, 4, GCC, + 0x112, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_mss_axis2_clk", 0x12F, 4, GCC, 0x12F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_mss_cfg_ahb_clk", 0x12D, 4, GCC, @@ -532,6 +529,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x135, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_mss_snoc_axi_clk", 0x134, 4, GCC, 0x134, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_vs_clk", 0x111, 4, GCC, + 0x111, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_pcie_0_aux_clk", 0xE5, 4, GCC, 0xE5, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_pcie_0_cfg_ahb_clk", 0xE4, 4, GCC, @@ -696,16 +695,30 @@ static struct clk_debug_mux gcc_debug_mux = { 0x6A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_usb_phy_cfg_ahb2phy_clk", 0x6F, 4, GCC, 0x6F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vdda_vs_clk", 0x10E, 4, GCC, + 0x10E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vddcx_vs_clk", 0x10C, 4, GCC, + 0x10C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vddmx_vs_clk", 0x10D, 4, GCC, + 0x10D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_video_ahb_clk", 0x39, 4, GCC, 0x39, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_video_axi_clk", 0x3F, 4, GCC, 0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gcc_video_xo_clk", 0x42, 4, GCC, 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vs_ctrl_ahb_clk", 0x110, 4, GCC, + 0x110, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vs_ctrl_clk", 0x10F, 4, GCC, + 0x10F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc1_ahb_clk", 0x15C, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc1_apps_clk", 0x15B, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc1_ice_core_clk", 0x15D, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, { "gpu_cc_acd_cxo_clk", 0x144, 4, GPU_CC, 0x1F, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_ahb_clk", 0x144, 4, GPU_CC, - 0x11, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_crc_ahb_clk", 0x144, 4, GPU_CC, 0x12, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cx_apb_clk", 0x144, 4, GPU_CC, @@ -728,8 +741,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0xB, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cxo_clk", 0x144, 4, GPU_CC, 0xA, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_gx_cxo_clk", 0x144, 4, GPU_CC, - 0xF, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_gx_gfx3d_clk", 0x144, 4, GPU_CC, + 0xC, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_gx_gmu_clk", 0x144, 4, GPU_CC, 0x10, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_gx_qdss_tsctr_clk", 0x144, 4, GPU_CC, @@ -742,8 +755,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x1C, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_sleep_clk", 0x144, 4, GPU_CC, 0x17, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_spdm_gx_gfx3d_div_clk", 0x144, 4, GPU_CC, - 0x1E, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, { "video_cc_apb_clk", 0x48, 4, VIDEO_CC, 0x8, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, { "video_cc_at_clk", 0x48, 4, VIDEO_CC, @@ -766,6 +777,12 @@ static struct clk_debug_mux gcc_debug_mux = { 0x4, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, { "video_cc_venus_ctl_core_clk", 0x48, 4, VIDEO_CC, 0x1, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "l3_clk", 0xD6, 4, CPU, + 0x46, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "pwrcl_clk", 0xD6, 4, CPU, + 0x44, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "perfcl_clk", 0xD6, 4, CPU, + 0x45, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, ), .hw.init = &(struct clk_init_data){ .name = "gcc_debug_mux", @@ -862,6 +879,16 @@ static int clk_debug_845_probe(struct platform_device *pdev) } } + if (of_get_property(pdev->dev.of_node, "qcom,cpucc", NULL)) { + gcc_debug_mux.regmap[CPU] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,cpucc"); + if (IS_ERR(gcc_debug_mux.regmap[CPU])) { + pr_err("Failed to map qcom,cpucc\n"); + return PTR_ERR(gcc_debug_mux.regmap[CPU]); + } + } + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index 3b56fa155529aba23ee591303deeb136f2eca68f..d4f27d79f638a3962123c082c80840e65f528e1b 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -38,8 +40,6 @@ #define DISP_CC_MISC_CMD 0x8000 #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } -#define F_SLEW(f, s, h, m, n, src_freq) { (f), (s), (2 * (h) - 1), (m), (n), \ - (src_freq) } static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); @@ -80,8 +80,8 @@ static const struct parent_map disp_cc_parent_map_1[] = { static const char * const disp_cc_parent_names_1[] = { "bi_tcxo", - "dp_phy_pll_link_clk", - "dp_phy_pll_vco_div_clk", + "dp_link_clk_divsel_ten", + "dp_vco_divided_clk_src_mux", "core_bi_pll_test_se", }; @@ -126,13 +126,18 @@ static const char * const disp_cc_parent_names_4[] = { }; static struct pll_vco fabia_vco[] = { - { 250000000, 2000000000, 0 }, + { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, }; static const struct pll_config disp_cc_pll0_config = { + .l = 0x15, + .frac = 0x7c00, +}; + +static const struct pll_config disp_cc_pll0_config_v2 = { .l = 0x2c, - .frac = 0xcaab, + .frac = 0xcaaa, }; static struct clk_alpha_pll disp_cc_pll0 = { @@ -217,12 +222,11 @@ static struct clk_rcg2 disp_cc_mdss_dp_aux_clk_src = { }, }; -/* Need to get the exact frequencies that are supported */ static const struct freq_tbl ftbl_disp_cc_mdss_dp_crypto_clk_src[] = { - F( 108000000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), - F( 180000000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), - F( 360000000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), - F( 540000000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 108000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 180000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 360000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 540000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), { } }; @@ -236,23 +240,22 @@ static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { .name = "disp_cc_mdss_dp_crypto_clk_src", .parent_names = disp_cc_parent_names_1, .num_parents = 4, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_rcg2_ops, VDD_CX_FMAX_MAP5( - MIN, 12800000, - LOWER, 108000000, - LOW, 180000000, - LOW_L1, 360000000, - NOMINAL, 540000000), + MIN, 12800, + LOWER, 108000, + LOW, 180000, + LOW_L1, 360000, + NOMINAL, 540000), }, }; -/* Need to get the exact frequencies that are supported */ static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { - F_SLEW( 162000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0, 324000000), - F_SLEW( 270000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0, 540000000), - F_SLEW( 540000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0, 1080000000), - F_SLEW( 810000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0, 1620000000), + F( 162000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F( 270000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F( 540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F( 810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), { } }; @@ -269,11 +272,11 @@ static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_rcg2_ops, VDD_CX_FMAX_MAP5( - MIN, 19200000, - LOWER, 162000000, - LOW, 270000000, - LOW_L1, 540000000, - NOMINAL, 810000000), + MIN, 19200, + LOWER, 162000, + LOW, 270000, + LOW_L1, 540000, + NOMINAL, 810000), }, }; @@ -284,17 +287,15 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel1_clk_src = { .parent_map = disp_cc_parent_map_1, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_dp_pixel1_clk_src", - .parent_names = (const char *[]){ - "dp_phy_pll_vco_div_clk", - }, - .num_parents = 1, + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_dp_ops, VDD_CX_FMAX_MAP4( - MIN, 19200000, - LOWER, 202500000, - LOW, 296735905, - LOW_L1, 675000000), + MIN, 19200, + LOWER, 202500, + LOW, 296735, + LOW_L1, 675000), }, }; @@ -305,17 +306,15 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel_clk_src = { .parent_map = disp_cc_parent_map_1, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_dp_pixel_clk_src", - .parent_names = (const char *[]){ - "dp_phy_pll_vco_div_clk", - }, - .num_parents = 1, + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_dp_ops, VDD_CX_FMAX_MAP4( - MIN, 19200000, - LOWER, 202500000, - LOW, 296735905, - LOW_L1, 675000000), + MIN, 19200, + LOWER, 202500, + LOW, 296735, + LOW_L1, 675000), }, }; @@ -371,6 +370,33 @@ static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { { } }; +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm670[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(286666667, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { .cmd_rcgr = 0x2088, .mnd_width = 0, @@ -440,6 +466,15 @@ static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = { { } }; +static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + static struct clk_rcg2 disp_cc_mdss_rot_clk_src = { .cmd_rcgr = 0x20a0, .mnd_width = 0, @@ -664,23 +699,7 @@ static struct clk_branch disp_cc_mdss_dp_link_clk = { }, }; -static struct clk_regmap_div disp_cc_mdss_dp_link_div_clk_src = { - .reg = 0x2150, - .shift = 0, - .width = 2, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "disp_cc_mdss_dp_link_div_clk_src", - .parent_names = (const char *[]){ - "disp_cc_mdss_dp_link_clk_src", - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_div_ops, - }, - }, -}; - +/* reset state of disp_cc_mdss_dp_link_div_clk_src divider is 0x3 (div 4) */ static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { .halt_reg = 0x2044, .halt_check = BRANCH_HALT, @@ -690,10 +709,10 @@ static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { .hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_dp_link_intf_clk", .parent_names = (const char *[]){ - "disp_cc_mdss_dp_link_div_clk_src", + "disp_cc_mdss_dp_link_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, @@ -955,8 +974,6 @@ static struct clk_regmap *disp_cc_sdm845_clocks[] = { &disp_cc_mdss_dp_crypto_clk_src.clkr, [DISP_CC_MDSS_DP_LINK_CLK] = &disp_cc_mdss_dp_link_clk.clkr, [DISP_CC_MDSS_DP_LINK_CLK_SRC] = &disp_cc_mdss_dp_link_clk_src.clkr, - [DISP_CC_MDSS_DP_LINK_DIV_CLK_SRC] = - &disp_cc_mdss_dp_link_div_clk_src.clkr, [DISP_CC_MDSS_DP_LINK_INTF_CLK] = &disp_cc_mdss_dp_link_intf_clk.clkr, [DISP_CC_MDSS_DP_PIXEL1_CLK] = &disp_cc_mdss_dp_pixel1_clk.clkr, [DISP_CC_MDSS_DP_PIXEL1_CLK_SRC] = @@ -987,8 +1004,6 @@ static struct clk_regmap *disp_cc_sdm845_clocks[] = { }; static const struct qcom_reset_map disp_cc_sdm845_resets[] = { - [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, - [DISP_CC_MDSS_GCC_CLOCKS_BCR] = { 0x4000 }, [DISP_CC_MDSS_RSCC_BCR] = { 0x5000 }, }; @@ -1010,10 +1025,92 @@ static const struct qcom_cc_desc disp_cc_sdm845_desc = { static const struct of_device_id disp_cc_sdm845_match_table[] = { { .compatible = "qcom,dispcc-sdm845" }, + { .compatible = "qcom,dispcc-sdm845-v2" }, + { .compatible = "qcom,dispcc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table); +static void disp_cc_sdm845_fixup_sdm845v2(struct regmap *regmap) +{ + clk_fabia_pll_configure(&disp_cc_pll0, regmap, + &disp_cc_pll0_config_v2); + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 180000000; + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 275000000; + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 328580000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 180000000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 275000000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 328580000; + disp_cc_mdss_dp_pixel1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 337500; + disp_cc_mdss_dp_pixel_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 337500; + disp_cc_mdss_mdp_clk_src.freq_tbl = + ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2; + disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 171428571; + disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 344000000; + disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 430000000; + disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 280000000; + disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 430000000; + disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 430000000; + disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 280000000; + disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 430000000; + disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 430000000; + disp_cc_mdss_rot_clk_src.freq_tbl = + ftbl_disp_cc_mdss_rot_clk_src_sdm845_v2; + disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 171428571; + disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 344000000; + disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 430000000; +} + +static void disp_cc_sdm845_fixup_sdm670(struct regmap *regmap) +{ + disp_cc_sdm845_fixup_sdm845v2(regmap); + + disp_cc_mdss_mdp_clk_src.freq_tbl = + ftbl_disp_cc_mdss_mdp_clk_src_sdm670; + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 358000000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 358000000; +} + +static int disp_cc_sdm845_fixup(struct platform_device *pdev, + struct regmap *regmap) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,dispcc-sdm845-v2")) + disp_cc_sdm845_fixup_sdm845v2(regmap); + else if (!strcmp(compat, "qcom,dispcc-sdm670")) + disp_cc_sdm845_fixup_sdm670(regmap); + + return 0; +} + static int disp_cc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; @@ -1038,6 +1135,10 @@ static int disp_cc_sdm845_probe(struct platform_device *pdev) /* Enable clock gating for DSI and MDP clocks */ regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x7f0, 0x7f0); + ret = disp_cc_sdm845_fixup(pdev, regmap); + if (ret) + return ret; + ret = qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap); if (ret) { dev_err(&pdev->dev, "Failed to register Display CC clocks\n"); @@ -1060,7 +1161,7 @@ static int __init disp_cc_sdm845_init(void) { return platform_driver_register(&disp_cc_sdm845_driver); } -core_initcall(disp_cc_sdm845_init); +subsys_initcall(disp_cc_sdm845_init); static void __exit disp_cc_sdm845_exit(void) { diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index b593065de8db6fdb860548c556c989c1531964cf..8ab6ce4d976f87cef48cbe11bfe1fe79aa62e1d3 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -525,10 +525,20 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { }; static const struct freq_tbl ftbl_gcc_apps_clk[] = { - F(48000000, P_XO, 1, 0, 0), + F(48000000, P_XO, 1, 0, 0), F(200000000, P_FEPLL200, 1, 0, 0), + F(384000000, P_DDRPLLAPSS, 1, 0, 0), + F(413000000, P_DDRPLLAPSS, 1, 0, 0), + F(448000000, P_DDRPLLAPSS, 1, 0, 0), + F(488000000, P_DDRPLLAPSS, 1, 0, 0), F(500000000, P_FEPLL500, 1, 0, 0), - F(626000000, P_DDRPLLAPSS, 1, 0, 0), + F(512000000, P_DDRPLLAPSS, 1, 0, 0), + F(537000000, P_DDRPLLAPSS, 1, 0, 0), + F(565000000, P_DDRPLLAPSS, 1, 0, 0), + F(597000000, P_DDRPLLAPSS, 1, 0, 0), + F(632000000, P_DDRPLLAPSS, 1, 0, 0), + F(672000000, P_DDRPLLAPSS, 1, 0, 0), + F(716000000, P_DDRPLLAPSS, 1, 0, 0), { } }; diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 678dd10111e57497987ae8e268676bb2d1f27536..555b8bd603e97baedc673e590a47decd073a37fb 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -34,9 +36,6 @@ #include "clk-alpha-pll.h" #include "vdd-level-sdm845.h" -#define GCC_APCS_CLOCK_SLEEP_ENA_VOTE_OFFSET 0x52008 -#define CPUSS_AHB_CLK_SLEEP_ENA BIT(21) -#define SYS_NOC_CPUSS_AHB_CLK_SLEEP_ENA BIT(0) #define GCC_MMSS_MISC 0x09FFC #define GCC_GPU_MISC 0x71028 @@ -51,7 +50,9 @@ enum { P_CORE_BI_PLL_TEST_SE, P_GPLL0_OUT_EVEN, P_GPLL0_OUT_MAIN, + P_GPLL1_OUT_MAIN, P_GPLL4_OUT_MAIN, + P_GPLL6_OUT_MAIN, P_SLEEP_CLK, }; @@ -158,6 +159,58 @@ static const char * const gcc_parent_names_7[] = { "core_bi_pll_test_se", }; +static const char * const gcc_parent_names_8[] = { + "bi_tcxo_ao", + "gpll0", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL1_OUT_MAIN, 4 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_9[] = { + "bi_tcxo", + "gpll0", + "gpll1", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_MAIN, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_10[] = { + "bi_tcxo", + "gpll0", + "gpll4", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL6_OUT_MAIN, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_11[] = { + "bi_tcxo", + "gpll0", + "gpll6", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + static struct clk_dummy measure_only_snoc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ @@ -191,7 +244,7 @@ static struct clk_dummy measure_only_ipa_2x_clk = { }; static struct pll_vco fabia_vco[] = { - { 250000000, 2000000000, 0 }, + { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, }; @@ -217,6 +270,28 @@ static struct clk_alpha_pll gpll0 = { }, }; +static struct clk_alpha_pll gpll4 = { + .offset = 0x76000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_fixed_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + static const struct clk_div_table post_div_table_fabia_even[] = { { 0x0, 1 }, { 0x1, 2 }, @@ -239,16 +314,16 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = { }, }; -static struct clk_alpha_pll gpll1 = { - .offset = 0x1000, +static struct clk_alpha_pll gpll6 = { + .offset = 0x13000, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), .type = FABIA_PLL, .clkr = { .enable_reg = 0x52000, - .enable_mask = BIT(1), + .enable_mask = BIT(6), .hw.init = &(struct clk_init_data){ - .name = "gpll1", + .name = "gpll6", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_fabia_fixed_pll_ops, @@ -290,6 +365,12 @@ static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src_sdm670[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { .cmd_rcgr = 0x4815c, .mnd_width = 0, @@ -298,16 +379,17 @@ static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_cpuss_rbcpr_clk_src", - .parent_names = gcc_parent_names_3, + .parent_names = gcc_parent_names_8, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP1( + VDD_CX_FMAX_MAP1_AO( MIN, 19200000), }, }; static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), @@ -442,6 +524,7 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { }; static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), F(19200000, P_BI_TCXO, 1, 0, 0), F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), { } @@ -467,6 +550,21 @@ static struct clk_rcg2 gcc_pdm2_clk_src = { }; static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75), + F(38400000, P_GPLL0_OUT_EVEN, 1, 16, 125), + F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75), + F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2[] = { F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), F(19200000, P_BI_TCXO, 1, 0, 0), @@ -477,6 +575,11 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15), F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25), F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + F(102400000, P_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GPLL0_OUT_EVEN, 2.5, 0, 0), + F(128000000, P_GPLL0_OUT_MAIN, 1, 16, 75), { } }; @@ -800,13 +903,75 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(75000000, P_GPLL0_OUT_EVEN, 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), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x26010, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 75000000, + LOW, 150000000, + NOMINAL, 300000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, P_BI_TCXO, 16, 3, 25), + F(400000, P_BI_TCXO, 12, 1, 4), + F(20000000, P_GPLL0_OUT_EVEN, 5, 1, 3), + F(25000000, P_GPLL0_OUT_EVEN, 6, 1, 2), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0), + F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0x26028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk_src", + .parent_names = gcc_parent_names_11, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 384000000), + }, +}; + static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), F(19200000, P_BI_TCXO, 1, 0, 0), - F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), - F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), - F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(201500000, P_GPLL4_OUT_MAIN, 4, 0, 0), { } }; @@ -814,12 +979,12 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .cmd_rcgr = 0x1400c, .mnd_width = 8, .hid_width = 5, - .parent_map = gcc_parent_map_5, + .parent_map = gcc_parent_map_10, .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_sdcc2_apps_clk_src", - .parent_names = gcc_parent_names_5, + .parent_names = gcc_parent_names_10, .num_parents = 5, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -827,12 +992,13 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { MIN, 9600000, LOWER, 19200000, LOW, 100000000, - LOW_L1, 200000000), + LOW_L1, 201500000), }, }; static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), F(19200000, P_BI_TCXO, 1, 0, 0), F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), @@ -840,17 +1006,28 @@ static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src_sdm670[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(33333333, P_GPLL0_OUT_EVEN, 9, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { .cmd_rcgr = 0x1600c, .mnd_width = 8, .hid_width = 5, - .parent_map = gcc_parent_map_3, + .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_sdcc4_apps_clk_src", - .parent_names = gcc_parent_names_3, - .num_parents = 3, + .parent_names = gcc_parent_names_0, + .num_parents = 4, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, VDD_CX_FMAX_MAP4( @@ -883,13 +1060,30 @@ static struct clk_rcg2 gcc_tsif_ref_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src[] = { + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2[] = { + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + static struct clk_rcg2 gcc_ufs_card_axi_clk_src = { .cmd_rcgr = 0x7501c, .mnd_width = 8, .hid_width = 5, .parent_map = gcc_parent_map_0, - .freq_tbl = ftbl_gcc_gp1_clk_src, - .enable_safe_config = true, + .freq_tbl = ftbl_gcc_ufs_card_axi_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_axi_clk_src", .parent_names = gcc_parent_names_0, @@ -917,7 +1111,7 @@ static struct clk_rcg2 gcc_ufs_card_ice_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, - .enable_safe_config = true, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_ice_core_clk_src", .parent_names = gcc_parent_names_0, @@ -937,6 +1131,7 @@ static struct clk_rcg2 gcc_ufs_card_phy_aux_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_4, .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_phy_aux_clk_src", .parent_names = gcc_parent_names_4, @@ -961,7 +1156,7 @@ static struct clk_rcg2 gcc_ufs_card_unipro_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_unipro_core_clk_src, - .enable_safe_config = true, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_unipro_core_clk_src", .parent_names = gcc_parent_names_0, @@ -990,7 +1185,7 @@ static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, - .enable_safe_config = true, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_axi_clk_src", .parent_names = gcc_parent_names_0, @@ -1011,7 +1206,7 @@ static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, - .enable_safe_config = true, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_ice_core_clk_src", .parent_names = gcc_parent_names_0, @@ -1031,6 +1226,7 @@ static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_4, .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_phy_aux_clk_src", .parent_names = gcc_parent_names_4, @@ -1048,6 +1244,7 @@ static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_unipro_core_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_unipro_core_clk_src", .parent_names = gcc_parent_names_0, @@ -1093,6 +1290,7 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { }; static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(20000000, P_GPLL0_OUT_EVEN, 15, 0, 0), F(40000000, P_GPLL0_OUT_EVEN, 7.5, 0, 0), F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), @@ -1194,6 +1392,49 @@ static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = { }, }; +static struct clk_rcg2 gcc_vs_ctrl_clk_src = { + .cmd_rcgr = 0x7a030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_vs_ctrl_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), + }, +}; + +static const struct freq_tbl ftbl_gcc_vsensor_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(600000000, P_GPLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_vsensor_clk_src = { + .cmd_rcgr = 0x7a018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_vsensor_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_vsensor_clk_src", + .parent_names = gcc_parent_names_9, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOW, 300000000, + LOW_L1, 600000000), + }, +}; + static struct clk_branch gcc_aggre_noc_pcie_tbu_clk = { .halt_reg = 0x90014, .halt_check = BRANCH_HALT, @@ -1210,6 +1451,8 @@ static struct clk_branch gcc_aggre_noc_pcie_tbu_clk = { static struct clk_branch gcc_aggre_ufs_card_axi_clk = { .halt_reg = 0x82028, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x82028, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x82028, .enable_mask = BIT(0), @@ -1225,9 +1468,28 @@ static struct clk_branch gcc_aggre_ufs_card_axi_clk = { }, }; +static struct clk_branch gcc_aggre_ufs_card_axi_hw_ctl_clk = { + .halt_reg = 0x82028, + .clkr = { + .enable_reg = 0x82028, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_card_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_aggre_ufs_card_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { .halt_reg = 0x82024, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x82024, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x82024, .enable_mask = BIT(0), @@ -1243,6 +1505,23 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { }, }; +static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x82024, + .clkr = { + .enable_reg = 0x82024, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_aggre_ufs_phy_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { .halt_reg = 0x8201c, .halt_check = BRANCH_HALT, @@ -1279,9 +1558,29 @@ static struct clk_branch gcc_aggre_usb3_sec_axi_clk = { }, }; +static struct clk_branch gcc_apc_vs_clk = { + .halt_reg = 0x7a050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apc_vs_clk", + .parent_names = (const char *[]){ + "gcc_vsensor_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_boot_rom_ahb_clk = { .halt_reg = 0x38004, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(10), @@ -1295,11 +1594,14 @@ static struct clk_branch gcc_boot_rom_ahb_clk = { static struct clk_branch gcc_camera_ahb_clk = { .halt_reg = 0xb008, .halt_check = BRANCH_HALT, + .hwcg_reg = 0xb008, + .hwcg_bit = 1, .clkr = { .enable_reg = 0xb008, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_camera_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1326,6 +1628,7 @@ static struct clk_branch gcc_camera_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_camera_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1334,6 +1637,8 @@ static struct clk_branch gcc_camera_xo_clk = { static struct clk_branch gcc_ce1_ahb_clk = { .halt_reg = 0x4100c, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4100c, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(3), @@ -1418,7 +1723,7 @@ static struct clk_branch gcc_cpuss_ahb_clk = { "gcc_cpuss_ahb_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1432,6 +1737,7 @@ static struct clk_branch gcc_cpuss_dvm_bus_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_cpuss_dvm_bus_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1440,11 +1746,14 @@ static struct clk_branch gcc_cpuss_dvm_bus_clk = { static struct clk_branch gcc_cpuss_gnoc_clk = { .halt_reg = 0x48004, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x48004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(22), .hw.init = &(struct clk_init_data){ .name = "gcc_cpuss_gnoc_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1484,11 +1793,14 @@ static struct clk_branch gcc_ddrss_gpu_axi_clk = { static struct clk_branch gcc_disp_ahb_clk = { .halt_reg = 0xb00c, .halt_check = BRANCH_HALT, + .hwcg_reg = 0xb00c, + .hwcg_bit = 1, .clkr = { .enable_reg = 0xb00c, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_disp_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1549,6 +1861,7 @@ static struct clk_branch gcc_disp_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_disp_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1611,11 +1924,14 @@ static struct clk_branch gcc_gp3_clk = { static struct clk_branch gcc_gpu_cfg_ahb_clk = { .halt_reg = 0x71004, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x71004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x71004, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_gpu_cfg_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1655,6 +1971,19 @@ static struct clk_gate2 gcc_gpu_gpll0_div_clk_src = { }, }; +static struct clk_branch gcc_gpu_iref_clk = { + .halt_reg = 0x8c010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_iref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_gpu_memnoc_gfx_clk = { .halt_reg = 0x7100c, .halt_check = BRANCH_VOTED, @@ -1681,6 +2010,24 @@ static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { }, }; +static struct clk_branch gcc_gpu_vs_clk = { + .halt_reg = 0x7a04c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_vs_clk", + .parent_names = (const char *[]){ + "gcc_vsensor_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_mss_axis2_clk = { .halt_reg = 0x8a008, .halt_check = BRANCH_HALT, @@ -1697,6 +2044,8 @@ static struct clk_branch gcc_mss_axis2_clk = { static struct clk_branch gcc_mss_cfg_ahb_clk = { .halt_reg = 0x8a000, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x8a000, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x8a000, .enable_mask = BIT(0), @@ -1722,6 +2071,8 @@ static struct clk_gate2 gcc_mss_gpll0_div_clk_src = { static struct clk_branch gcc_mss_mfab_axis_clk = { .halt_reg = 0x8a004, .halt_check = BRANCH_VOTED, + .hwcg_reg = 0x8a004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x8a004, .enable_mask = BIT(0), @@ -1758,6 +2109,24 @@ static struct clk_branch gcc_mss_snoc_axi_clk = { }, }; +static struct clk_branch gcc_mss_vs_clk = { + .halt_reg = 0x7a048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mss_vs_clk", + .parent_names = (const char *[]){ + "gcc_vsensor_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_pcie_0_aux_clk = { .halt_reg = 0x6b01c, .halt_check = BRANCH_HALT_VOTED, @@ -1779,6 +2148,8 @@ static struct clk_branch gcc_pcie_0_aux_clk = { static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { .halt_reg = 0x6b018, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b018, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x5200c, .enable_mask = BIT(2), @@ -1815,14 +2186,15 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = { }, }; -static struct clk_gate2 gcc_pcie_0_pipe_clk = { - .udelay = 500, +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x6b020, + .halt_check = BRANCH_VOTED, .clkr = { .enable_reg = 0x5200c, .enable_mask = BIT(4), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_0_pipe_clk", - .ops = &clk_gate2_ops, + .ops = &clk_branch2_ops, }, }, }; @@ -1830,6 +2202,8 @@ static struct clk_gate2 gcc_pcie_0_pipe_clk = { static struct clk_branch gcc_pcie_0_slv_axi_clk = { .halt_reg = 0x6b010, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b010, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x5200c, .enable_mask = BIT(0), @@ -1874,6 +2248,8 @@ static struct clk_branch gcc_pcie_1_aux_clk = { static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { .halt_reg = 0x8d018, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d018, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(28), @@ -1910,14 +2286,15 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = { }, }; -static struct clk_gate2 gcc_pcie_1_pipe_clk = { - .udelay = 500, +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x8d020, + .halt_check = BRANCH_VOTED, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(30), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_1_pipe_clk", - .ops = &clk_gate2_ops, + .ops = &clk_branch2_ops, }, }, }; @@ -1925,6 +2302,8 @@ static struct clk_gate2 gcc_pcie_1_pipe_clk = { static struct clk_branch gcc_pcie_1_slv_axi_clk = { .halt_reg = 0x8d010, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d010, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(26), @@ -2005,6 +2384,8 @@ static struct clk_branch gcc_pdm2_clk = { static struct clk_branch gcc_pdm_ahb_clk = { .halt_reg = 0x33004, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x33004, .enable_mask = BIT(0), @@ -2031,6 +2412,8 @@ static struct clk_branch gcc_pdm_xo4_clk = { static struct clk_branch gcc_prng_ahb_clk = { .halt_reg = 0x34004, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x34004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(13), @@ -2044,6 +2427,8 @@ static struct clk_branch gcc_prng_ahb_clk = { static struct clk_branch gcc_qmip_camera_ahb_clk = { .halt_reg = 0xb014, .halt_check = BRANCH_HALT, + .hwcg_reg = 0xb014, + .hwcg_bit = 1, .clkr = { .enable_reg = 0xb014, .enable_mask = BIT(0), @@ -2057,6 +2442,8 @@ static struct clk_branch gcc_qmip_camera_ahb_clk = { static struct clk_branch gcc_qmip_disp_ahb_clk = { .halt_reg = 0xb018, .halt_check = BRANCH_HALT, + .hwcg_reg = 0xb018, + .hwcg_bit = 1, .clkr = { .enable_reg = 0xb018, .enable_mask = BIT(0), @@ -2070,6 +2457,8 @@ static struct clk_branch gcc_qmip_disp_ahb_clk = { static struct clk_branch gcc_qmip_video_ahb_clk = { .halt_reg = 0xb010, .halt_check = BRANCH_HALT, + .hwcg_reg = 0xb010, + .hwcg_bit = 1, .clkr = { .enable_reg = 0xb010, .enable_mask = BIT(0), @@ -2384,6 +2773,8 @@ static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = { static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = { .halt_reg = 0x17008, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x17008, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x5200c, .enable_mask = BIT(7), @@ -2410,6 +2801,8 @@ static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { .halt_reg = 0x18010, .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x18010, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x5200c, .enable_mask = BIT(21), @@ -2420,6 +2813,55 @@ static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { }, }; +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x2600c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk", + .parent_names = (const char *[]){ + "gcc_sdcc1_ice_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x26004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]){ + "gcc_sdcc1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_sdcc2_ahb_clk = { .halt_reg = 0x14008, .halt_check = BRANCH_HALT, @@ -2494,7 +2936,7 @@ static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = { "gcc_cpuss_ahb_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2547,6 +2989,8 @@ static struct clk_branch gcc_tsif_ref_clk = { static struct clk_branch gcc_ufs_card_ahb_clk = { .halt_reg = 0x75010, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x75010, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x75010, .enable_mask = BIT(0), @@ -2560,6 +3004,8 @@ static struct clk_branch gcc_ufs_card_ahb_clk = { static struct clk_branch gcc_ufs_card_axi_clk = { .halt_reg = 0x7500c, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7500c, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x7500c, .enable_mask = BIT(0), @@ -2575,6 +3021,23 @@ static struct clk_branch gcc_ufs_card_axi_clk = { }, }; +static struct clk_branch gcc_ufs_card_axi_hw_ctl_clk = { + .halt_reg = 0x7500c, + .clkr = { + .enable_reg = 0x7500c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_card_clkref_clk = { .halt_reg = 0x8c004, .halt_check = BRANCH_HALT, @@ -2591,6 +3054,8 @@ static struct clk_branch gcc_ufs_card_clkref_clk = { static struct clk_branch gcc_ufs_card_ice_core_clk = { .halt_reg = 0x75058, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x75058, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x75058, .enable_mask = BIT(0), @@ -2606,9 +3071,28 @@ static struct clk_branch gcc_ufs_card_ice_core_clk = { }, }; +static struct clk_branch gcc_ufs_card_ice_core_hw_ctl_clk = { + .halt_reg = 0x75058, + .clkr = { + .enable_reg = 0x75058, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_ice_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_ice_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_card_phy_aux_clk = { .halt_reg = 0x7508c, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7508c, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x7508c, .enable_mask = BIT(0), @@ -2624,6 +3108,23 @@ static struct clk_branch gcc_ufs_card_phy_aux_clk = { }, }; +static struct clk_branch gcc_ufs_card_phy_aux_hw_ctl_clk = { + .halt_reg = 0x7508c, + .clkr = { + .enable_reg = 0x7508c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_phy_aux_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_phy_aux_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_gate2 gcc_ufs_card_rx_symbol_0_clk = { .udelay = 500, .clkr = { @@ -2663,6 +3164,8 @@ static struct clk_gate2 gcc_ufs_card_tx_symbol_0_clk = { static struct clk_branch gcc_ufs_card_unipro_core_clk = { .halt_reg = 0x75054, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x75054, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x75054, .enable_mask = BIT(0), @@ -2678,6 +3181,23 @@ static struct clk_branch gcc_ufs_card_unipro_core_clk = { }, }; +static struct clk_branch gcc_ufs_card_unipro_core_hw_ctl_clk = { + .halt_reg = 0x75054, + .clkr = { + .enable_reg = 0x75054, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_unipro_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_unipro_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_mem_clkref_clk = { .halt_reg = 0x8c000, .halt_check = BRANCH_HALT, @@ -2694,6 +3214,8 @@ static struct clk_branch gcc_ufs_mem_clkref_clk = { static struct clk_branch gcc_ufs_phy_ahb_clk = { .halt_reg = 0x77010, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77010, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x77010, .enable_mask = BIT(0), @@ -2707,6 +3229,8 @@ static struct clk_branch gcc_ufs_phy_ahb_clk = { static struct clk_branch gcc_ufs_phy_axi_clk = { .halt_reg = 0x7700c, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7700c, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x7700c, .enable_mask = BIT(0), @@ -2722,9 +3246,28 @@ static struct clk_branch gcc_ufs_phy_axi_clk = { }, }; +static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x7700c, + .clkr = { + .enable_reg = 0x7700c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_phy_ice_core_clk = { .halt_reg = 0x77058, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77058, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x77058, .enable_mask = BIT(0), @@ -2740,9 +3283,28 @@ static struct clk_branch gcc_ufs_phy_ice_core_clk = { }, }; +static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = { + .halt_reg = 0x77058, + .clkr = { + .enable_reg = 0x77058, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_ice_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_phy_phy_aux_clk = { .halt_reg = 0x7708c, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7708c, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x7708c, .enable_mask = BIT(0), @@ -2758,6 +3320,23 @@ static struct clk_branch gcc_ufs_phy_phy_aux_clk = { }, }; +static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = { + .halt_reg = 0x7708c, + .clkr = { + .enable_reg = 0x7708c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_phy_aux_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_gate2 gcc_ufs_phy_rx_symbol_0_clk = { .udelay = 500, .clkr = { @@ -2797,6 +3376,8 @@ static struct clk_gate2 gcc_ufs_phy_tx_symbol_0_clk = { static struct clk_branch gcc_ufs_phy_unipro_core_clk = { .halt_reg = 0x77054, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77054, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x77054, .enable_mask = BIT(0), @@ -2812,6 +3393,23 @@ static struct clk_branch gcc_ufs_phy_unipro_core_clk = { }, }; +static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = { + .halt_reg = 0x77054, + .clkr = { + .enable_reg = 0x77054, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_unipro_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_usb30_prim_master_clk = { .halt_reg = 0xf00c, .halt_check = BRANCH_HALT, @@ -3035,6 +3633,8 @@ static struct clk_gate2 gcc_usb3_sec_phy_pipe_clk = { static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { .halt_reg = 0x6a004, .halt_check = BRANCH_HALT, + .hwcg_reg = 0x6a004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0x6a004, .enable_mask = BIT(0), @@ -3045,14 +3645,71 @@ static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { }, }; +static struct clk_branch gcc_vdda_vs_clk = { + .halt_reg = 0x7a00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vdda_vs_clk", + .parent_names = (const char *[]){ + "gcc_vsensor_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vddcx_vs_clk = { + .halt_reg = 0x7a004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vddcx_vs_clk", + .parent_names = (const char *[]){ + "gcc_vsensor_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vddmx_vs_clk = { + .halt_reg = 0x7a008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vddmx_vs_clk", + .parent_names = (const char *[]){ + "gcc_vsensor_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_video_ahb_clk = { .halt_reg = 0xb004, .halt_check = BRANCH_HALT, + .hwcg_reg = 0xb004, + .hwcg_bit = 1, .clkr = { .enable_reg = 0xb004, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_video_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3079,6 +3736,40 @@ static struct clk_branch gcc_video_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_video_xo_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vs_ctrl_ahb_clk = { + .halt_reg = 0x7a014, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7a014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7a014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vs_ctrl_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vs_ctrl_clk = { + .halt_reg = 0x7a010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vs_ctrl_clk", + .parent_names = (const char *[]){ + "gcc_vs_ctrl_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -3094,9 +3785,14 @@ struct clk_hw *gcc_sdm845_hws[] = { static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK] = + &gcc_aggre_ufs_card_axi_hw_ctl_clk.clkr, [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = + &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr, [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr, + [GCC_APC_VS_CLK] = &gcc_apc_vs_clk.clkr, [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, [GCC_CAMERA_AHB_CLK] = &gcc_camera_ahb_clk.clkr, [GCC_CAMERA_AXI_CLK] = &gcc_camera_axi_clk.clkr, @@ -3127,14 +3823,17 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr, [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_GPU_IREF_CLK] = &gcc_gpu_iref_clk.clkr, [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr, [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, + [GCC_GPU_VS_CLK] = &gcc_gpu_vs_clk.clkr, [GCC_MSS_AXIS2_CLK] = &gcc_mss_axis2_clk.clkr, [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr, [GCC_MSS_GPLL0_DIV_CLK_SRC] = &gcc_mss_gpll0_div_clk_src.clkr, [GCC_MSS_MFAB_AXIS_CLK] = &gcc_mss_mfab_axis_clk.clkr, [GCC_MSS_Q6_MEMNOC_AXI_CLK] = &gcc_mss_q6_memnoc_axi_clk.clkr, [GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr, + [GCC_MSS_VS_CLK] = &gcc_mss_vs_clk.clkr, [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, @@ -3212,30 +3911,43 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_TSIF_REF_CLK_SRC] = &gcc_tsif_ref_clk_src.clkr, [GCC_UFS_CARD_AHB_CLK] = &gcc_ufs_card_ahb_clk.clkr, [GCC_UFS_CARD_AXI_CLK] = &gcc_ufs_card_axi_clk.clkr, + [GCC_UFS_CARD_AXI_HW_CTL_CLK] = &gcc_ufs_card_axi_hw_ctl_clk.clkr, [GCC_UFS_CARD_AXI_CLK_SRC] = &gcc_ufs_card_axi_clk_src.clkr, [GCC_UFS_CARD_CLKREF_CLK] = &gcc_ufs_card_clkref_clk.clkr, [GCC_UFS_CARD_ICE_CORE_CLK] = &gcc_ufs_card_ice_core_clk.clkr, + [GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK] = + &gcc_ufs_card_ice_core_hw_ctl_clk.clkr, [GCC_UFS_CARD_ICE_CORE_CLK_SRC] = &gcc_ufs_card_ice_core_clk_src.clkr, [GCC_UFS_CARD_PHY_AUX_CLK] = &gcc_ufs_card_phy_aux_clk.clkr, + [GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] = + &gcc_ufs_card_phy_aux_hw_ctl_clk.clkr, [GCC_UFS_CARD_PHY_AUX_CLK_SRC] = &gcc_ufs_card_phy_aux_clk_src.clkr, [GCC_UFS_CARD_RX_SYMBOL_0_CLK] = &gcc_ufs_card_rx_symbol_0_clk.clkr, [GCC_UFS_CARD_RX_SYMBOL_1_CLK] = &gcc_ufs_card_rx_symbol_1_clk.clkr, [GCC_UFS_CARD_TX_SYMBOL_0_CLK] = &gcc_ufs_card_tx_symbol_0_clk.clkr, [GCC_UFS_CARD_UNIPRO_CORE_CLK] = &gcc_ufs_card_unipro_core_clk.clkr, + [GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK] = + &gcc_ufs_card_unipro_core_hw_ctl_clk.clkr, [GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_card_unipro_core_clk_src.clkr, [GCC_UFS_MEM_CLKREF_CLK] = &gcc_ufs_mem_clkref_clk.clkr, [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr, [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = + &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr, [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr, [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = + &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr, [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, @@ -3261,16 +3973,28 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr, [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr, [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr, + [GCC_VDDA_VS_CLK] = &gcc_vdda_vs_clk.clkr, + [GCC_VDDCX_VS_CLK] = &gcc_vddcx_vs_clk.clkr, + [GCC_VDDMX_VS_CLK] = &gcc_vddmx_vs_clk.clkr, [GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr, [GCC_VIDEO_AXI_CLK] = &gcc_video_axi_clk.clkr, [GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr, + [GCC_VS_CTRL_AHB_CLK] = &gcc_vs_ctrl_ahb_clk.clkr, + [GCC_VS_CTRL_CLK] = &gcc_vs_ctrl_clk.clkr, + [GCC_VS_CTRL_CLK_SRC] = &gcc_vs_ctrl_clk_src.clkr, + [GCC_VSENSOR_CLK_SRC] = &gcc_vsensor_clk_src.clkr, [GPLL0] = &gpll0.clkr, [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, - [GPLL1] = &gpll1.clkr, + [GPLL4] = &gpll4.clkr, + [GCC_SDCC1_AHB_CLK] = NULL, + [GCC_SDCC1_APPS_CLK] = NULL, + [GCC_SDCC1_ICE_CORE_CLK] = NULL, + [GCC_SDCC1_APPS_CLK_SRC] = NULL, + [GCC_SDCC1_ICE_CORE_CLK_SRC] = NULL, + [GPLL6] = NULL, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { - [GCC_GPU_BCR] = { 0x71000 }, [GCC_MMSS_BCR] = { 0xb000 }, [GCC_PCIE_0_BCR] = { 0x6b000 }, [GCC_PCIE_1_BCR] = { 0x8d000 }, @@ -3297,6 +4021,32 @@ static const struct qcom_reset_map gcc_sdm845_resets[] = { [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_SDCC1_BCR] = { 0x26000 }, +}; + +/* List of RCG clocks and corresponding flags requested for DFS Mode */ +static struct clk_dfs gcc_dfs_clocks[] = { + { &gcc_qupv3_wrap0_s0_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s1_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s2_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s3_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s4_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s5_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s6_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s7_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s0_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s1_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s2_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s3_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s4_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s5_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s6_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s7_clk_src, DFS_ENABLE_RCG }, +}; + +static const struct qcom_cc_dfs_desc gcc_sdm845_dfs_desc = { + .clks = gcc_dfs_clocks, + .num_clks = ARRAY_SIZE(gcc_dfs_clocks), }; static const struct regmap_config gcc_sdm845_regmap_config = { @@ -3317,10 +4067,216 @@ static const struct qcom_cc_desc gcc_sdm845_desc = { static const struct of_device_id gcc_sdm845_match_table[] = { { .compatible = "qcom,gcc-sdm845" }, + { .compatible = "qcom,gcc-sdm845-v2" }, + { .compatible = "qcom,gcc-sdm845-v2.1" }, + { .compatible = "qcom,gcc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table); +static void gcc_sdm845_fixup_sdm845v2(void) +{ + gcc_qupv3_wrap0_s0_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s1_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s2_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s3_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s4_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s5_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s6_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s7_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s0_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s1_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s2_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s3_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s4_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s5_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s6_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s7_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_ufs_card_axi_clk_src.freq_tbl = + ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2; + gcc_ufs_card_axi_clk_src.clkr.hw.init->rate_max[VDD_CX_HIGH] = + 240000000; + gcc_ufs_phy_axi_clk_src.freq_tbl = + ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2; + gcc_vsensor_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 600000000; +} + +static void gcc_sdm845_fixup_sdm670(void) +{ + gcc_sdm845_fixup_sdm845v2(); + + gcc_sdm845_clocks[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr; + gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr; + gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK] = + &gcc_sdcc1_ice_core_clk.clkr; + gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK_SRC] = + &gcc_sdcc1_apps_clk_src.clkr; + gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK_SRC] = + &gcc_sdcc1_ice_core_clk_src.clkr; + gcc_sdm845_clocks[GPLL6] = &gpll6.clkr; + gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_AGGRE_USB3_SEC_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_AGGRE_NOC_PCIE_TBU_CLK] = NULL; + gcc_sdm845_clocks[GCC_CFG_NOC_USB3_SEC_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_CFG_AHB_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_MSTR_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_PIPE_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_SLV_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_SLV_Q2A_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_CFG_AHB_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_MSTR_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_PIPE_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_SLV_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_SLV_Q2A_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_PHY_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AHB_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AXI_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_0_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_1_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_TX_SYMBOL_0_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_PHY_RX_SYMBOL_1_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_SLEEP_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_COM_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_PIPE_CLK] = NULL; + + gcc_cpuss_rbcpr_clk_src.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src_sdm670; + gcc_cpuss_rbcpr_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 50000000; + gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 50000000; + gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 100000000; + gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 201500000; + gcc_sdcc4_apps_clk_src.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src_sdm670; + gcc_sdcc4_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 33333333; +} + +static int gcc_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,gcc-sdm845-v2") || + !strcmp(compat, "qcom,gcc-sdm845-v2.1")) + gcc_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,gcc-sdm670")) + gcc_sdm845_fixup_sdm670(); + + return 0; +} + static int gcc_sdm845_probe(struct platform_device *pdev) { struct clk *clk; @@ -3331,14 +4287,6 @@ static int gcc_sdm845_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); - /* - * Set the *_SLEEP_ENA bits to allow certain cpuss* clocks to be - * turned off by hardware during certain apps low power modes. - */ - regmap_update_bits(regmap, GCC_APCS_CLOCK_SLEEP_ENA_VOTE_OFFSET, - CPUSS_AHB_CLK_SLEEP_ENA | SYS_NOC_CPUSS_AHB_CLK_SLEEP_ENA, - CPUSS_AHB_CLK_SLEEP_ENA | SYS_NOC_CPUSS_AHB_CLK_SLEEP_ENA); - vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); if (IS_ERR(vdd_cx.regulator[0])) { if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) @@ -3355,6 +4303,10 @@ static int gcc_sdm845_probe(struct platform_device *pdev) return PTR_ERR(vdd_cx_ao.regulator[0]); } + ret = gcc_sdm845_fixup(pdev); + if (ret) + return ret; + /* Register the dummy measurement clocks */ for (i = 0; i < ARRAY_SIZE(gcc_sdm845_hws); i++) { clk = devm_clk_register(&pdev->dev, gcc_sdm845_hws[i]); @@ -3372,30 +4324,14 @@ static int gcc_sdm845_probe(struct platform_device *pdev) regmap_update_bits(regmap, GCC_MMSS_MISC, 0x3, 0x3); regmap_update_bits(regmap, GCC_GPU_MISC, 0x3, 0x3); - /* Keep these CPUSS clocks enabled always */ - clk_prepare_enable(gcc_cpuss_ahb_clk.clkr.hw.clk); - clk_prepare_enable(gcc_sys_noc_cpuss_ahb_clk.clkr.hw.clk); - clk_prepare_enable(gcc_cpuss_dvm_bus_clk.clkr.hw.clk); - clk_prepare_enable(gcc_cpuss_gnoc_clk.clkr.hw.clk); - - /* Keep the core XO clock enabled always */ - clk_prepare_enable(gcc_camera_xo_clk.clkr.hw.clk); - clk_prepare_enable(gcc_disp_xo_clk.clkr.hw.clk); - clk_prepare_enable(gcc_video_xo_clk.clkr.hw.clk); - - /* Enable for core register access */ - clk_prepare_enable(gcc_gpu_cfg_ahb_clk.clkr.hw.clk); - clk_prepare_enable(gcc_disp_ahb_clk.clkr.hw.clk); - clk_prepare_enable(gcc_camera_ahb_clk.clkr.hw.clk); - clk_prepare_enable(gcc_video_ahb_clk.clkr.hw.clk); - - /* - * TODO: - * 1. Support HW clock measurement - * 2. Support UFS clock hw_ctrl - * 3. Support mux clock interface for pcie pipe clocks - * 4. QUPv3 support - */ + /* Keep this clock on all the times except on SDM845 v2.1 */ + if (!of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdm845-v2.1")) + clk_prepare_enable(gcc_aggre_noc_pcie_tbu_clk.clkr.hw.clk); + + /* DFS clock registration */ + ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc); + if (ret) + dev_err(&pdev->dev, "Failed to register with DFS!\n"); dev_info(&pdev->dev, "Registered GCC clocks\n"); return ret; @@ -3413,7 +4349,7 @@ static int __init gcc_sdm845_init(void) { return platform_driver_register(&gcc_sdm845_driver); } -core_initcall(gcc_sdm845_init); +subsys_initcall(gcc_sdm845_init); static void __exit gcc_sdm845_exit(void) { diff --git a/drivers/clk/qcom/gcc-sdxpoorwills.c b/drivers/clk/qcom/gcc-sdxpoorwills.c new file mode 100644 index 0000000000000000000000000000000000000000..c6e8faa6f1fc4dc17097c93dc1641b04c0250122 --- /dev/null +++ b/drivers/clk/qcom/gcc-sdxpoorwills.c @@ -0,0 +1,1905 @@ +/* + * Copyright (c) 2017-2018, 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) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" + +#include "clk-alpha-pll.h" +#include "vdd-level-sdm845.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_EVEN, + P_GPLL0_OUT_MAIN, + P_GPLL4_OUT_EVEN, + P_SLEEP_CLK, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_0[] = { + "bi_tcxo", + "gpll0", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_1[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_2[] = { + "bi_tcxo", + "gpll0", + "core_pi_sleep_clk", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_3[] = { + "bi_tcxo", + "core_pi_sleep_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_EVEN, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_4[] = { + "bi_tcxo", + "gpll0", + "gpll4_out_even", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static struct pll_vco trion_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +static struct clk_alpha_pll gpll0 = { + .offset = 0x0, + .vco_table = trion_vco, + .num_vco = ARRAY_SIZE(trion_vco), + .type = TRION_PLL, + .clkr = { + .enable_reg = 0x6d000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_trion_fixed_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static const struct clk_div_table post_div_table_trion_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_trion_even, + .num_post_div = ARRAY_SIZE(post_div_table_trion_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll0_out_even", + .parent_names = (const char *[]){ "gpll0" }, + .num_parents = 1, + .ops = &clk_trion_pll_postdiv_ops, + }, +}; + +static struct clk_alpha_pll gpll4 = { + .offset = 0x76000, + .vco_table = trion_vco, + .num_vco = ARRAY_SIZE(trion_vco), + .type = TRION_PLL, + .clkr = { + .enable_reg = 0x6d000, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_trion_fixed_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4_out_even = { + .offset = 0x76000, + .post_div_shift = 8, + .post_div_table = post_div_table_trion_even, + .num_post_div = ARRAY_SIZE(post_div_table_trion_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll4_out_even", + .parent_names = (const char *[]){ "gpll4" }, + .num_parents = 1, + .ops = &clk_trion_pll_postdiv_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_i2c_apps_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x11024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 9600000, + LOWER, 19200000, + LOW, 50000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_spi_apps_clk_src[] = { + F(960000, P_BI_TCXO, 10, 1, 2), + F(4800000, P_BI_TCXO, 4, 0, 0), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(15000000, P_GPLL0_OUT_EVEN, 5, 1, 4), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_GPLL0_OUT_MAIN, 12.5, 1, 2), + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x1100c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 25000000, + NOMINAL, 50000000), + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x13024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 9600000, + LOWER, 19200000, + LOW, 50000000), + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x1300c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 25000000, + NOMINAL, 50000000), + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x15024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 9600000, + LOWER, 19200000, + LOW, 50000000), + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x1500c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 25000000, + NOMINAL, 50000000), + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x17024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 9600000, + LOWER, 19200000, + LOW, 50000000), + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x1700c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 25000000, + NOMINAL, 50000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_uart1_apps_clk_src[] = { + F(3686400, P_GPLL0_OUT_EVEN, 1, 192, 15625), + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(16000000, P_GPLL0_OUT_EVEN, 1, 4, 75), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(19354839, P_GPLL0_OUT_MAIN, 15.5, 1, 2), + F(20000000, P_GPLL0_OUT_MAIN, 15, 1, 2), + F(20689655, P_GPLL0_OUT_MAIN, 14.5, 1, 2), + F(21428571, P_GPLL0_OUT_MAIN, 14, 1, 2), + F(22222222, P_GPLL0_OUT_MAIN, 13.5, 1, 2), + F(23076923, P_GPLL0_OUT_MAIN, 13, 1, 2), + F(24000000, P_GPLL0_OUT_MAIN, 5, 1, 5), + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(26086957, P_GPLL0_OUT_MAIN, 11.5, 1, 2), + F(27272727, P_GPLL0_OUT_MAIN, 11, 1, 2), + F(28571429, P_GPLL0_OUT_MAIN, 10.5, 1, 2), + F(32000000, P_GPLL0_OUT_MAIN, 1, 4, 75), + F(40000000, P_GPLL0_OUT_MAIN, 15, 0, 0), + F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 375), + F(48000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + F(51200000, P_GPLL0_OUT_MAIN, 1, 32, 375), + F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 75), + F(58982400, P_GPLL0_OUT_MAIN, 1, 1536, 15625), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + F(63157895, P_GPLL0_OUT_MAIN, 9.5, 0, 0), + { } +}; + + +static struct clk_rcg2 gcc_blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x1200c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 48000000, + NOMINAL, 63157895), + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x1400c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 48000000, + NOMINAL, 63157895), + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x1600c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 48000000, + NOMINAL, 63157895), + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart4_apps_clk_src = { + .cmd_rcgr = 0x1800c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart4_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 48000000, + NOMINAL, 63157895), + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { + .cmd_rcgr = 0x24010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + NOMINAL, 100000000, + HIGH, 133333333), + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { + .cmd_rcgr = 0x2402c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + NOMINAL, 50000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_emac_clk_src[] = { + F(2500000, P_BI_TCXO, 1, 25, 192), + F(5000000, P_BI_TCXO, 1, 25, 96), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(125000000, P_GPLL4_OUT_EVEN, 4, 0, 0), + F(250000000, P_GPLL4_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac_clk_src = { + .cmd_rcgr = 0x47020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_emac_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_emac_clk_src", + .parent_names = gcc_parent_names_4, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 125000000, + NOMINAL, 250000000), + }, +}; + +static struct clk_rcg2 gcc_emac_ptp_clk_src = { + .cmd_rcgr = 0x47038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_emac_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_emac_ptp_clk_src", + .parent_names = gcc_parent_names_4, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 125000000, + NOMINAL, 250000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x2b004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x2c004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x2d004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_aux_phy_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_aux_phy_clk_src = { + .cmd_rcgr = 0x37030, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_aux_phy_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_aux_phy_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_phy_refgen_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { + .cmd_rcgr = 0x39010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_phy_refgen_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_refgen_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + LOW, 100000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x19010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 9600000, + LOWER, 19200000, + LOW, 60000000), + }, +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0xf00c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), + }, +}; + +static struct clk_rcg2 gcc_spmi_fetcher_clk_src = { + .cmd_rcgr = 0x3f00c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_aux_phy_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_spmi_fetcher_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_master_clk_src[] = { + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_master_clk_src = { + .cmd_rcgr = 0xb01c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 50000000, + LOWER, 75000000, + LOW, 100000000, + NOMINAL, 200000000, + HIGH, 240000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(40000000, P_GPLL0_OUT_EVEN, 7.5, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0xb034, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 40000000, + LOW, 60000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_usb3_phy_aux_clk_src[] = { + F(1000000, P_BI_TCXO, 1, 5, 96), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb3_phy_aux_clk_src = { + .cmd_rcgr = 0xb05c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_usb3_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x10004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(25), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x11008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup1_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x11004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup1_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x13008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup2_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup2_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x15008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup3_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x15004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup3_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x17008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup4_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup4_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_sleep_clk = { + .halt_reg = 0x10008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(26), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x12004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart3_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart4_apps_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x18004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart4_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart4_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1c004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1c004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_ahb_clk = { + .halt_reg = 0x2100c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2100c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_axi_clk = { + .halt_reg = 0x21008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_clk = { + .halt_reg = 0x21004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_ahb_clk = { + .halt_reg = 0x24000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(21), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk", + .parent_names = (const char *[]){ + "gcc_cpuss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_gnoc_clk = { + .halt_reg = 0x24004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x24004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_gnoc_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_rbcpr_clk = { + .halt_reg = 0x24008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x24008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk", + .parent_names = (const char *[]){ + "gcc_cpuss_rbcpr_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_axi_clk = { + .halt_reg = 0x4701c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4701c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_ptp_clk = { + .halt_reg = 0x47018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_ptp_clk", + .parent_names = (const char *[]){ + "gcc_emac_ptp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_rgmii_clk = { + .halt_reg = 0x47010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_rgmii_clk", + .parent_names = (const char *[]){ + "gcc_emac_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_slave_ahb_clk = { + .halt_reg = 0x47014, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x47014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x47014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_slave_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x2b000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_names = (const char *[]){ + "gcc_gp1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x2c000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2c000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_names = (const char *[]){ + "gcc_gp2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x2d000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_names = (const char *[]){ + "gcc_gp3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_clkref_clk = { + .halt_reg = 0x88004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x88004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_aux_clk = { + .halt_reg = 0x37020, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_cfg_ahb_clk = { + .halt_reg = 0x3701c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3701c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_mstr_axi_clk = { + .halt_reg = 0x37018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_refgen_clk = { + .halt_reg = 0x39028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_refgen_clk", + .parent_names = (const char *[]){ + "gcc_pcie_phy_refgen_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_pipe_clk = { + .halt_reg = 0x37028, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_sleep_clk = { + .halt_reg = 0x37024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_sleep_clk", + .parent_names = (const char *[]){ + "gcc_pcie_aux_phy_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_slv_axi_clk = { + .halt_reg = 0x37014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x37014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_slv_q2a_axi_clk = { + .halt_reg = 0x37010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d00c, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x1900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1900c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk", + .parent_names = (const char *[]){ + "gcc_pdm2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x19004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x19004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x19004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x19008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x19008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x1a004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0xf008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0xf004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]){ + "gcc_sdcc1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_spmi_fetcher_ahb_clk = { + .halt_reg = 0x3f008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_spmi_fetcher_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_spmi_fetcher_clk = { + .halt_reg = 0x3f004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_spmi_fetcher_clk", + .parent_names = (const char *[]){ + "gcc_spmi_fetcher_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = { + .halt_reg = 0x400c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_cpuss_ahb_clk", + .parent_names = (const char *[]){ + "gcc_cpuss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb3_clk = { + .halt_reg = 0x4018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_usb3_clk", + .parent_names = (const char *[]){ + "gcc_usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_master_clk = { + .halt_reg = 0xb010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk", + .parent_names = (const char *[]){ + "gcc_usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mock_utmi_clk = { + .halt_reg = 0xb018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk", + .parent_names = (const char *[]){ + "gcc_usb30_mock_utmi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sleep_clk = { + .halt_reg = 0xb014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_aux_clk = { + .halt_reg = 0xb050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk", + .parent_names = (const char *[]){ + "gcc_usb3_phy_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_gate2 gcc_usb3_phy_pipe_clk = { + .udelay = 500, + .clkr = { + .enable_reg = 0xb054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_pipe_clk", + .ops = &clk_gate2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_clkref_clk = { + .halt_reg = 0x88000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x88000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0xe004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_phy_cfg_ahb2phy_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gcc_sdxpoorwills_clocks[] = { + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup1_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup1_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup2_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup2_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup3_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup3_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup4_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup4_spi_apps_clk_src.clkr, + [GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK_SRC] = &gcc_blsp1_uart1_apps_clk_src.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK_SRC] = &gcc_blsp1_uart2_apps_clk_src.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK_SRC] = &gcc_blsp1_uart3_apps_clk_src.clkr, + [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr, + [GCC_BLSP1_UART4_APPS_CLK_SRC] = &gcc_blsp1_uart4_apps_clk_src.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr, + [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr, + [GCC_CE1_CLK] = &gcc_ce1_clk.clkr, + [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr, + [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, + [GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr, + [GCC_EMAC_CLK_SRC] = &gcc_emac_clk_src.clkr, + [GCC_EMAC_PTP_CLK_SRC] = &gcc_emac_ptp_clk_src.clkr, + [GCC_ETH_AXI_CLK] = &gcc_eth_axi_clk.clkr, + [GCC_ETH_PTP_CLK] = &gcc_eth_ptp_clk.clkr, + [GCC_ETH_RGMII_CLK] = &gcc_eth_rgmii_clk.clkr, + [GCC_ETH_SLAVE_AHB_CLK] = &gcc_eth_slave_ahb_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr, + [GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr, + [GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr, + [GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr, + [GCC_PCIE_MSTR_AXI_CLK] = &gcc_pcie_mstr_axi_clk.clkr, + [GCC_PCIE_PHY_REFGEN_CLK] = &gcc_pcie_phy_refgen_clk.clkr, + [GCC_PCIE_PHY_REFGEN_CLK_SRC] = &gcc_pcie_phy_refgen_clk_src.clkr, + [GCC_PCIE_PIPE_CLK] = &gcc_pcie_pipe_clk.clkr, + [GCC_PCIE_SLEEP_CLK] = &gcc_pcie_sleep_clk.clkr, + [GCC_PCIE_SLV_AXI_CLK] = &gcc_pcie_slv_axi_clk.clkr, + [GCC_PCIE_SLV_Q2A_AXI_CLK] = &gcc_pcie_slv_q2a_axi_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr, + [GCC_SPMI_FETCHER_AHB_CLK] = &gcc_spmi_fetcher_ahb_clk.clkr, + [GCC_SPMI_FETCHER_CLK] = &gcc_spmi_fetcher_clk.clkr, + [GCC_SPMI_FETCHER_CLK_SRC] = &gcc_spmi_fetcher_clk_src.clkr, + [GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr, + [GCC_SYS_NOC_USB3_CLK] = &gcc_sys_noc_usb3_clk.clkr, + [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr, + [GCC_USB30_MASTER_CLK_SRC] = &gcc_usb30_master_clk_src.clkr, + [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr, + [GCC_USB30_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mock_utmi_clk_src.clkr, + [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr, + [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr, + [GCC_USB3_PHY_AUX_CLK_SRC] = &gcc_usb3_phy_aux_clk_src.clkr, + [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr, + [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL4_OUT_EVEN] = &gpll4_out_even.clkr, +}; + +static const struct qcom_reset_map gcc_sdxpoorwills_resets[] = { + [GCC_BLSP1_QUP1_BCR] = { 0x11000 }, + [GCC_BLSP1_QUP2_BCR] = { 0x13000 }, + [GCC_BLSP1_QUP3_BCR] = { 0x15000 }, + [GCC_BLSP1_QUP4_BCR] = { 0x17000 }, + [GCC_BLSP1_UART2_BCR] = { 0x14000 }, + [GCC_BLSP1_UART3_BCR] = { 0x16000 }, + [GCC_BLSP1_UART4_BCR] = { 0x18000 }, + [GCC_CE1_BCR] = { 0x21000 }, + [GCC_EMAC_BCR] = { 0x47000 }, + [GCC_PCIE_BCR] = { 0x37000 }, + [GCC_PCIE_PHY_BCR] = { 0x39000 }, + [GCC_PDM_BCR] = { 0x19000 }, + [GCC_PRNG_BCR] = { 0x1a000 }, + [GCC_SDCC1_BCR] = { 0xf000 }, + [GCC_SPMI_FETCHER_BCR] = { 0x3f000 }, + [GCC_USB30_BCR] = { 0xb000 }, + [GCC_USB3_PHY_BCR] = { 0xc000 }, + [GCC_USB3PHY_PHY_BCR] = { 0xc004 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 }, +}; + + +static const struct regmap_config gcc_sdxpoorwills_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9b040, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sdxpoorwills_desc = { + .config = &gcc_sdxpoorwills_regmap_config, + .clks = gcc_sdxpoorwills_clocks, + .num_clks = ARRAY_SIZE(gcc_sdxpoorwills_clocks), + .resets = gcc_sdxpoorwills_resets, + .num_resets = ARRAY_SIZE(gcc_sdxpoorwills_resets), +}; + +static const struct of_device_id gcc_sdxpoorwills_match_table[] = { + { .compatible = "qcom,gcc-sdxpoorwills" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sdxpoorwills_match_table); + +static int gcc_sdxpoorwills_probe(struct platform_device *pdev) +{ + int ret = 0; + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gcc_sdxpoorwills_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + ret = qcom_cc_really_probe(pdev, &gcc_sdxpoorwills_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GCC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered GCC clocks\n"); + + return ret; +} + +static struct platform_driver gcc_sdxpoorwills_driver = { + .probe = gcc_sdxpoorwills_probe, + .driver = { + .name = "gcc-sdxpoorwills", + .of_match_table = gcc_sdxpoorwills_match_table, + }, +}; + +static int __init gcc_sdxpoorwills_init(void) +{ + return platform_driver_register(&gcc_sdxpoorwills_driver); +} +subsys_initcall(gcc_sdxpoorwills_init); + +static void __exit gcc_sdxpoorwills_exit(void) +{ + platform_driver_unregister(&gcc_sdxpoorwills_driver); +} +module_exit(gcc_sdxpoorwills_exit); + +MODULE_DESCRIPTION("QTI GCC SDXPOORWILLS Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gcc-sdxpoorwills"); diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 3bb7c04d0b488195fd8f43ce442c4400f0f787e9..08991387d85aad2cd1831325bfdf71dfd073c2b4 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "gdsc: %s: " fmt, __func__ + #include #include #include @@ -54,6 +56,9 @@ /* Timeout Delay */ #define TIMEOUT_US 100 +/* TOGGLE SW COLLAPSE */ +#define TOGGLE_SW_COLLAPSE_IN_DISABLE BIT(0) + struct gdsc { struct regulator_dev *rdev; struct regulator_desc rdesc; @@ -79,6 +84,7 @@ struct gdsc { int reset_count; int root_clk_idx; u32 gds_timeout; + u32 flags; }; enum gdscr_status { @@ -378,6 +384,13 @@ static int gdsc_disable(struct regulator_dev *rdev) regval |= SW_COLLAPSE_MASK; regmap_write(sc->regmap, REG_OFFSET, regval); + if (sc->flags & TOGGLE_SW_COLLAPSE_IN_DISABLE) { + regval &= ~SW_COLLAPSE_MASK; + regmap_write(sc->regmap, REG_OFFSET, regval); + regval |= SW_COLLAPSE_MASK; + regmap_write(sc->regmap, REG_OFFSET, regval); + } + /* Wait for 8 XO cycles before polling the status bit. */ mb(); udelay(1); @@ -522,7 +535,7 @@ static int gdsc_probe(struct platform_device *pdev) struct resource *res; struct gdsc *sc; uint32_t regval, clk_dis_wait_val = 0; - bool retain_mem, retain_periph, support_hw_trigger; + bool retain_mem, retain_periph, support_hw_trigger, prop_val; int i, ret; u32 timeout; @@ -613,6 +626,11 @@ static int gdsc_probe(struct platform_device *pdev) sc->force_root_en = of_property_read_bool(pdev->dev.of_node, "qcom,force-enable-root-clk"); + prop_val = of_property_read_bool(pdev->dev.of_node, + "qcom,toggle-sw-collapse-in-disable"); + if (prop_val) + sc->flags |= TOGGLE_SW_COLLAPSE_IN_DISABLE; + for (i = 0; i < sc->clock_count; i++) { const char *clock_name; diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c index 0115bb1d73457e367005a9a1b6fc45abe4db9889..53446a2d7b59bb2621da19282d11aa3b14a064cf 100644 --- a/drivers/clk/qcom/gpucc-sdm845.c +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -34,8 +36,12 @@ #include "clk-alpha-pll.h" #include "vdd-level-sdm845.h" +#define CX_GMU_CBCR_SLEEP_MASK 0xF +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xF +#define CX_GMU_CBCR_WAKE_SHIFT 8 + #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } -#define F_SLEW(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) } static int vdd_gx_corner[] = { RPMH_REGULATOR_LEVEL_OFF, /* VDD_GX_NONE */ @@ -65,6 +71,7 @@ enum { P_GPU_CC_PLL1_OUT_EVEN, P_GPU_CC_PLL1_OUT_MAIN, P_GPU_CC_PLL1_OUT_ODD, + P_CRC_DIV, }; static const struct parent_map gpu_cc_parent_map_0[] = { @@ -107,20 +114,26 @@ static const char * const gpu_cc_parent_names_1[] = { static const struct parent_map gpu_cc_parent_map_2[] = { { P_BI_TCXO, 0 }, + { P_CRC_DIV, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, { P_GPLL0_OUT_MAIN, 5 }, - { P_GPLL0_OUT_MAIN_DIV, 6 }, { P_CORE_BI_PLL_TEST_SE, 7 }, }; static const char * const gpu_cc_parent_names_2[] = { "bi_tcxo", + "crc_div", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", "gcc_gpu_gpll0_clk_src", - "gcc_gpu_gpll0_div_clk_src", "core_bi_pll_test_se", }; static struct pll_vco fabia_vco[] = { - { 250000000, 2000000000, 0 }, + { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, }; @@ -129,6 +142,11 @@ static const struct pll_config gpu_cc_pll0_config = { .frac = 0x2aaa, }; +static const struct pll_config gpu_cc_pll1_config = { + .l = 0x1a, + .frac = 0xaaaa, +}; + static struct clk_alpha_pll gpu_cc_pll0 = { .offset = 0x0, .vco_table = fabia_vco, @@ -172,6 +190,26 @@ static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { }, }; +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_MX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), @@ -179,6 +217,19 @@ static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm670[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + { } +}; + static struct clk_rcg2 gpu_cc_gmu_clk_src = { .cmd_rcgr = 0x1120, .mnd_width = 0, @@ -198,12 +249,52 @@ static struct clk_rcg2 gpu_cc_gmu_clk_src = { }, }; +static struct clk_fixed_factor crc_div = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "crc_div", + .parent_names = (const char *[]){ "gpu_cc_pll0_out_even" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { - F_SLEW(147000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 294000000), - F_SLEW(210000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 420000000), - F_SLEW(338000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 676000000), - F_SLEW(425000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 850000000), - F_SLEW(600000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0, 1200000000), + F(147000000, P_CRC_DIV, 1, 0, 0), + F(210000000, P_CRC_DIV, 1, 0, 0), + F(280000000, P_CRC_DIV, 1, 0, 0), + F(338000000, P_CRC_DIV, 1, 0, 0), + F(425000000, P_CRC_DIV, 1, 0, 0), + F(487000000, P_CRC_DIV, 1, 0, 0), + F(548000000, P_CRC_DIV, 1, 0, 0), + F(600000000, P_CRC_DIV, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2[] = { + F(180000000, P_CRC_DIV, 1, 0, 0), + F(257000000, P_CRC_DIV, 1, 0, 0), + F(342000000, P_CRC_DIV, 1, 0, 0), + F(414000000, P_CRC_DIV, 1, 0, 0), + F(520000000, P_CRC_DIV, 1, 0, 0), + F(596000000, P_CRC_DIV, 1, 0, 0), + F(675000000, P_CRC_DIV, 1, 0, 0), + F(710000000, P_CRC_DIV, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670[] = { + F(180000000, P_CRC_DIV, 1, 0, 0), + F(267000000, P_CRC_DIV, 1, 0, 0), + F(355000000, P_CRC_DIV, 1, 0, 0), + F(430000000, P_CRC_DIV, 1, 0, 0), + F(565000000, P_CRC_DIV, 1, 0, 0), + F(650000000, P_CRC_DIV, 1, 0, 0), + F(700000000, P_CRC_DIV, 1, 0, 0), + F(750000000, P_CRC_DIV, 1, 0, 0), + F(780000000, P_CRC_DIV, 1, 0, 0), { } }; @@ -211,12 +302,12 @@ static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { .cmd_rcgr = 0x101c, .mnd_width = 0, .hid_width = 5, - .parent_map = gpu_cc_parent_map_1, + .parent_map = gpu_cc_parent_map_2, .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gpu_cc_gx_gfx3d_clk_src", - .parent_names = gpu_cc_parent_names_1, + .parent_names = gpu_cc_parent_names_2, .num_parents = 7, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -232,29 +323,6 @@ static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { }, }; -static const struct freq_tbl ftbl_gpu_cc_rbcpr_clk_src[] = { - F(19200000, P_BI_TCXO, 1, 0, 0), - { } -}; - -static struct clk_rcg2 gpu_cc_rbcpr_clk_src = { - .cmd_rcgr = 0x10b0, - .mnd_width = 0, - .hid_width = 5, - .parent_map = gpu_cc_parent_map_2, - .freq_tbl = ftbl_gpu_cc_rbcpr_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gpu_cc_rbcpr_clk_src", - .parent_names = gpu_cc_parent_names_2, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP2( - MIN, 19200000, - NOMINAL, 50000000), - }, -}; - static struct clk_branch gpu_cc_acd_ahb_clk = { .halt_reg = 0x1168, .halt_check = BRANCH_HALT, @@ -281,19 +349,6 @@ static struct clk_branch gpu_cc_acd_cxo_clk = { }, }; -static struct clk_branch gpu_cc_ahb_clk = { - .halt_reg = 0x1078, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x1078, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gpu_cc_ahb_clk", - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_branch gpu_cc_crc_ahb_clk = { .halt_reg = 0x107c, .halt_check = BRANCH_HALT, @@ -413,19 +468,6 @@ static struct clk_branch gpu_cc_cxo_clk = { }, }; -static struct clk_branch gpu_cc_gx_cxo_clk = { - .halt_reg = 0x1060, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x1060, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gpu_cc_gx_cxo_clk", - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_branch gpu_cc_gx_gfx3d_clk = { .halt_reg = 0x1054, .halt_check = BRANCH_HALT, @@ -488,41 +530,9 @@ static struct clk_branch gpu_cc_pll_test_clk = { }, }; -static struct clk_branch gpu_cc_rbcpr_ahb_clk = { - .halt_reg = 0x10f4, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x10f4, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gpu_cc_rbcpr_ahb_clk", - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gpu_cc_rbcpr_clk = { - .halt_reg = 0x10f0, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x10f0, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gpu_cc_rbcpr_clk", - .parent_names = (const char *[]){ - "gpu_cc_rbcpr_clk_src", - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_regmap *gpu_cc_sdm845_clocks[] = { [GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr, [GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr, - [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, @@ -532,17 +542,14 @@ static struct clk_regmap *gpu_cc_sdm845_clocks[] = { [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, - [GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr, [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, [GPU_CC_PLL_TEST_CLK] = &gpu_cc_pll_test_clk.clkr, - [GPU_CC_RBCPR_AHB_CLK] = &gpu_cc_rbcpr_ahb_clk.clkr, - [GPU_CC_RBCPR_CLK] = &gpu_cc_rbcpr_clk.clkr, - [GPU_CC_RBCPR_CLK_SRC] = &gpu_cc_rbcpr_clk_src.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL1] = NULL, }; static struct clk_regmap *gpu_cc_gfx_sdm845_clocks[] = { - [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, @@ -554,7 +561,6 @@ static const struct qcom_reset_map gpu_cc_sdm845_resets[] = { [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 }, [GPUCC_GPU_CC_GMU_BCR] = { 0x111c }, [GPUCC_GPU_CC_GX_BCR] = { 0x1008 }, - [GPUCC_GPU_CC_RBCPR_BCR] = { 0x10ac }, [GPUCC_GPU_CC_SPDM_BCR] = { 0x1110 }, [GPUCC_GPU_CC_XO_BCR] = { 0x1000 }, }; @@ -583,16 +589,111 @@ static const struct qcom_cc_desc gpu_cc_gfx_sdm845_desc = { static const struct of_device_id gpu_cc_sdm845_match_table[] = { { .compatible = "qcom,gpucc-sdm845" }, + { .compatible = "qcom,gpucc-sdm845-v2" }, + { .compatible = "qcom,gpucc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table); static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = { { .compatible = "qcom,gfxcc-sdm845" }, + { .compatible = "qcom,gfxcc-sdm845-v2" }, + { .compatible = "qcom,gfxcc-sdm670" }, {}, }; MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table); +static void gpu_cc_sdm845_fixup_sdm845v2(struct regmap *regmap) +{ + gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr; + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm845_v2; + gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000; +} + +static void gpu_cc_sdm845_fixup_sdm670(struct regmap *regmap) +{ + gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr; + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm670; + gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 200000000; +} + +static void gpu_cc_gfx_sdm845_fixup_sdm845v2(void) +{ + gpu_cc_gx_gfx3d_clk_src.freq_tbl = + ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] = 180000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] = + 257000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] = 342000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] = + 414000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] = + 520000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] = + 596000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] = 675000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] = + 710000000; +} + +static void gpu_cc_gfx_sdm845_fixup_sdm670(void) +{ + gpu_cc_gx_gfx3d_clk_src.freq_tbl = + ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] = 180000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] = + 267000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] = 355000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] = + 430000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] = + 565000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] = + 650000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] = 750000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] = + 780000000; +} + +static int gpu_cc_gfx_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,gfxcc-sdm845-v2")) + gpu_cc_gfx_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,gfxcc-sdm670")) + gpu_cc_gfx_sdm845_fixup_sdm670(); + + return 0; +} + +static int gpu_cc_sdm845_fixup(struct platform_device *pdev, + struct regmap *regmap) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,gpucc-sdm845-v2")) + gpu_cc_sdm845_fixup_sdm845v2(regmap); + else if (!strcmp(compat, "qcom,gpucc-sdm670")) + gpu_cc_sdm845_fixup_sdm670(regmap); + + return 0; +} + static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; @@ -602,16 +703,23 @@ static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { - dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc.\n"); + dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc\n"); return -EINVAL; } base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (IS_ERR(base)) { - dev_err(&pdev->dev, "Failed to ioremap the GFX CC base.\n"); + dev_err(&pdev->dev, "Failed to ioremap the GFX CC base\n"); return PTR_ERR(base); } + /* Register clock fixed factor for CRC divide. */ + ret = devm_clk_hw_register(&pdev->dev, &crc_div.hw); + if (ret) { + dev_err(&pdev->dev, "Failed to register hardware clock\n"); + return ret; + } + regmap = devm_regmap_init_mmio(&pdev->dev, base, gpu_cc_gfx_sdm845_desc.config); if (IS_ERR(regmap)) { @@ -619,15 +727,6 @@ static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev) return PTR_ERR(regmap); } - /* Get MX voltage regulator for GPU PLL graphic clock. */ - vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx"); - if (IS_ERR(vdd_mx.regulator[0])) { - if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) - dev_err(&pdev->dev, - "Unable to get vdd_mx regulator\n"); - return PTR_ERR(vdd_mx.regulator[0]); - } - /* GFX voltage regulators for GFX3D graphic clock. */ vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx"); if (IS_ERR(vdd_gfx.regulator[0])) { @@ -636,6 +735,15 @@ static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev) return PTR_ERR(vdd_gfx.regulator[0]); } + /* Avoid turning on the rail during clock registration */ + vdd_gfx.skip_handoff = true; + + ret = gpu_cc_gfx_sdm845_fixup(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to do GFX clock fixup\n"); + return ret; + } + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); ret = qcom_cc_really_probe(pdev, &gpu_cc_gfx_sdm845_desc, regmap); @@ -644,9 +752,7 @@ static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev) return ret; } - clk_prepare_enable(gpu_cc_cxo_clk.clkr.hw.clk); - - dev_info(&pdev->dev, "Registered GFX CC clocks.\n"); + dev_info(&pdev->dev, "Registered GFX CC clocks\n"); return ret; } @@ -663,7 +769,7 @@ static int __init gpu_cc_gfx_sdm845_init(void) { return platform_driver_register(&gpu_cc_gfx_sdm845_driver); } -arch_initcall(gpu_cc_gfx_sdm845_init); +subsys_initcall(gpu_cc_gfx_sdm845_init); static void __exit gpu_cc_gfx_sdm845_exit(void) { @@ -675,6 +781,7 @@ static int gpu_cc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; int ret = 0; + unsigned int value, mask; regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); if (IS_ERR(regmap)) @@ -689,13 +796,34 @@ static int gpu_cc_sdm845_probe(struct platform_device *pdev) return PTR_ERR(vdd_cx.regulator[0]); } + /* Get MX voltage regulator for GPU PLL graphic clock. */ + vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx"); + if (IS_ERR(vdd_mx.regulator[0])) { + if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_mx regulator\n"); + return PTR_ERR(vdd_mx.regulator[0]); + } + + ret = gpu_cc_sdm845_fixup(pdev, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to do GPU CC clock fixup\n"); + return ret; + } + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); if (ret) { dev_err(&pdev->dev, "Failed to register GPU CC clocks\n"); return ret; } - dev_info(&pdev->dev, "Registered GPU CC clocks.\n"); + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg, + mask, value); + + dev_info(&pdev->dev, "Registered GPU CC clocks\n"); return ret; } @@ -712,7 +840,7 @@ static int __init gpu_cc_sdm845_init(void) { return platform_driver_register(&gpu_cc_sdm845_driver); } -core_initcall(gpu_cc_sdm845_init); +subsys_initcall(gpu_cc_sdm845_init); static void __exit gpu_cc_sdm845_exit(void) { diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile index d183393f80a839e70ab5ac92e35c646f6a951bf0..87feee6f282d6978c1634523fb3645a009261317 100644 --- a/drivers/clk/qcom/mdss/Makefile +++ b/drivers/clk/qcom/mdss/Makefile @@ -1,3 +1,6 @@ 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-10nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-10nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-10nm-util.o + diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c new file mode 100644 index 0000000000000000000000000000000000000000..eb2092a9e102993d25b4fba2c78511ba4259c459 --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c @@ -0,0 +1,766 @@ +/* Copyright (c) 2016-2017, 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 +#include +#include +#include +#include + +#include "mdss-pll.h" +#include "mdss-dp-pll.h" +#include "mdss-dp-pll-10nm.h" + +#define DP_PHY_REVISION_ID0 0x0000 +#define DP_PHY_REVISION_ID1 0x0004 +#define DP_PHY_REVISION_ID2 0x0008 +#define DP_PHY_REVISION_ID3 0x000C + +#define DP_PHY_CFG 0x0010 +#define DP_PHY_PD_CTL 0x0018 +#define DP_PHY_MODE 0x001C + +#define DP_PHY_AUX_CFG0 0x0020 +#define DP_PHY_AUX_CFG1 0x0024 +#define DP_PHY_AUX_CFG2 0x0028 +#define DP_PHY_AUX_CFG3 0x002C +#define DP_PHY_AUX_CFG4 0x0030 +#define DP_PHY_AUX_CFG5 0x0034 +#define DP_PHY_AUX_CFG6 0x0038 +#define DP_PHY_AUX_CFG7 0x003C +#define DP_PHY_AUX_CFG8 0x0040 +#define DP_PHY_AUX_CFG9 0x0044 +#define DP_PHY_AUX_INTERRUPT_MASK 0x0048 +#define DP_PHY_AUX_INTERRUPT_CLEAR 0x004C +#define DP_PHY_AUX_BIST_CFG 0x0050 + +#define DP_PHY_VCO_DIV 0x0064 +#define DP_PHY_TX0_TX1_LANE_CTL 0x006C +#define DP_PHY_TX2_TX3_LANE_CTL 0x0088 + +#define DP_PHY_SPARE0 0x00AC +#define DP_PHY_STATUS 0x00C0 + +/* Tx registers */ +#define TXn_BIST_MODE_LANENO 0x0000 +#define TXn_CLKBUF_ENABLE 0x0008 +#define TXn_TX_EMP_POST1_LVL 0x000C + +#define TXn_TX_DRV_LVL 0x001C + +#define TXn_RESET_TSYNC_EN 0x0024 +#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028 +#define TXn_TX_BAND 0x002C +#define TXn_SLEW_CNTL 0x0030 +#define TXn_INTERFACE_SELECT 0x0034 + +#define TXn_RES_CODE_LANE_TX 0x003C +#define TXn_RES_CODE_LANE_RX 0x0040 +#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044 +#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048 + +#define TXn_DEBUG_BUS_SEL 0x0058 +#define TXn_TRANSCEIVER_BIAS_EN 0x005C +#define TXn_HIGHZ_DRVR_EN 0x0060 +#define TXn_TX_POL_INV 0x0064 +#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068 + +#define TXn_LANE_MODE_1 0x008C + +#define TXn_TRAN_DRVR_EMP_EN 0x00C0 +#define TXn_TX_INTERFACE_MODE 0x00C4 + +#define TXn_VMODE_CTRL1 0x00F0 + +/* PLL register offset */ +#define QSERDES_COM_ATB_SEL1 0x0000 +#define QSERDES_COM_ATB_SEL2 0x0004 +#define QSERDES_COM_FREQ_UPDATE 0x0008 +#define QSERDES_COM_BG_TIMER 0x000C +#define QSERDES_COM_SSC_EN_CENTER 0x0010 +#define QSERDES_COM_SSC_ADJ_PER1 0x0014 +#define QSERDES_COM_SSC_ADJ_PER2 0x0018 +#define QSERDES_COM_SSC_PER1 0x001C +#define QSERDES_COM_SSC_PER2 0x0020 +#define QSERDES_COM_SSC_STEP_SIZE1 0x0024 +#define QSERDES_COM_SSC_STEP_SIZE2 0x0028 +#define QSERDES_COM_POST_DIV 0x002C +#define QSERDES_COM_POST_DIV_MUX 0x0030 +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034 +#define QSERDES_COM_CLK_ENABLE1 0x0038 +#define QSERDES_COM_SYS_CLK_CTRL 0x003C +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040 +#define QSERDES_COM_PLL_EN 0x0044 +#define QSERDES_COM_PLL_IVCO 0x0048 +#define QSERDES_COM_CMN_IETRIM 0x004C +#define QSERDES_COM_CMN_IPTRIM 0x0050 + +#define QSERDES_COM_CP_CTRL_MODE0 0x0060 +#define QSERDES_COM_CP_CTRL_MODE1 0x0064 +#define QSERDES_COM_PLL_RCTRL_MODE0 0x0068 +#define QSERDES_COM_PLL_RCTRL_MODE1 0x006C +#define QSERDES_COM_PLL_CCTRL_MODE0 0x0070 +#define QSERDES_COM_PLL_CCTRL_MODE1 0x0074 +#define QSERDES_COM_PLL_CNTRL 0x0078 +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x007C +#define QSERDES_COM_SYSCLK_EN_SEL 0x0080 +#define QSERDES_COM_CML_SYSCLK_SEL 0x0084 +#define QSERDES_COM_RESETSM_CNTRL 0x0088 +#define QSERDES_COM_RESETSM_CNTRL2 0x008C +#define QSERDES_COM_LOCK_CMP_EN 0x0090 +#define QSERDES_COM_LOCK_CMP_CFG 0x0094 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x0098 +#define QSERDES_COM_LOCK_CMP2_MODE0 0x009C +#define QSERDES_COM_LOCK_CMP3_MODE0 0x00A0 + +#define QSERDES_COM_DEC_START_MODE0 0x00B0 +#define QSERDES_COM_DEC_START_MODE1 0x00B4 +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00B8 +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00BC +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00C0 +#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x00C4 +#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x00C8 +#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x00CC +#define QSERDES_COM_INTEGLOOP_INITVAL 0x00D0 +#define QSERDES_COM_INTEGLOOP_EN 0x00D4 +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00D8 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00DC +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x00E0 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x00E4 +#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x00E8 +#define QSERDES_COM_VCO_TUNE_CTRL 0x00EC +#define QSERDES_COM_VCO_TUNE_MAP 0x00F0 + +#define QSERDES_COM_CMN_STATUS 0x0124 +#define QSERDES_COM_RESET_SM_STATUS 0x0128 + +#define QSERDES_COM_CLK_SEL 0x0138 +#define QSERDES_COM_HSCLK_SEL 0x013C + +#define QSERDES_COM_CORECLK_DIV_MODE0 0x0148 + +#define QSERDES_COM_SW_RESET 0x0150 +#define QSERDES_COM_CORE_CLK_EN 0x0154 +#define QSERDES_COM_C_READY_STATUS 0x0158 +#define QSERDES_COM_CMN_CONFIG 0x015C + +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x0164 + +#define DP_PHY_PLL_POLL_SLEEP_US 500 +#define DP_PHY_PLL_POLL_TIMEOUT_US 10000 + +#define DP_VCO_RATE_8100MHZDIV1000 8100000UL +#define DP_VCO_RATE_9720MHZDIV1000 9720000UL +#define DP_VCO_RATE_10800MHZDIV1000 10800000UL + +int dp_mux_set_parent_10nm(void *context, unsigned int reg, unsigned int val) +{ + struct mdss_pll_resources *dp_res = context; + int rc; + u32 auxclk_div; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP PLL resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= ~0x03; /* bits 0 to 1 */ + + if (val == 0) /* mux parent index = 0 */ + auxclk_div |= 1; + else if (val == 1) /* mux parent index = 1 */ + auxclk_div |= 2; + else if (val == 2) /* mux parent index = 2 */ + auxclk_div |= 0; + + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_VCO_DIV, auxclk_div); + /* Make sure the PHY registers writes are done */ + wmb(); + pr_debug("%s: mux=%d auxclk_div=%x\n", __func__, val, auxclk_div); + + mdss_pll_resource_enable(dp_res, false); + + return 0; +} + +int dp_mux_get_parent_10nm(void *context, unsigned int reg, unsigned int *val) +{ + int rc; + u32 auxclk_div = 0; + struct mdss_pll_resources *dp_res = context; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable dp_res resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= 0x03; + + if (auxclk_div == 1) /* Default divider */ + *val = 0; + else if (auxclk_div == 2) + *val = 1; + else if (auxclk_div == 0) + *val = 2; + + mdss_pll_resource_enable(dp_res, false); + + pr_debug("%s: auxclk_div=%d, val=%d\n", __func__, auxclk_div, *val); + + return 0; +} + +static int dp_vco_pll_init_db_10nm(struct dp_pll_db *pdb, + unsigned long rate) +{ + struct mdss_pll_resources *dp_res = pdb->pll; + u32 spare_value = 0; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + pdb->lane_cnt = spare_value & 0x0F; + pdb->orientation = (spare_value & 0xF0) >> 4; + + pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + __func__, spare_value, pdb->lane_cnt, pdb->orientation); + + switch (rate) { + case DP_VCO_HSCLK_RATE_1620MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_9720MHZDIV1000); + pdb->hsclk_sel = 0x0c; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x6f; + pdb->lock_cmp2_mode0 = 0x08; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x00; + break; + case DP_VCO_HSCLK_RATE_2700MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x04; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x0f; + pdb->lock_cmp2_mode0 = 0x0e; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x00; + break; + case DP_VCO_HSCLK_RATE_5400MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x00; + pdb->dec_start_mode0 = 0x8c; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x00; + pdb->div_frac_start3_mode0 = 0x0a; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x1f; + pdb->lock_cmp2_mode0 = 0x1c; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x2; + pdb->lock_cmp_en = 0x00; + break; + case DP_VCO_HSCLK_RATE_8100MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_8100MHZDIV1000); + pdb->hsclk_sel = 0x03; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x2f; + pdb->lock_cmp2_mode0 = 0x2a; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x0; + pdb->lock_cmp_en = 0x08; + break; + default: + return -EINVAL; + } + return 0; +} + +static int dp_config_vco_rate_10nm(struct dp_pll_vco_clk *vco, + unsigned long rate) +{ + u32 res = 0; + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + + res = dp_vco_pll_init_db_10nm(pdb, rate); + if (res) { + pr_err("VCO Init DB failed\n"); + return res; + } + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x6d); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x75); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x7d); + } + + /* Make sure the PHY register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, 0x01); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0e); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_SEL, 0x30); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CMN_CONFIG, 0x02); + + /* Different for each clock rates */ + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN0_MODE0, pdb->integloop_gain0_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN1_MODE0, pdb->integloop_gain1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_MAP, pdb->vco_tune_map); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP3_MODE0, pdb->lock_cmp3_mode0); + /* Make sure the PLL register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BG_TIMER, 0x0a); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORECLK_DIV_MODE0, 0x0a); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_VCO_TUNE_CTRL, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORE_CLK_EN, 0x1f); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_IVCO, 0x07); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP_EN, pdb->lock_cmp_en); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CP_CTRL_MODE0, 0x06); + /* Make sure the PHY register writes are done */ + wmb(); + + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x4c); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x5c); + /* Make sure the PLL register writes are done */ + wmb(); + + /* TX Lane configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX0_TX1_LANE_CTL, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX2_TX3_LANE_CTL, 0x05); + + /* TX-0 register configuration */ + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_BAND, 0x4); + + /* TX-1 register configuration */ + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_BAND, 0x4); + /* Make sure the PHY register writes are done */ + wmb(); + + /* dependent on the vco frequency */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, pdb->phy_vco_div); + + return res; +} + +static bool dp_10nm_pll_lock_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool pll_locked; + + /* poll for PLL lock status */ + if (readl_poll_timeout_atomic((dp_res->pll_base + + QSERDES_COM_C_READY_STATUS), + status, + ((status & BIT(0)) > 0), + DP_PHY_PLL_POLL_SLEEP_US, + DP_PHY_PLL_POLL_TIMEOUT_US)) { + pr_err("%s: C_READY status is not high. Status=%x\n", + __func__, status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +static bool dp_10nm_phy_rdy_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool phy_ready = true; + + /* poll for PHY ready status */ + if (readl_poll_timeout_atomic((dp_res->phy_base + + DP_PHY_STATUS), + status, + ((status & (BIT(1))) > 0), + DP_PHY_PLL_POLL_SLEEP_US, + DP_PHY_PLL_POLL_TIMEOUT_US)) { + pr_err("%s: Phy_ready is not high. Status=%x\n", + __func__, status); + phy_ready = false; + } + + return phy_ready; +} + +static int dp_pll_enable_10nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + u32 bias_en, drvr_en; + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_AUX_CFG2, 0x04); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09); + wmb(); /* Make sure the PHY register writes are done */ + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20); + wmb(); /* Make sure the PLL register writes are done */ + + if (!dp_10nm_pll_lock_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + /* Make sure the PHY register writes are done */ + wmb(); + /* poll for PHY ready status */ + if (!dp_10nm_phy_rdy_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + pr_debug("%s: PLL is locked\n", __func__); + + if (pdb->lane_cnt == 1) { + bias_en = 0x3e; + drvr_en = 0x13; + } else { + bias_en = 0x3f; + drvr_en = 0x10; + } + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC1) { + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + } else { + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + } + } else { + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + } + + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_POL_INV, 0x0a); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_POL_INV, 0x0a); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x18); + udelay(2000); + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + + /* + * Make sure all the register writes are completed before + * doing any other operation + */ + wmb(); + + /* poll for PHY ready status */ + if (!dp_10nm_phy_rdy_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_DRV_LVL, 0x38); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_DRV_LVL, 0x38); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_EMP_POST1_LVL, 0x20); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_EMP_POST1_LVL, 0x20); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07); + /* Make sure the PHY register writes are done */ + wmb(); + +lock_err: + return rc; +} + +static int dp_pll_disable_10nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + /* Assert DP PHY power down */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2); + /* + * Make sure all the register writes to disable PLL are + * completed before doing any other operation + */ + wmb(); + + return rc; +} + + +int dp_vco_prepare_10nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + pr_debug("rate=%ld\n", vco->rate); + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll resources\n"); + goto error; + } + + if ((dp_res->vco_cached_rate != 0) + && (dp_res->vco_cached_rate == vco->rate)) { + rc = vco->hw.init->ops->set_rate(hw, + dp_res->vco_cached_rate, dp_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, dp_res->index); + mdss_pll_resource_enable(dp_res, false); + goto error; + } + } + + rc = dp_pll_enable_10nm(hw); + if (rc) { + mdss_pll_resource_enable(dp_res, false); + pr_err("ndx=%d failed to enable dp pll\n", + dp_res->index); + goto error; + } + + mdss_pll_resource_enable(dp_res, false); +error: + return rc; +} + +void dp_vco_unprepare_10nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + if (!dp_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!dp_res->pll_on && + mdss_pll_resource_enable(dp_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + dp_res->vco_cached_rate = vco->rate; + dp_pll_disable_10nm(hw); + + dp_res->handoff_resources = false; + mdss_pll_resource_enable(dp_res, false); + dp_res->pll_on = false; +} + +int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + int rc; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + pr_debug("DP lane CLK rate=%ld\n", rate); + + rc = dp_config_vco_rate_10nm(vco, rate); + if (rc) + pr_err("%s: Failed to set clk rate\n", __func__); + + mdss_pll_resource_enable(dp_res, false); + + vco->rate = rate; + + return 0; +} + +unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + int rc; + u32 div, hsclk_div, link_clk_div = 0; + u64 vco_rate; + struct mdss_pll_resources *dp_res = vco->priv; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index); + return rc; + } + + div = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL); + div &= 0x0f; + + if (div == 12) + hsclk_div = 6; /* Default */ + else if (div == 4) + hsclk_div = 4; + else if (div == 0) + hsclk_div = 2; + else if (div == 3) + hsclk_div = 1; + else { + pr_debug("unknown divider. forcing to default\n"); + hsclk_div = 5; + } + + div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_AUX_CFG2); + div >>= 2; + + if ((div & 0x3) == 0) + link_clk_div = 5; + else if ((div & 0x3) == 1) + link_clk_div = 10; + else if ((div & 0x3) == 2) + link_clk_div = 20; + else + pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div); + + if (link_clk_div == 20) { + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + } else { + if (hsclk_div == 6) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 4) + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (hsclk_div == 2) + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + vco_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000; + } + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(dp_res, false); + + dp_res->vco_cached_rate = vco->rate = vco_rate; + return (unsigned long)vco_rate; +} + +long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + + if (rate <= vco->min_rate) + rrate = vco->min_rate; + else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + rrate = vco->max_rate; + + pr_debug("%s: rrate=%ld\n", __func__, rrate); + + *parent_rate = rrate; + return rrate; +} + diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c new file mode 100644 index 0000000000000000000000000000000000000000..e30ef8251903b7ebf7e808e9baa81ac4635378a9 --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c @@ -0,0 +1,310 @@ +/* Copyright (c) 2016-2017, 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. + * + */ + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------------+ + * | DP_VCO_CLK | + * | | + * | +-------------------+ | + * | | (DP PLL/VCO) | | + * | +---------+---------+ | + * | v | + * | +----------+-----------+ | + * | | hsclk_divsel_clk_src | | + * | +----------+-----------+ | + * +------------------------------+ + * | + * +------------<---------v------------>----------+ + * | | + * +-----v------------+ | + * | dp_link_clk_src | | + * | divsel_ten | | + * +---------+--------+ | + * | | + * | | + * v v + * Input to DISPCC block | + * for link clk, crypto clk | + * and interface clock | + * | + * | + * +--------<------------+-----------------+---<---+ + * | | | + * +-------v------+ +--------v-----+ +--------v------+ + * | vco_divided | | vco_divided | | vco_divided | + * | _clk_src | | _clk_src | | _clk_src | + * | | | | | | + * |divsel_six | | divsel_two | | divsel_four | + * +-------+------+ +-----+--------+ +--------+------+ + * | | | + * v------->----------v-------------<------v + * | + * +----------+---------+ + * | vco_divided_clk | + * | _src_mux | + * +---------+----------+ + * | + * v + * Input to DISPCC block + * for DP pixel clock + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include + +#include "mdss-pll.h" +#include "mdss-dp-pll.h" +#include "mdss-dp-pll-10nm.h" + +static struct dp_pll_db dp_pdb; +static struct clk_ops mux_clk_ops; + +static struct regmap_config dp_pll_10nm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x910, +}; + +static struct regmap_bus dp_pixel_mux_regmap_ops = { + .reg_write = dp_mux_set_parent_10nm, + .reg_read = dp_mux_get_parent_10nm, +}; + +/* Op structures */ +static const struct clk_ops dp_10nm_vco_clk_ops = { + .recalc_rate = dp_vco_recalc_rate_10nm, + .set_rate = dp_vco_set_rate_10nm, + .round_rate = dp_vco_round_rate_10nm, + .prepare = dp_vco_prepare_10nm, + .unprepare = dp_vco_unprepare_10nm, +}; + +static struct dp_pll_vco_clk dp_vco_clk = { + .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000, + .max_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000, + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_clk", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &dp_10nm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor dp_link_clk_divsel_ten = { + .div = 10, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_link_clk_divsel_ten", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_six_clk_src = { + .div = 6, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_six_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + + +static int clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int ret = 0; + + ret = __clk_mux_determine_rate_closest(hw, req); + if (ret) + return ret; + + /* Set the new parent of mux if there is a new valid parent */ + if (hw->clk && req->best_parent_hw->clk) + clk_set_parent(hw->clk, req->best_parent_hw->clk); + + return 0; +} + +static unsigned long mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk *div_clk = NULL, *vco_clk = NULL; + struct dp_pll_vco_clk *vco = NULL; + + div_clk = clk_get_parent(hw->clk); + if (!div_clk) + return 0; + + vco_clk = clk_get_parent(div_clk); + if (!vco_clk) + return 0; + + vco = to_dp_vco_hw(__clk_get_hw(vco_clk)); + if (!vco) + return 0; + + if (vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) + return (vco->rate / 6); + else if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + return (vco->rate / 4); + else + return (vco->rate / 2); +} + +static struct clk_regmap_mux dp_vco_divided_clk_src_mux = { + .reg = 0x64, + .shift = 0, + .width = 2, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divided_clk_src_mux", + .parent_names = + (const char *[]){"dp_vco_divsel_two_clk_src", + "dp_vco_divsel_four_clk_src", + "dp_vco_divsel_six_clk_src"}, + .num_parents = 3, + .ops = &mux_clk_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + }, + }, +}; + +static struct clk_hw *mdss_dp_pllcc_10nm[] = { + [DP_VCO_CLK] = &dp_vco_clk.hw, + [DP_LINK_CLK_DIVSEL_TEN] = &dp_link_clk_divsel_ten.hw, + [DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw, + [DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw, + [DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw, + [DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_vco_divided_clk_src_mux.clkr.hw, +}; + +int dp_pll_clock_register_10nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i = 0; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dp_pllcc_10nm); + + if (!pdev || !pdev->dev.of_node) { + pr_err("Invalid input parameters\n"); + return -EINVAL; + } + + if (!pll_res || !pll_res->pll_base || !pll_res->phy_base || + !pll_res->ln_tx0_base || !pll_res->ln_tx1_base) { + pr_err("%s: Invalid input parameters\n", __func__); + return -EINVAL; + } + + 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; + + pll_res->priv = &dp_pdb; + dp_pdb.pll = pll_res; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops, + pll_res, &dp_pll_10nm_cfg); + dp_vco_divided_clk_src_mux.clkr.regmap = regmap; + mux_clk_ops = clk_regmap_mux_closest_ops; + mux_clk_ops.determine_rate = clk_mux_determine_rate; + mux_clk_ops.recalc_rate = mux_recalc_rate; + + dp_vco_clk.priv = pll_res; + + for (i = DP_VCO_CLK; i <= DP_VCO_DIVIDED_CLK_SRC_MUX; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dp_pllcc_10nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DP: %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_err("%s: Clock register failed rc=%d\n", __func__, rc); + rc = -EPROBE_DEFER; + } else { + pr_debug("%s SUCCESS\n", __func__); + } + return 0; +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-dp-pll-10nm.h b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h new file mode 100644 index 0000000000000000000000000000000000000000..c3b5635a55ae9790464bd529a3bbf0286e2ec8c6 --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2016-2017, 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_DP_PLL_10NM_H +#define __MDSS_DP_PLL_10NM_H + +#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL +#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL +#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL +#define DP_VCO_HSCLK_RATE_8100MHZDIV1000 8100000UL + +struct dp_pll_db { + struct mdss_pll_resources *pll; + + /* lane and orientation settings */ + u8 lane_cnt; + u8 orientation; + + /* COM PHY settings */ + u32 hsclk_sel; + u32 dec_start_mode0; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 integloop_gain0_mode0; + u32 integloop_gain1_mode0; + u32 vco_tune_map; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp3_mode0; + u32 lock_cmp_en; + + /* PHY vco divider */ + u32 phy_vco_div; +}; + +int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw, + unsigned long parent_rate); +long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int dp_vco_prepare_10nm(struct clk_hw *hw); +void dp_vco_unprepare_10nm(struct clk_hw *hw); +int dp_mux_set_parent_10nm(void *context, + unsigned int reg, unsigned int val); +int dp_mux_get_parent_10nm(void *context, + unsigned int reg, unsigned int *val); +#endif /* __MDSS_DP_PLL_10NM_H */ diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c deleted file mode 100644 index a3ed8a8bb84e0273dab89970e834b4ed1a449fa2..0000000000000000000000000000000000000000 --- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c +++ /dev/null @@ -1,774 +0,0 @@ -/* Copyright (c) 2016-2017, 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 -#include -#include -#include -#include - -#include "mdss-pll.h" -#include "mdss-dp-pll.h" -#include "mdss-dp-pll-8998.h" - -int link2xclk_divsel_set_div(struct div_clk *clk, int div) -{ - int rc; - u32 link2xclk_div_tx0, link2xclk_div_tx1; - u32 phy_mode; - struct mdss_pll_resources *dp_res = clk->priv; - - rc = mdss_pll_resource_enable(dp_res, true); - if (rc) { - pr_err("Failed to enable mdss DP PLL resources\n"); - return rc; - } - - link2xclk_div_tx0 = MDSS_PLL_REG_R(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_BAND); - link2xclk_div_tx1 = MDSS_PLL_REG_R(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_BAND); - - link2xclk_div_tx0 &= ~0x07; /* bits 0 to 2 */ - link2xclk_div_tx1 &= ~0x07; /* bits 0 to 2 */ - - /* Configure TX band Mux */ - link2xclk_div_tx0 |= 0x4; - link2xclk_div_tx1 |= 0x4; - - /*configure DP PHY MODE */ - phy_mode = 0x58; - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_BAND, - link2xclk_div_tx0); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_BAND, - link2xclk_div_tx1); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_MODE, phy_mode); - /* Make sure the PHY register writes are done */ - wmb(); - - pr_debug("%s: div=%d link2xclk_div_tx0=%x, link2xclk_div_tx1=%x\n", - __func__, div, link2xclk_div_tx0, link2xclk_div_tx1); - - mdss_pll_resource_enable(dp_res, false); - - return rc; -} - -int link2xclk_divsel_get_div(struct div_clk *clk) -{ - int rc; - u32 div = 0, phy_mode; - struct mdss_pll_resources *dp_res = clk->priv; - - rc = mdss_pll_resource_enable(dp_res, true); - if (rc) { - pr_err("Failed to enable dp_res resources\n"); - return rc; - } - - phy_mode = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_MODE); - - if (phy_mode & 0x48) - pr_err("%s: DP PAR Rate not correct\n", __func__); - - if ((phy_mode & 0x3) == 1) - div = 10; - else if ((phy_mode & 0x3) == 0) - div = 5; - else - pr_err("%s: unsupported div: %d\n", __func__, phy_mode); - - mdss_pll_resource_enable(dp_res, false); - pr_debug("%s: phy_mode=%d, div=%d\n", __func__, - phy_mode, div); - - return div; -} - -int vco_divided_clk_set_div(struct div_clk *clk, int div) -{ - int rc; - u32 auxclk_div; - struct mdss_pll_resources *dp_res = clk->priv; - - rc = mdss_pll_resource_enable(dp_res, true); - if (rc) { - pr_err("Failed to enable mdss DP PLL resources\n"); - return rc; - } - - auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); - auxclk_div &= ~0x03; /* bits 0 to 1 */ - - auxclk_div |= 1; /* Default divider */ - - if (div == 4) - auxclk_div |= 2; - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_VCO_DIV, auxclk_div); - /* Make sure the PHY registers writes are done */ - wmb(); - pr_debug("%s: div=%d auxclk_div=%x\n", __func__, div, auxclk_div); - - mdss_pll_resource_enable(dp_res, false); - - return rc; -} - - -enum handoff vco_divided_clk_handoff(struct clk *c) -{ - /* - * Since cont-splash is not enabled, disable handoff - * for vco_divider_clk. - */ - return HANDOFF_DISABLED_CLK; -} - -int vco_divided_clk_get_div(struct div_clk *clk) -{ - int rc; - u32 div, auxclk_div; - struct mdss_pll_resources *dp_res = clk->priv; - - rc = mdss_pll_resource_enable(dp_res, true); - if (rc) { - pr_err("Failed to enable dp_res resources\n"); - return rc; - } - - auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); - auxclk_div &= 0x03; - - div = 2; /* Default divider */ - if (auxclk_div == 2) - div = 4; - - mdss_pll_resource_enable(dp_res, false); - - pr_debug("%s: auxclk_div=%d, div=%d\n", __func__, auxclk_div, div); - - return div; -} - -int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate) -{ - u32 res = 0; - struct mdss_pll_resources *dp_res = vco->priv; - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_PD_CTL, 0x3d); - /* Make sure the PHY register writes are done */ - wmb(); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_SVS_MODE_CLK_SEL, 0x01); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_SYSCLK_EN_SEL, 0x37); - - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CLK_ENABLE1, 0x0e); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CLK_SEL, 0x30); - - /* Different for each clock rates */ - if (rate == DP_VCO_HSCLK_RATE_1620MHZDIV1000) { - pr_debug("%s: VCO rate: %ld\n", __func__, - DP_VCO_RATE_8100MHZDIV1000); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_SYS_CLK_CTRL, 0x02); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_HSCLK_SEL, 0x2c); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP_EN, 0x04); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DEC_START_MODE0, 0x69); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CMN_CONFIG, 0x42); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP1_MODE0, 0xbf); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP2_MODE0, 0x21); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP3_MODE0, 0x00); - } else if (rate == DP_VCO_HSCLK_RATE_2700MHZDIV1000) { - pr_debug("%s: VCO rate: %ld\n", __func__, - DP_VCO_RATE_8100MHZDIV1000); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_SYS_CLK_CTRL, 0x06); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_HSCLK_SEL, 0x84); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP_EN, 0x08); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DEC_START_MODE0, 0x69); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CMN_CONFIG, 0x02); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP1_MODE0, 0x3f); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP2_MODE0, 0x38); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP3_MODE0, 0x00); - } else if (rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) { - pr_debug("%s: VCO rate: %ld\n", __func__, - DP_VCO_RATE_10800MHZDIV1000); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_SYS_CLK_CTRL, 0x06); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_HSCLK_SEL, 0x80); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP_EN, 0x08); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DEC_START_MODE0, 0x8c); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_DIV_FRAC_START3_MODE0, 0xa0); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CMN_CONFIG, 0x12); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP1_MODE0, 0x7f); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP2_MODE0, 0x70); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_LOCK_CMP3_MODE0, 0x00); - } else { - pr_err("%s: unsupported rate: %ld\n", __func__, rate); - return -EINVAL; - } - /* Make sure the PLL register writes are done */ - wmb(); - - if ((rate == DP_VCO_HSCLK_RATE_1620MHZDIV1000) - || (rate == DP_VCO_HSCLK_RATE_2700MHZDIV1000)) { - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_VCO_DIV, 0x1); - } else { - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_VCO_DIV, 0x2); - } - /* Make sure the PHY register writes are done */ - wmb(); - - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_VCO_TUNE_MAP, 0x00); - - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_BG_TIMER, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_BG_TIMER, 0x0a); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CORECLK_DIV_MODE0, 0x05); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_VCO_TUNE_CTRL, 0x00); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CP_CTRL_MODE0, 0x06); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_PLL_CCTRL_MODE0, 0x36); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_PLL_RCTRL_MODE0, 0x16); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_PLL_IVCO, 0x07); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x37); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_CORE_CLK_EN, 0x0f); - - /* Make sure the PLL register writes are done */ - wmb(); - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_MODE, 0x58); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_TX0_TX1_LANE_CTL, 0x05); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_TX2_TX3_LANE_CTL, 0x05); - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, - 0x1a); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, - 0x1a); - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_VMODE_CTRL1, - 0x40); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_VMODE_CTRL1, - 0x40); - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN, - 0x30); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN, - 0x30); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_INTERFACE_SELECT, - 0x3d); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_INTERFACE_SELECT, - 0x3d); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE, - 0x0f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE, - 0x0f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_RESET_TSYNC_EN, - 0x03); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_RESET_TSYNC_EN, - 0x03); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TRAN_DRVR_EMP_EN, - 0x03); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TRAN_DRVR_EMP_EN, - 0x03); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN, - 0x00); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN, - 0x00); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_INTERFACE_MODE, - 0x00); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_INTERFACE_MODE, - 0x00); - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_BAND, - 0x4); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_BAND, - 0x4); - /* Make sure the PHY register writes are done */ - wmb(); - return res; -} - -static bool dp_pll_lock_status(struct mdss_pll_resources *dp_res) -{ - u32 status; - bool pll_locked; - - /* poll for PLL ready status */ - if (readl_poll_timeout_atomic((dp_res->pll_base + - QSERDES_COM_C_READY_STATUS), - status, - ((status & BIT(0)) > 0), - DP_PLL_POLL_SLEEP_US, - DP_PLL_POLL_TIMEOUT_US)) { - pr_err("%s: C_READY status is not high. Status=%x\n", - __func__, status); - pll_locked = false; - } else if (readl_poll_timeout_atomic((dp_res->pll_base + - DP_PHY_STATUS), - status, - ((status & BIT(1)) > 0), - DP_PLL_POLL_SLEEP_US, - DP_PLL_POLL_TIMEOUT_US)) { - pr_err("%s: Phy_ready is not high. Status=%x\n", - __func__, status); - pll_locked = false; - } else { - pll_locked = true; - } - - return pll_locked; -} - - -static int dp_pll_enable(struct clk *c) -{ - int rc = 0; - u32 status; - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - struct mdss_pll_resources *dp_res = vco->priv; - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x01); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x05); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x01); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x09); - /* Make sure the PHY register writes are done */ - wmb(); - MDSS_PLL_REG_W(dp_res->pll_base, - QSERDES_COM_RESETSM_CNTRL, 0x20); - /* Make sure the PLL register writes are done */ - wmb(); - /* poll for PLL ready status */ - if (readl_poll_timeout_atomic((dp_res->pll_base + - QSERDES_COM_C_READY_STATUS), - status, - ((status & BIT(0)) > 0), - DP_PLL_POLL_SLEEP_US, - DP_PLL_POLL_TIMEOUT_US)) { - pr_err("%s: C_READY status is not high. Status=%x\n", - __func__, status); - rc = -EINVAL; - goto lock_err; - } - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x19); - /* Make sure the PHY register writes are done */ - wmb(); - /* poll for PHY ready status */ - if (readl_poll_timeout_atomic((dp_res->phy_base + - DP_PHY_STATUS), - status, - ((status & BIT(1)) > 0), - DP_PLL_POLL_SLEEP_US, - DP_PLL_POLL_TIMEOUT_US)) { - pr_err("%s: Phy_ready is not high. Status=%x\n", - __func__, status); - rc = -EINVAL; - goto lock_err; - } - - pr_debug("%s: PLL is locked\n", __func__); - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, - 0x3f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, - 0x10); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, - 0x3f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, - 0x10); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_POL_INV, - 0x0a); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_POL_INV, - 0x0a); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x18); - udelay(2000); - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x19); - - /* - * Make sure all the register writes are completed before - * doing any other operation - */ - wmb(); - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_LANE_MODE_1, - 0xf6); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_LANE_MODE_1, - 0xf6); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE, - 0x1f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE, - 0x1f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE, - 0x0f); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE, - 0x0f); - /* - * Make sure all the register writes are completed before - * doing any other operation - */ - wmb(); - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x09); - udelay(2000); - - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_CFG, 0x19); - udelay(2000); - /* poll for PHY ready status */ - if (readl_poll_timeout_atomic((dp_res->phy_base + - DP_PHY_STATUS), - status, - ((status & BIT(1)) > 0), - DP_PLL_POLL_SLEEP_US, - DP_PLL_POLL_TIMEOUT_US)) { - pr_err("%s: Lane_mode: Phy_ready is not high. Status=%x\n", - __func__, status); - rc = -EINVAL; - goto lock_err; - } - - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_DRV_LVL, - 0x2a); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_DRV_LVL, - 0x2a); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TX_EMP_POST1_LVL, - 0x20); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL, - 0x20); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX, - 0x11); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX, - 0x11); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX, - 0x11); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX, - 0x11); - /* Make sure the PHY register writes are done */ - wmb(); - -lock_err: - return rc; -} - -static int dp_pll_disable(struct clk *c) -{ - int rc = 0; - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - struct mdss_pll_resources *dp_res = vco->priv; - - /* Assert DP PHY power down */ - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_PD_CTL, 0x2); - /* - * Make sure all the register writes to disable PLL are - * completed before doing any other operation - */ - wmb(); - - return rc; -} - - -int dp_vco_prepare(struct clk *c) -{ - int rc = 0; - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - struct mdss_pll_resources *dp_pll_res = vco->priv; - - DEV_DBG("rate=%ld\n", vco->rate); - rc = mdss_pll_resource_enable(dp_pll_res, true); - if (rc) { - pr_err("Failed to enable mdss DP pll resources\n"); - goto error; - } - - rc = dp_pll_enable(c); - if (rc) { - mdss_pll_resource_enable(dp_pll_res, false); - pr_err("ndx=%d failed to enable dsi pll\n", - dp_pll_res->index); - goto error; - } - - mdss_pll_resource_enable(dp_pll_res, false); -error: - return rc; -} - -void dp_vco_unprepare(struct clk *c) -{ - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - struct mdss_pll_resources *io = vco->priv; - - if (!io) { - DEV_ERR("Invalid input parameter\n"); - return; - } - - if (!io->pll_on && - mdss_pll_resource_enable(io, true)) { - DEV_ERR("pll resource can't be enabled\n"); - return; - } - dp_pll_disable(c); - - io->handoff_resources = false; - mdss_pll_resource_enable(io, false); - io->pll_on = false; -} - -int dp_vco_set_rate(struct clk *c, unsigned long rate) -{ - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - struct mdss_pll_resources *io = vco->priv; - int rc; - - rc = mdss_pll_resource_enable(io, true); - if (rc) { - DEV_ERR("pll resource can't be enabled\n"); - return rc; - } - - DEV_DBG("DP lane CLK rate=%ld\n", rate); - - rc = dp_config_vco_rate(vco, rate); - if (rc) - DEV_ERR("%s: Failed to set clk rate\n", __func__); - - mdss_pll_resource_enable(io, false); - - vco->rate = rate; - - return 0; -} - -unsigned long dp_vco_get_rate(struct clk *c) -{ - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - int rc; - u32 div, hsclk_div, link2xclk_div; - u64 vco_rate; - struct mdss_pll_resources *pll = vco->priv; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable mdss DP pll=%d\n", pll->index); - return rc; - } - - div = MDSS_PLL_REG_R(pll->pll_base, QSERDES_COM_HSCLK_SEL); - div &= 0x0f; - - if (div == 12) - hsclk_div = 5; /* Default */ - else if (div == 4) - hsclk_div = 3; - else if (div == 0) - hsclk_div = 2; - else { - pr_debug("unknown divider. forcing to default\n"); - hsclk_div = 5; - } - - div = MDSS_PLL_REG_R(pll->phy_base, DP_PHY_MODE); - - if (div & 0x58) - pr_err("%s: DP PAR Rate not correct\n", __func__); - - if ((div & 0x3) == 1) - link2xclk_div = 10; - else if ((div & 0x3) == 0) - link2xclk_div = 5; - else - pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div); - - if (link2xclk_div == 10) { - vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; - } else { - if (hsclk_div == 5) - vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; - else if (hsclk_div == 3) - vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; - else - vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; - } - - pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); - - mdss_pll_resource_enable(pll, false); - - return (unsigned long)vco_rate; -} - -long dp_vco_round_rate(struct clk *c, unsigned long rate) -{ - unsigned long rrate = rate; - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - - if (rate <= vco->min_rate) - rrate = vco->min_rate; - else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) - rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; - else - rrate = vco->max_rate; - - pr_debug("%s: rrate=%ld\n", __func__, rrate); - - return rrate; -} - -enum handoff dp_vco_handoff(struct clk *c) -{ - enum handoff ret = HANDOFF_DISABLED_CLK; - struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); - struct mdss_pll_resources *io = vco->priv; - - if (mdss_pll_resource_enable(io, true)) { - DEV_ERR("pll resource can't be enabled\n"); - return ret; - } - - if (dp_pll_lock_status(io)) { - io->pll_on = true; - c->rate = dp_vco_get_rate(c); - io->handoff_resources = true; - ret = HANDOFF_ENABLED_CLK; - } else { - io->handoff_resources = false; - mdss_pll_resource_enable(io, false); - DEV_DBG("%s: PLL not locked\n", __func__); - } - - DEV_DBG("done, ret=%d\n", ret); - return ret; -} diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c b/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c deleted file mode 100644 index 6a49d156395e1d5b102487c66ddf28af7a3a2ec8..0000000000000000000000000000000000000000 --- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c +++ /dev/null @@ -1,224 +0,0 @@ -/* Copyright (c) 2016-2017, 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. - * - */ - -/* - *************************************************************************** - ******** Display Port PLL driver block diagram for branch clocks ********** - *************************************************************************** - - +--------------------------+ - | DP_VCO_CLK | - | | - | +-------------------+ | - | | (DP PLL/VCO) | | - | +---------+---------+ | - | v | - | +----------+-----------+ | - | | hsclk_divsel_clk_src | | - | +----------+-----------+ | - +--------------------------+ - | - v - +------------<------------|------------>-------------+ - | | | -+----------v----------+ +----------v----------+ +----------v----------+ -| dp_link_2x_clk | | vco_divided_clk_src | | vco_divided_clk_src | -| divsel_five | | | | | -v----------+----------v | divsel_two | | divsel_four | - | +----------+----------+ +----------+----------+ - | | | - v v v - | +---------------------+ | - Input to MMSSCC block | | (aux_clk_ops) | | - for link clk, crypto clk +--> vco_divided_clk <-+ - and interface clock | _src_mux | - +----------+----------+ - | - v - Input to MMSSCC block - for DP pixel clock - - ****************************************************************************** - */ - -#define pr_fmt(fmt) "%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include - -#include "mdss-pll.h" -#include "mdss-dp-pll.h" -#include "mdss-dp-pll-8998.h" - -static const struct clk_ops clk_ops_vco_divided_clk_src_c; -static const struct clk_ops clk_ops_link_2x_clk_div_c; -static const struct clk_ops clk_ops_gen_mux_dp; - -static struct clk_div_ops link2xclk_divsel_ops = { - .set_div = link2xclk_divsel_set_div, - .get_div = link2xclk_divsel_get_div, -}; - -static struct clk_div_ops vco_divided_clk_ops = { - .set_div = vco_divided_clk_set_div, - .get_div = vco_divided_clk_get_div, -}; - -static const struct clk_ops dp_8998_vco_clk_ops = { - .set_rate = dp_vco_set_rate, - .round_rate = dp_vco_round_rate, - .prepare = dp_vco_prepare, - .unprepare = dp_vco_unprepare, - .handoff = dp_vco_handoff, -}; - -static struct clk_mux_ops mdss_mux_ops = { - .set_mux_sel = mdss_set_mux_sel, - .get_mux_sel = mdss_get_mux_sel, -}; - -static struct dp_pll_vco_clk dp_vco_clk = { - .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000, - .max_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000, - .c = { - .dbg_name = "dp_vco_clk", - .ops = &dp_8998_vco_clk_ops, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dp_vco_clk.c), - }, -}; - -static struct div_clk dp_link_2x_clk_divsel_five = { - .data = { - .div = 5, - .min_div = 5, - .max_div = 5, - }, - .ops = &link2xclk_divsel_ops, - .c = { - .parent = &dp_vco_clk.c, - .dbg_name = "dp_link_2x_clk_divsel_five", - .ops = &clk_ops_link_2x_clk_div_c, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(dp_link_2x_clk_divsel_five.c), - }, -}; - -static struct div_clk vco_divsel_four_clk_src = { - .data = { - .div = 4, - .min_div = 4, - .max_div = 4, - }, - .ops = &vco_divided_clk_ops, - .c = { - .parent = &dp_vco_clk.c, - .dbg_name = "vco_divsel_four_clk_src", - .ops = &clk_ops_vco_divided_clk_src_c, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(vco_divsel_four_clk_src.c), - }, -}; - -static struct div_clk vco_divsel_two_clk_src = { - .data = { - .div = 2, - .min_div = 2, - .max_div = 2, - }, - .ops = &vco_divided_clk_ops, - .c = { - .parent = &dp_vco_clk.c, - .dbg_name = "vco_divsel_two_clk_src", - .ops = &clk_ops_vco_divided_clk_src_c, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(vco_divsel_two_clk_src.c), - }, -}; - -static struct mux_clk vco_divided_clk_src_mux = { - .num_parents = 2, - .parents = (struct clk_src[]) { - {&vco_divsel_two_clk_src.c, 0}, - {&vco_divsel_four_clk_src.c, 1}, - }, - .ops = &mdss_mux_ops, - .c = { - .parent = &vco_divsel_two_clk_src.c, - .dbg_name = "vco_divided_clk_src_mux", - .ops = &clk_ops_gen_mux_dp, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(vco_divided_clk_src_mux.c), - } -}; - -static struct clk_lookup dp_pllcc_8998[] = { - CLK_LIST(dp_vco_clk), - CLK_LIST(dp_link_2x_clk_divsel_five), - CLK_LIST(vco_divsel_four_clk_src), - CLK_LIST(vco_divsel_two_clk_src), - CLK_LIST(vco_divided_clk_src_mux), -}; - -int dp_pll_clock_register_8998(struct platform_device *pdev, - struct mdss_pll_resources *pll_res) -{ - int rc = -ENOTSUPP; - - if (!pll_res || !pll_res->pll_base || !pll_res->phy_base) { - DEV_ERR("%s: Invalid input parameters\n", __func__); - return -EINVAL; - } - - /* Set client data for vco, mux and div clocks */ - dp_vco_clk.priv = pll_res; - vco_divided_clk_src_mux.priv = pll_res; - vco_divsel_two_clk_src.priv = pll_res; - vco_divsel_four_clk_src.priv = pll_res; - dp_link_2x_clk_divsel_five.priv = pll_res; - - clk_ops_link_2x_clk_div_c = clk_ops_div; - clk_ops_link_2x_clk_div_c.prepare = mdss_pll_div_prepare; - - /* - * Set the ops for the divider in the pixel clock tree to the - * slave_div to ensure that a set rate on this divider clock will not - * be propagated to it's parent. This is needed ensure that when we set - * the rate for pixel clock, the vco is not reconfigured - */ - clk_ops_vco_divided_clk_src_c = clk_ops_slave_div; - clk_ops_vco_divided_clk_src_c.prepare = mdss_pll_div_prepare; - clk_ops_vco_divided_clk_src_c.handoff = vco_divided_clk_handoff; - - clk_ops_gen_mux_dp = clk_ops_gen_mux; - clk_ops_gen_mux_dp.get_rate = parent_get_rate; - - /* We can select different clock ops for future versions */ - dp_vco_clk.c.ops = &dp_8998_vco_clk_ops; - - rc = of_msm_clock_register(pdev->dev.of_node, dp_pllcc_8998, - ARRAY_SIZE(dp_pllcc_8998)); - if (rc) { - DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc); - rc = -EPROBE_DEFER; - } else { - DEV_DBG("%s SUCCESS\n", __func__); - } - - return rc; -} diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h b/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h deleted file mode 100644 index 11d5ddc5ae196bb9452a8f12774643a55bf2f401..0000000000000000000000000000000000000000 --- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2016-2017, 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_DP_PLL_8998_H -#define __MDSS_DP_PLL_8998_H - -#define DP_PHY_REVISION_ID0 0x0000 -#define DP_PHY_REVISION_ID1 0x0004 -#define DP_PHY_REVISION_ID2 0x0008 -#define DP_PHY_REVISION_ID3 0x000C - -#define DP_PHY_CFG 0x0010 -#define DP_PHY_PD_CTL 0x0014 -#define DP_PHY_MODE 0x0018 - -#define DP_PHY_AUX_CFG0 0x001C -#define DP_PHY_AUX_CFG1 0x0020 -#define DP_PHY_AUX_CFG2 0x0024 -#define DP_PHY_AUX_CFG3 0x0028 -#define DP_PHY_AUX_CFG4 0x002C -#define DP_PHY_AUX_CFG5 0x0030 -#define DP_PHY_AUX_CFG6 0x0034 -#define DP_PHY_AUX_CFG7 0x0038 -#define DP_PHY_AUX_CFG8 0x003C -#define DP_PHY_AUX_CFG9 0x0040 -#define DP_PHY_AUX_INTERRUPT_MASK 0x0044 -#define DP_PHY_AUX_INTERRUPT_CLEAR 0x0048 -#define DP_PHY_AUX_BIST_CFG 0x004C - -#define DP_PHY_VCO_DIV 0x0064 -#define DP_PHY_TX0_TX1_LANE_CTL 0x0068 - -#define DP_PHY_TX2_TX3_LANE_CTL 0x0084 -#define DP_PHY_STATUS 0x00BC - -/* Tx registers */ -#define QSERDES_TX0_OFFSET 0x0400 -#define QSERDES_TX1_OFFSET 0x0800 - -#define TXn_BIST_MODE_LANENO 0x0000 -#define TXn_CLKBUF_ENABLE 0x0008 -#define TXn_TX_EMP_POST1_LVL 0x000C - -#define TXn_TX_DRV_LVL 0x001C - -#define TXn_RESET_TSYNC_EN 0x0024 -#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028 -#define TXn_TX_BAND 0x002C -#define TXn_SLEW_CNTL 0x0030 -#define TXn_INTERFACE_SELECT 0x0034 - -#define TXn_RES_CODE_LANE_TX 0x003C -#define TXn_RES_CODE_LANE_RX 0x0040 -#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044 -#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048 - -#define TXn_DEBUG_BUS_SEL 0x0058 -#define TXn_TRANSCEIVER_BIAS_EN 0x005C -#define TXn_HIGHZ_DRVR_EN 0x0060 -#define TXn_TX_POL_INV 0x0064 -#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068 - -#define TXn_LANE_MODE_1 0x008C - -#define TXn_TRAN_DRVR_EMP_EN 0x00C0 -#define TXn_TX_INTERFACE_MODE 0x00C4 - -#define TXn_VMODE_CTRL1 0x00F0 - - -/* PLL register offset */ -#define QSERDES_COM_ATB_SEL1 0x0000 -#define QSERDES_COM_ATB_SEL2 0x0004 -#define QSERDES_COM_FREQ_UPDATE 0x0008 -#define QSERDES_COM_BG_TIMER 0x000C -#define QSERDES_COM_SSC_EN_CENTER 0x0010 -#define QSERDES_COM_SSC_ADJ_PER1 0x0014 -#define QSERDES_COM_SSC_ADJ_PER2 0x0018 -#define QSERDES_COM_SSC_PER1 0x001C -#define QSERDES_COM_SSC_PER2 0x0020 -#define QSERDES_COM_SSC_STEP_SIZE1 0x0024 -#define QSERDES_COM_SSC_STEP_SIZE2 0x0028 -#define QSERDES_COM_POST_DIV 0x002C -#define QSERDES_COM_POST_DIV_MUX 0x0030 -#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034 -#define QSERDES_COM_CLK_ENABLE1 0x0038 -#define QSERDES_COM_SYS_CLK_CTRL 0x003C -#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040 -#define QSERDES_COM_PLL_EN 0x0044 -#define QSERDES_COM_PLL_IVCO 0x0048 -#define QSERDES_COM_CMN_IETRIM 0x004C -#define QSERDES_COM_CMN_IPTRIM 0x0050 - -#define QSERDES_COM_CP_CTRL_MODE0 0x0060 -#define QSERDES_COM_CP_CTRL_MODE1 0x0064 -#define QSERDES_COM_PLL_RCTRL_MODE0 0x0068 -#define QSERDES_COM_PLL_RCTRL_MODE1 0x006C -#define QSERDES_COM_PLL_CCTRL_MODE0 0x0070 -#define QSERDES_COM_PLL_CCTRL_MODE1 0x0074 -#define QSERDES_COM_PLL_CNTRL 0x0078 -#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x007C -#define QSERDES_COM_SYSCLK_EN_SEL 0x0080 -#define QSERDES_COM_CML_SYSCLK_SEL 0x0084 -#define QSERDES_COM_RESETSM_CNTRL 0x0088 -#define QSERDES_COM_RESETSM_CNTRL2 0x008C -#define QSERDES_COM_LOCK_CMP_EN 0x0090 -#define QSERDES_COM_LOCK_CMP_CFG 0x0094 -#define QSERDES_COM_LOCK_CMP1_MODE0 0x0098 -#define QSERDES_COM_LOCK_CMP2_MODE0 0x009C -#define QSERDES_COM_LOCK_CMP3_MODE0 0x00A0 - -#define QSERDES_COM_DEC_START_MODE0 0x00B0 -#define QSERDES_COM_DEC_START_MODE1 0x00B4 -#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00B8 -#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00BC -#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00C0 -#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x00C4 -#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x00C8 -#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x00CC -#define QSERDES_COM_INTEGLOOP_INITVAL 0x00D0 -#define QSERDES_COM_INTEGLOOP_EN 0x00D4 -#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00D8 -#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00DC -#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x00E0 -#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x00E4 -#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x00E8 -#define QSERDES_COM_VCO_TUNE_CTRL 0x00EC -#define QSERDES_COM_VCO_TUNE_MAP 0x00F0 - -#define QSERDES_COM_CMN_STATUS 0x0124 -#define QSERDES_COM_RESET_SM_STATUS 0x0128 - -#define QSERDES_COM_CLK_SEL 0x0138 -#define QSERDES_COM_HSCLK_SEL 0x013C - -#define QSERDES_COM_CORECLK_DIV_MODE0 0x0148 - -#define QSERDES_COM_SW_RESET 0x0150 -#define QSERDES_COM_CORE_CLK_EN 0x0154 -#define QSERDES_COM_C_READY_STATUS 0x0158 -#define QSERDES_COM_CMN_CONFIG 0x015C - -#define QSERDES_COM_SVS_MODE_CLK_SEL 0x0164 - -#define DP_PLL_POLL_SLEEP_US 500 -#define DP_PLL_POLL_TIMEOUT_US 10000 - -#define DP_VCO_RATE_8100MHZDIV1000 8100000UL -#define DP_VCO_RATE_10800MHZDIV1000 10800000UL - -#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL -#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL -#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL - -int dp_vco_set_rate(struct clk *c, unsigned long rate); -unsigned long dp_vco_get_rate(struct clk *c); -long dp_vco_round_rate(struct clk *c, unsigned long rate); -enum handoff dp_vco_handoff(struct clk *c); -enum handoff vco_divided_clk_handoff(struct clk *c); -int dp_vco_prepare(struct clk *c); -void dp_vco_unprepare(struct clk *c); -int hsclk_divsel_set_div(struct div_clk *clk, int div); -int hsclk_divsel_get_div(struct div_clk *clk); -int link2xclk_divsel_set_div(struct div_clk *clk, int div); -int link2xclk_divsel_get_div(struct div_clk *clk); -int vco_divided_clk_set_div(struct div_clk *clk, int div); -int vco_divided_clk_get_div(struct div_clk *clk); - -#endif /* __MDSS_DP_PLL_8998_H */ diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll.h b/drivers/clk/qcom/mdss/mdss-dp-pll.h index 2805ff9b8c5008962d8ebba8d065a14978c0356f..2b1d70ea8f2a1926cc72f9e4f5153efad6c088d4 100644 --- a/drivers/clk/qcom/mdss/mdss-dp-pll.h +++ b/drivers/clk/qcom/mdss/mdss-dp-pll.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,21 +15,19 @@ #define __MDSS_DP_PLL_H struct dp_pll_vco_clk { + struct clk_hw hw; unsigned long rate; /* current vco rate */ u64 min_rate; /* min vco rate */ u64 max_rate; /* max vco rate */ void *priv; - - struct clk c; }; -static inline struct dp_pll_vco_clk *mdss_dp_to_vco_clk(struct clk *clk) +static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw) { - return container_of(clk, struct dp_pll_vco_clk, c); + return container_of(hw, struct dp_pll_vco_clk, hw); } -int dp_pll_clock_register_8998(struct platform_device *pdev, +int dp_pll_clock_register_10nm(struct platform_device *pdev, struct mdss_pll_resources *pll_res); - #endif /* __MDSS_DP_PLL_H */ diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c index 9ce0afc5e8df16fa8b263dc2e8438ecac9a83ace..3f9fcd98815c20c4b16ed2d776a36f2800533fbe 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c @@ -33,24 +33,52 @@ /* Register Offsets from PLL base address */ #define PLL_ANALOG_CONTROLS_ONE 0x000 #define PLL_ANALOG_CONTROLS_TWO 0x004 +#define PLL_INT_LOOP_SETTINGS 0x008 +#define PLL_INT_LOOP_SETTINGS_TWO 0x00c #define PLL_ANALOG_CONTROLS_THREE 0x010 +#define PLL_ANALOG_CONTROLS_FOUR 0x014 +#define PLL_INT_LOOP_CONTROLS 0x018 #define PLL_DSM_DIVIDER 0x01c #define PLL_FEEDBACK_DIVIDER 0x020 #define PLL_SYSTEM_MUXES 0x024 +#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028 #define PLL_CMODE 0x02c #define PLL_CALIBRATION_SETTINGS 0x030 +#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034 +#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038 +#define PLL_BAND_SEL_CAL_SETTINGS 0x03c +#define PLL_BAND_SEL_MIN 0x040 +#define PLL_BAND_SEL_MAX 0x044 +#define PLL_BAND_SEL_PFILT 0x048 +#define PLL_BAND_SEL_IFILT 0x04c +#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050 #define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054 +#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058 +#define PLL_BAND_SEL_ICODE_HIGH 0x05c +#define PLL_BAND_SEL_ICODE_LOW 0x060 #define PLL_FREQ_DETECT_SETTINGS_ONE 0x064 #define PLL_PFILT 0x07c #define PLL_IFILT 0x080 +#define PLL_GAIN 0x084 +#define PLL_ICODE_LOW 0x088 +#define PLL_ICODE_HIGH 0x08c +#define PLL_LOCKDET 0x090 #define PLL_OUTDIV 0x094 +#define PLL_FASTLOCK_CONTROL 0x098 +#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c +#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0 #define PLL_CORE_OVERRIDE 0x0a4 #define PLL_CORE_INPUT_OVERRIDE 0x0a8 +#define PLL_RATE_CHANGE 0x0ac +#define PLL_PLL_DIGITAL_TIMERS 0x0b0 #define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4 +#define PLL_DEC_FRAC_MUXES 0x0c8 #define PLL_DECIMAL_DIV_START_1 0x0cc #define PLL_FRAC_DIV_START_LOW_1 0x0d0 #define PLL_FRAC_DIV_START_MID_1 0x0d4 #define PLL_FRAC_DIV_START_HIGH_1 0x0d8 +#define PLL_MASH_CONTROL 0x0ec +#define PLL_SSC_MUX_CONTROL 0x108 #define PLL_SSC_STEPSIZE_LOW_1 0x10c #define PLL_SSC_STEPSIZE_HIGH_1 0x110 #define PLL_SSC_DIV_PER_LOW_1 0x114 @@ -64,9 +92,16 @@ #define PLL_PLL_BAND_SET_RATE_1 0x154 #define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c #define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164 +#define PLL_FASTLOCK_EN_BAND 0x16c +#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c #define PLL_PLL_LOCK_OVERRIDE 0x180 #define PLL_PLL_LOCK_DELAY 0x184 +#define PLL_PLL_LOCK_MIN_DELAY 0x188 #define PLL_CLOCK_INVERTERS 0x18c +#define PLL_SPARE_AND_JPC_OVERRIDES 0x190 +#define PLL_BIAS_CONTROL_1 0x194 +#define PLL_BIAS_CONTROL_2 0x198 +#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c #define PLL_COMMON_STATUS_ONE 0x1a0 /* Register Offsets from PHY base address */ @@ -94,7 +129,6 @@ enum { struct dsi_pll_regs { u32 pll_prop_gain_rate; - u32 pll_outdiv_rate; u32 pll_lockdet_rate; u32 decimal_div_start; u32 frac_div_start_low; @@ -134,6 +168,173 @@ struct dsi_pll_10nm { struct dsi_pll_regs reg_setup; }; +static inline int pll_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *val = MDSS_PLL_REG_R(rsc->pll_base, reg); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int pll_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + MDSS_PLL_REG_W(rsc->pll_base, reg, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *val = MDSS_PLL_REG_R(rsc->phy_base, reg); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + MDSS_PLL_REG_W(rsc->phy_base, reg, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_update_bits_sub(struct mdss_pll_resources *rsc, + unsigned int reg, unsigned int mask, unsigned int val) +{ + u32 reg_val; + int rc = 0; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg); + reg_val &= ~mask; + reg_val |= (val & mask); + MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val); + + return rc; +} + +static inline int phy_reg_update_bits(void *context, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + rc = phy_reg_update_bits_sub(rsc, reg, mask, val); + if (!rc && rsc->slave) + rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int pclk_mux_read_sel(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + else + *val = (MDSS_PLL_REG_R(rsc->phy_base, reg) & 0x3); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + + +static inline int pclk_mux_write_sel_sub(struct mdss_pll_resources *rsc, + unsigned int reg, unsigned int val) +{ + u32 reg_val; + int rc = 0; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg); + reg_val &= ~0x03; + reg_val |= val; + + MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val); + + return rc; +} + +static inline int pclk_mux_write_sel(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + rc = pclk_mux_write_sel_sub(rsc, reg, val); + if (!rc && rsc->slave) + rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); + + (void)mdss_pll_resource_enable(rsc, false); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + rsc->cached_cfg1 = val; + + return rc; +} + static struct mdss_pll_resources *pll_rsc_db[DSI_PLL_MAX]; static struct dsi_pll_10nm plls[DSI_PLL_MAX]; @@ -203,54 +404,14 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll, { struct dsi_pll_config *config = &pll->pll_configuration; struct dsi_pll_regs *regs = &pll->reg_setup; - u64 target_freq; u64 fref = rsc->vco_ref_clk_rate; - u32 computed_output_div, div_log = 0; u64 pll_freq; u64 divider; u64 dec, dec_multiple; u32 frac; u64 multiplier; - u32 i; - - target_freq = rsc->vco_current_rate; - pr_debug("target_freq = %llu\n", target_freq); - if (config->div_override) { - computed_output_div = config->output_div; - - /* - * Computed_output_div = 2 ^ div_log - * To get div_log from output div just get the index of the - * 1 bit in the value. - * div_log ranges from 0-3. so check the 4 lsbs - */ - - for (i = 0; i < 4; i++) { - if (computed_output_div & (1 << i)) { - div_log = i; - break; - } - } - - } else { - if (target_freq < MHZ_250) { - computed_output_div = 8; - div_log = 3; - } else if (target_freq < MHZ_500) { - computed_output_div = 4; - div_log = 2; - } else if (target_freq < MHZ_1000) { - computed_output_div = 2; - div_log = 1; - } else { - computed_output_div = 1; - div_log = 0; - } - } - pr_debug("computed_output_div = %d\n", computed_output_div); - - pll_freq = target_freq * computed_output_div; + pll_freq = rsc->vco_current_rate; if (config->disable_prescaler) divider = fref; @@ -274,7 +435,6 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll, else regs->pll_clock_inverters = 0; - regs->pll_outdiv_rate = div_log; regs->pll_lockdet_rate = config->lock_timer; regs->decimal_div_start = dec; regs->frac_div_start_low = (frac & 0xff); @@ -378,6 +538,49 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll, MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f); } +static void dsi_pll_init_val(struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19); + MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20); + MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0); +} + static void dsi_pll_commit(struct dsi_pll_10nm *pll, struct mdss_pll_resources *rsc) { @@ -394,7 +597,6 @@ static void dsi_pll_commit(struct dsi_pll_10nm *pll, MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1, reg->frac_div_start_high); MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40); - MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate); MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06); MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10); MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters); @@ -435,6 +637,8 @@ static int vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, return rc; } + dsi_pll_init_val(rsc); + dsi_pll_setup_config(pll, rsc); dsi_pll_calc_dec_frac(pll, rsc); @@ -517,6 +721,12 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) if (rsc->slave) dsi_pll_enable_pll_bias(rsc->slave); + phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1); + if (rsc->slave) + phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1, + 0x03, rsc->cached_cfg1); + wmb(); /* ensure dsiclk_sel is always programmed before pll start */ + /* Start PLL */ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); @@ -549,7 +759,6 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc) { - dsi_pll_disable_global_clk(rsc); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0); dsi_pll_disable_pll_bias(rsc); } @@ -568,11 +777,20 @@ static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) pr_debug("stop PLL (%d)\n", rsc->index); + /* + * To avoid any stray glitches while + * abruptly powering down the PLL + * make sure to gate the clock using + * the clock enable bit before powering + * down the PLL + */ + dsi_pll_disable_global_clk(rsc); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0); dsi_pll_disable_sub(rsc); - if (rsc->slave) + if (rsc->slave) { + dsi_pll_disable_global_clk(rsc->slave); dsi_pll_disable_sub(rsc->slave); - + } /* flush, ensure all register writes are done*/ wmb(); rsc->pll_on = false; @@ -604,7 +822,31 @@ static void vco_10nm_unprepare(struct clk_hw *hw) return; } - pll->vco_cached_rate = clk_hw_get_rate(hw); + /* + * During unprepare in continuous splash use case we want driver + * to pick all dividers instead of retaining bootloader configurations. + */ + if (!pll->handoff_resources) { + pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, + PHY_CMN_CLK_CFG0); + pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, + PLL_PLL_OUTDIV_RATE); + pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0, + pll->cached_cfg1, pll->cached_outdiv); + + pll->vco_cached_rate = clk_hw_get_rate(hw); + } + + /* + * When continuous splash screen feature is enabled, we need to cache + * the mux configuration for the pixel_clk_src mux clock. The clock + * framework does not call back to re-configure the mux value if it is + * does not change.For such usecases, we need to ensure that the cached + * value is programmed prior to PLL being locked + */ + if (pll->handoff_resources) + pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base, + PHY_CMN_CLK_CFG1); dsi_pll_disable(vco); mdss_pll_resource_enable(pll, false); } @@ -620,6 +862,10 @@ static int vco_10nm_prepare(struct clk_hw *hw) return -EINVAL; } + /* Skip vco recalculation for continuous splash use case */ + if (pll->handoff_resources == true) + return 0; + rc = mdss_pll_resource_enable(pll, true); if (rc) { pr_err("failed to enable pll (%d) resource, rc=%d\n", @@ -637,6 +883,12 @@ static int vco_10nm_prepare(struct clk_hw *hw) mdss_pll_resource_enable(pll, false); return rc; } + pr_debug("cfg0=%d, cfg1=%d\n", pll->cached_cfg0, + pll->cached_cfg1); + MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, + pll->cached_cfg0); + MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, + pll->cached_outdiv); } rc = dsi_pll_enable(vco); @@ -666,6 +918,19 @@ static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw, if (!vco->priv) pr_err("vco priv is null\n"); + /* + * Calculate the vco rate from HW registers only for handoff cases. + * For other cases where a vco_10nm_set_rate() has already been + * called, just return the rate that was set earlier. This is due + * to the fact that recalculating VCO rate requires us to read the + * correct value of the pll_out_div divider clock, which is only set + * afterwards. + */ + if (pll->vco_current_rate != 0) { + pr_debug("returning vco rate = %lld\n", pll->vco_current_rate); + return pll->vco_current_rate; + } + rc = mdss_pll_resource_enable(pll, true); if (rc) { pr_err("failed to enable pll(%d) resource, rc=%d\n", @@ -673,6 +938,9 @@ static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw, return 0; } + if (!dsi_pll_10nm_lock_status(pll)) + pll->handoff_resources = true; + dec = MDSS_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1); dec &= 0xFF; @@ -846,176 +1114,6 @@ static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div) return rc; } -static int post_vco_clk_get_div(void *context, unsigned int reg, - unsigned int *div) -{ - int rc; - struct mdss_pll_resources *pll = context; - u32 reg_val; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); - return rc; - } - - reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1); - reg_val &= 0x3; - - if (reg_val == 2) - *div = 1; - else if (reg_val == 3) - *div = 4; - else - *div = 1; - - /** - *Common clock framework the divider value is interpreted as one less - * hence we return one less for all dividers except when zero - */ - if (*div != 0) - *div -= 1; - - (void)mdss_pll_resource_enable(pll, false); - - return rc; -} - -static int post_vco_clk_set_div_sub(struct mdss_pll_resources *pll, int div) -{ - u32 reg_val; - int rc = 0; - - reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1); - reg_val &= ~0x03; - if (div == 1) { - reg_val |= 0x2; - } else if (div == 4) { - reg_val |= 0x3; - } else { - rc = -EINVAL; - pr_err("unsupported divider %d\n", div); - goto error; - } - - MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val); - -error: - return rc; -} - -static int post_vco_clk_set_div(void *context, unsigned int reg, - unsigned int div) -{ - int rc = 0; - struct mdss_pll_resources *pll = context; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); - return rc; - } - - /** - * In common clock framework the divider value provided is one less and - * and hence adjusting the divider value by one prior to writing it to - * hardware - */ - div++; - rc = post_vco_clk_set_div_sub(pll, div); - if (!rc && pll->slave) - rc = post_vco_clk_set_div_sub(pll->slave, div); - - (void)mdss_pll_resource_enable(pll, false); - - return rc; -} - -static int post_bit_clk_get_div(void *context, unsigned int reg, - unsigned int *div) -{ - int rc; - struct mdss_pll_resources *pll = context; - u32 reg_val; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); - return rc; - } - - reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1); - reg_val &= 0x3; - - if (reg_val == 0) - *div = 1; - else if (reg_val == 1) - *div = 2; - else - *div = 1; - - /** - *Common clock framework the divider value is interpreted as one less - * hence we return one less for all dividers except when zero - */ - if (*div != 0) - *div -= 1; - - (void)mdss_pll_resource_enable(pll, false); - - return rc; -} - -static int post_bit_clk_set_div_sub(struct mdss_pll_resources *pll, int div) -{ - int rc = 0; - u32 reg_val; - - reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1); - reg_val &= ~0x03; - if (div == 1) { - reg_val |= 0x0; - } else if (div == 2) { - reg_val |= 0x1; - } else { - rc = -EINVAL; - pr_err("unsupported divider %d\n", div); - goto error; - } - - MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val); - -error: - return rc; -} - -static int post_bit_clk_set_div(void *context, unsigned int reg, - unsigned int div) -{ - int rc = 0; - struct mdss_pll_resources *pll = context; - - rc = mdss_pll_resource_enable(pll, true); - if (rc) { - pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); - return rc; - } - - /** - * In common clock framework the divider value provided is one less and - * and hence adjusting the divider value by one prior to writing it to - * hardware - */ - div++; - rc = post_bit_clk_set_div_sub(pll, div); - if (!rc && pll->slave) - rc = post_bit_clk_set_div_sub(pll->slave, div); - - (void)mdss_pll_resource_enable(pll, false); - - return rc; -} - static struct regmap_config dsi_pll_10nm_config = { .reg_bits = 32, .reg_stride = 4, @@ -1023,14 +1121,14 @@ static struct regmap_config dsi_pll_10nm_config = { .max_register = 0x7c0, }; -static struct regmap_bus post_vco_regmap_bus = { - .reg_write = post_vco_clk_set_div, - .reg_read = post_vco_clk_get_div, +static struct regmap_bus pll_regmap_bus = { + .reg_write = pll_reg_write, + .reg_read = pll_reg_read, }; -static struct regmap_bus post_bit_regmap_bus = { - .reg_write = post_bit_clk_set_div, - .reg_read = post_bit_clk_get_div, +static struct regmap_bus pclk_src_mux_regmap_bus = { + .reg_read = pclk_mux_read_sel, + .reg_write = pclk_mux_write_sel, }; static struct regmap_bus pclk_src_regmap_bus = { @@ -1064,23 +1162,30 @@ static struct regmap_bus mdss_mux_regmap_bus = { * | vco_clk | * +-------+-------+ * | - * +--------------------------------------+ - * | | - * +-------v-------+ | - * | bitclk_src | | - * | DIV(1..15) | | - * +-------+-------+ | - * | | - * +--------------------+ | - * Shadow Path | | | - * + +-------v-------+ +------v------+ +------v-------+ - * | | byteclk_src | |post_bit_div | |post_vco_div | - * | | DIV(8) | |DIV(1,2) | |DIV(1,4) | - * | +-------+-------+ +------+------+ +------+-------+ - * | | | | - * | | +------+ +----+ - * | +--------+ | | - * | | +----v-----v------+ + * | + * +---------------+ + * | pll_out_div | + * | DIV(1,2,4,8) | + * +-------+-------+ + * | + * +-----------------------------+--------+ + * | | | + * +-------v-------+ | | + * | bitclk_src | | | + * | DIV(1..15) | | | + * +-------+-------+ | | + * | | | + * +----------+---------+ | | + * Shadow Path | | | | | + * + +-------v-------+ | +------v------+ | +------v-------+ + * | | byteclk_src | | |post_bit_div | | |post_vco_div | + * | | DIV(8) | | |DIV (2) | | |DIV(4) | + * | +-------+-------+ | +------+------+ | +------+-------+ + * | | | | | | | + * | | | +------+ | | + * | | +-------------+ | | +----+ + * | +--------+ | | | | + * | | +-v--v-v---v------+ * +-v---------v----+ \ pclk_src_mux / * \ byteclk_mux / \ / * \ / +-----+-----+ @@ -1111,7 +1216,7 @@ static struct dsi_pll_vco_clk dsi0pll_vco_clk = { .max_rate = 3500000000UL, .hw.init = &(struct clk_init_data){ .name = "dsi0pll_vco_clk", - .parent_names = (const char *[]){"xo_board"}, + .parent_names = (const char *[]){"bi_tcxo"}, .num_parents = 1, .ops = &clk_ops_vco_10nm, .flags = CLK_GET_RATE_NOCACHE, @@ -1124,19 +1229,21 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = { .max_rate = 3500000000UL, .hw.init = &(struct clk_init_data){ .name = "dsi1pll_vco_clk", - .parent_names = (const char *[]){"xo_board"}, + .parent_names = (const char *[]){"bi_tcxo"}, .num_parents = 1, .ops = &clk_ops_vco_10nm, .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_regmap_div dsi0pll_bitclk_src = { +static struct clk_regmap_div dsi0pll_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, .shift = 0, - .width = 4, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_bitclk_src", + .name = "dsi0pll_pll_out_div", .parent_names = (const char *[]){"dsi0pll_vco_clk"}, .num_parents = 1, .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), @@ -1145,12 +1252,14 @@ static struct clk_regmap_div dsi0pll_bitclk_src = { }, }; -static struct clk_regmap_div dsi1pll_bitclk_src = { +static struct clk_regmap_div dsi1pll_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, .shift = 0, - .width = 4, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_bitclk_src", + .name = "dsi1pll_pll_out_div", .parent_names = (const char *[]){"dsi1pll_vco_clk"}, .num_parents = 1, .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), @@ -1159,34 +1268,58 @@ static struct clk_regmap_div dsi1pll_bitclk_src = { }, }; -static struct clk_regmap_div dsi0pll_post_vco_div = { +static struct clk_regmap_div dsi0pll_bitclk_src = { .shift = 0, - .width = 2, + .width = 4, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_vco_div", - .parent_names = (const char *[]){"dsi0pll_vco_clk"}, + .name = "dsi0pll_bitclk_src", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), .ops = &clk_regmap_div_ops, }, }, }; -static struct clk_regmap_div dsi1pll_post_vco_div = { +static struct clk_regmap_div dsi1pll_bitclk_src = { .shift = 0, - .width = 2, + .width = 4, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_vco_div", - .parent_names = (const char *[]){"dsi1pll_vco_clk"}, + .name = "dsi1pll_bitclk_src", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), .ops = &clk_regmap_div_ops, }, }, }; +static struct clk_fixed_factor dsi0pll_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_vco_div", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_vco_div", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_fixed_factor dsi0pll_byteclk_src = { .div = 8, .mult = 1, @@ -1211,37 +1344,33 @@ static struct clk_fixed_factor dsi1pll_byteclk_src = { }, }; -static struct clk_regmap_div dsi0pll_post_bit_div = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_post_bit_div", - .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_div_ops, - }, +static struct clk_fixed_factor dsi0pll_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_bit_div", + .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, }, }; -static struct clk_regmap_div dsi1pll_post_bit_div = { - .shift = 0, - .width = 1, - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_post_bit_div", - .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, - .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, - .ops = &clk_regmap_div_ops, - }, +static struct clk_fixed_factor dsi1pll_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_bit_div", + .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, }, }; static struct clk_regmap_mux dsi0pll_byteclk_mux = { .shift = 0, - .width = 0, + .width = 1, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0_phy_pll_out_byteclk", @@ -1255,7 +1384,7 @@ static struct clk_regmap_mux dsi0pll_byteclk_mux = { static struct clk_regmap_mux dsi1pll_byteclk_mux = { .shift = 0, - .width = 0, + .width = 1, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1_phy_pll_out_byteclk", @@ -1268,30 +1397,36 @@ static struct clk_regmap_mux dsi1pll_byteclk_mux = { }; static struct clk_regmap_mux dsi0pll_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, .shift = 0, - .width = 0, + .width = 2, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0pll_pclk_src_mux", - .parent_names = (const char *[]){"dsi0pll_post_bit_div", - "dsi0pll_post_vco_div"}, - .num_parents = 2, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .parent_names = (const char *[]){"dsi0pll_bitclk_src", + "dsi0pll_post_bit_div", + "dsi0pll_pll_out_div", + "dsi0pll_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_regmap_mux_closest_ops, }, }, }; static struct clk_regmap_mux dsi1pll_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, .shift = 0, - .width = 0, + .width = 2, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1pll_pclk_src_mux", - .parent_names = (const char *[]){"dsi1pll_post_bit_div", - "dsi1pll_post_vco_div"}, - .num_parents = 2, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .parent_names = (const char *[]){"dsi1pll_bitclk_src", + "dsi1pll_post_bit_div", + "dsi1pll_pll_out_div", + "dsi1pll_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_regmap_mux_closest_ops, }, }, @@ -1329,7 +1464,7 @@ static struct clk_regmap_div dsi1pll_pclk_src = { static struct clk_regmap_mux dsi0pll_pclk_mux = { .shift = 0, - .width = 0, + .width = 1, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0_phy_pll_out_dsiclk", @@ -1343,7 +1478,7 @@ static struct clk_regmap_mux dsi0pll_pclk_mux = { static struct clk_regmap_mux dsi1pll_pclk_mux = { .shift = 0, - .width = 0, + .width = 1, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1_phy_pll_out_dsiclk", @@ -1357,24 +1492,25 @@ static struct clk_regmap_mux dsi1pll_pclk_mux = { static struct clk_hw *mdss_dsi_pllcc_10nm[] = { [VCO_CLK_0] = &dsi0pll_vco_clk.hw, + [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw, [BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw, [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw, - [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.clkr.hw, - [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.clkr.hw, + [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw, + [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw, [BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw, [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw, [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw, [VCO_CLK_1] = &dsi1pll_vco_clk.hw, + [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw, [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw, [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw, - [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.clkr.hw, - [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.clkr.hw, + [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw, + [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw, [BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw, [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw, [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw, - }; int dsi_pll_clock_register_10nm(struct platform_device *pdev, @@ -1419,13 +1555,10 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, /* Establish client data */ if (ndx == 0) { - rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus, - pll_res, &dsi_pll_10nm_config); - dsi0pll_post_vco_div.clkr.regmap = rmap; - rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus, + rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, pll_res, &dsi_pll_10nm_config); - dsi0pll_post_bit_div.clkr.regmap = rmap; + dsi0pll_pll_out_div.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, pll_res, &dsi_pll_10nm_config); @@ -1439,10 +1572,9 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, pll_res, &dsi_pll_10nm_config); dsi0pll_pclk_mux.clkr.regmap = rmap; - rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_pclk_src_mux.clkr.regmap = rmap; - rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi0pll_byteclk_mux.clkr.regmap = rmap; @@ -1466,13 +1598,9 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, } else { - rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus, - pll_res, &dsi_pll_10nm_config); - dsi1pll_post_vco_div.clkr.regmap = rmap; - - rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus, + rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, pll_res, &dsi_pll_10nm_config); - dsi1pll_post_bit_div.clkr.regmap = rmap; + dsi1pll_pll_out_div.clkr.regmap = rmap; rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, pll_res, &dsi_pll_10nm_config); @@ -1486,10 +1614,9 @@ int dsi_pll_clock_register_10nm(struct platform_device *pdev, pll_res, &dsi_pll_10nm_config); dsi1pll_pclk_mux.clkr.regmap = rmap; - rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_pclk_src_mux.clkr.regmap = rmap; - rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, pll_res, &dsi_pll_10nm_config); dsi1pll_byteclk_mux.clkr.regmap = rmap; diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 7f82fda2e1efe5710c8ba50f6e33144f165c1be1..e292ef863ff76c4f1b5eb2d5f534f23b83c22df5 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -21,6 +21,7 @@ #include #include "mdss-pll.h" #include "mdss-dsi-pll.h" +#include "mdss-dp-pll.h" int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable) { @@ -126,6 +127,8 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_10nm")) pll_res->pll_interface_type = MDSS_DSI_PLL_10NM; + if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_10nm")) + pll_res->pll_interface_type = MDSS_DP_PLL_10NM; else goto err; @@ -151,6 +154,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev, case MDSS_DSI_PLL_10NM: rc = dsi_pll_clock_register_10nm(pdev, pll_res); break; + case MDSS_DP_PLL_10NM: + rc = dp_pll_clock_register_10nm(pdev, pll_res); + break; case MDSS_UNKNOWN_PLL: default: rc = -EINVAL; @@ -171,6 +177,7 @@ static int mdss_pll_probe(struct platform_device *pdev) const char *label; struct resource *pll_base_reg; struct resource *phy_base_reg; + struct resource *tx0_base_reg, *tx1_base_reg; struct resource *dynamic_pll_base_reg; struct resource *gdsc_base_reg; struct mdss_pll_resources *pll_res; @@ -272,6 +279,30 @@ static int mdss_pll_probe(struct platform_device *pdev) } } + tx0_base_reg = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ln_tx0_base"); + if (tx0_base_reg) { + pll_res->ln_tx0_base = ioremap(tx0_base_reg->start, + resource_size(tx0_base_reg)); + if (!pll_res->ln_tx0_base) { + pr_err("Unable to remap Lane TX0 base resources\n"); + rc = -ENOMEM; + goto tx0_io_error; + } + } + + tx1_base_reg = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ln_tx1_base"); + if (tx1_base_reg) { + pll_res->ln_tx1_base = ioremap(tx1_base_reg->start, + resource_size(tx1_base_reg)); + if (!pll_res->ln_tx1_base) { + pr_err("Unable to remap Lane TX1 base resources\n"); + rc = -ENOMEM; + goto tx1_io_error; + } + } + gdsc_base_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gdsc_base"); if (!gdsc_base_reg) { @@ -309,6 +340,12 @@ static int mdss_pll_probe(struct platform_device *pdev) if (pll_res->gdsc_base) iounmap(pll_res->gdsc_base); gdsc_io_error: + if (pll_res->ln_tx1_base) + iounmap(pll_res->ln_tx1_base); +tx1_io_error: + if (pll_res->ln_tx0_base) + iounmap(pll_res->ln_tx0_base); +tx0_io_error: if (pll_res->dyn_pll_base) iounmap(pll_res->dyn_pll_base); dyn_pll_io_error: @@ -347,6 +384,7 @@ static int mdss_pll_remove(struct platform_device *pdev) static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_10nm"}, + {.compatible = "qcom,mdss_dp_pll_10nm"}, {} }; diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index eccfceadf1681b3e96ad68a72f1be926e5c51e74..2f92270841ac0bf32828d72dadf011f7b28901f4 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.h @@ -37,6 +37,7 @@ enum { MDSS_DSI_PLL_10NM, + MDSS_DP_PLL_10NM, MDSS_UNKNOWN_PLL, }; @@ -81,6 +82,8 @@ struct mdss_pll_resources { */ void __iomem *pll_base; void __iomem *phy_base; + void __iomem *ln_tx0_base; + void __iomem *ln_tx1_base; void __iomem *gdsc_base; void __iomem *dyn_pll_base; @@ -94,6 +97,9 @@ struct mdss_pll_resources { * suspend/resume scenario. Cached the vco rate for such plls. */ unsigned long vco_cached_rate; + u32 cached_cfg0; + u32 cached_cfg1; + u32 cached_outdiv; /* dsi/edp/hmdi pll interface type */ u32 pll_interface_type; diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c index 4eb8a04aad61655de1fdb2235a672c86c8324c4c..79cc5cf41cc73b62ce541eb8e9f6885bfd751ee9 100644 --- a/drivers/clk/qcom/videocc-sdm845.c +++ b/drivers/clk/qcom/videocc-sdm845.c @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -63,7 +65,7 @@ static const char * const video_cc_parent_names_0[] = { }; static struct pll_vco fabia_vco[] = { - { 250000000, 2000000000, 0 }, + { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, }; @@ -102,6 +104,27 @@ static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { { } }; +static const struct freq_tbl ftbl_video_cc_venus_clk_src_sdm845_v2[] = { + F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(330000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_video_cc_venus_clk_src_sdm670[] = { + F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(330000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(364700000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + static struct clk_rcg2 video_cc_venus_clk_src = { .cmd_rcgr = 0x7f0, .mnd_width = 0, @@ -299,13 +322,6 @@ static struct clk_regmap *video_cc_sdm845_clocks[] = { [VIDEO_PLL0] = &video_pll0.clkr, }; -static const struct qcom_reset_map video_cc_sdm845_resets[] = { - [VIDEO_CC_INTERFACE_BCR] = { 0x8f0 }, - [VIDEO_CC_VCODEC0_BCR] = { 0x870 }, - [VIDEO_CC_VCODEC1_BCR] = { 0x8b0 }, - [VIDEO_CC_VENUS_BCR] = { 0x810 }, -}; - static const struct regmap_config video_cc_sdm845_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -318,16 +334,49 @@ static const struct qcom_cc_desc video_cc_sdm845_desc = { .config = &video_cc_sdm845_regmap_config, .clks = video_cc_sdm845_clocks, .num_clks = ARRAY_SIZE(video_cc_sdm845_clocks), - .resets = video_cc_sdm845_resets, - .num_resets = ARRAY_SIZE(video_cc_sdm845_resets), }; static const struct of_device_id video_cc_sdm845_match_table[] = { { .compatible = "qcom,video_cc-sdm845" }, + { .compatible = "qcom,video_cc-sdm845-v2" }, + { .compatible = "qcom,video_cc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table); +static void video_cc_sdm845_fixup_sdm845v2(void) +{ + video_cc_venus_clk_src.freq_tbl = ftbl_video_cc_venus_clk_src_sdm845_v2; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 330000000; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 404000000; +} + +static void video_cc_sdm845_fixup_sdm670(void) +{ + video_cc_venus_clk_src.freq_tbl = ftbl_video_cc_venus_clk_src_sdm670; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 330000000; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 404000000; +} + +static int video_cc_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,video_cc-sdm845-v2")) + video_cc_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,video_cc-sdm670")) + video_cc_sdm845_fixup_sdm670(); + + return 0; +} + static int video_cc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; @@ -347,6 +396,10 @@ static int video_cc_sdm845_probe(struct platform_device *pdev) return PTR_ERR(vdd_cx.regulator[0]); } + ret = video_cc_sdm845_fixup(pdev); + if (ret) + return ret; + clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); ret = qcom_cc_really_probe(pdev, &video_cc_sdm845_desc, regmap); @@ -371,7 +424,7 @@ static int __init video_cc_sdm845_init(void) { return platform_driver_register(&video_cc_sdm845_driver); } -core_initcall(video_cc_sdm845_init); +subsys_initcall(video_cc_sdm845_init); static void __exit video_cc_sdm845_exit(void) { diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c index 924f560dcf80e8a5681fba4c670524b2b20b01ee..dcde70f4c1056f12e3ba6ad4bf837b539a5f158d 100644 --- a/drivers/clk/rockchip/clk-rk3036.c +++ b/drivers/clk/rockchip/clk-rk3036.c @@ -127,7 +127,7 @@ PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" }; PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" }; -PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll" "usb480m" }; +PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll", "usb480m" }; PNAME(mux_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" }; PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 8c8b495cbf0d502daa51c5c1403125b4e7ea15f3..cdc092a1d9effd7815fbd43314977059a52e0ec8 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -586,7 +586,7 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = { GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam", GATE_BUS_TOP, 24, 0, 0), GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler", - GATE_BUS_TOP, 27, 0, 0), + GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0), }; static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { @@ -956,20 +956,20 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0), GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys", - GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0), + GATE_BUS_FSYS0, 9, CLK_IS_CRITICAL, 0), GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2", GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d", GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d", - GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 1, CLK_IS_CRITICAL, 0), GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg", GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0", GATE_BUS_TOP, 5, 0, 0), GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl", - GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0), GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl", GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp", @@ -983,20 +983,20 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(0, "aclk166", "mout_user_aclk166", GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333", - GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0), GATE(0, "aclk400_isp", "mout_user_aclk400_isp", GATE_BUS_TOP, 16, 0, 0), GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl", GATE_BUS_TOP, 17, 0, 0), GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1", - GATE_BUS_TOP, 18, 0, 0), + GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0), GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24", GATE_BUS_TOP, 28, 0, 0), GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m", GATE_BUS_TOP, 29, 0, 0), GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1", - SRC_MASK_TOP2, 24, 0, 0), + SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0), GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk", SRC_MASK_TOP7, 20, 0, 0), diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ea1608682d7fe90b3b20ede863386d82c4f23e7b..2fe057326552a9c13aa38b721ad17bbfafb962d0 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -2559,8 +2559,10 @@ static const struct samsung_fixed_rate_clock disp_fixed_clks[] __initconst = { FRATE(0, "phyclk_mipidphy1_bitclkdiv8_phy", NULL, 0, 188000000), FRATE(0, "phyclk_mipidphy1_rxclkesc0_phy", NULL, 0, 100000000), /* PHY clocks from MIPI_DPHY0 */ - FRATE(0, "phyclk_mipidphy0_bitclkdiv8_phy", NULL, 0, 188000000), - FRATE(0, "phyclk_mipidphy0_rxclkesc0_phy", NULL, 0, 100000000), + FRATE(CLK_PHYCLK_MIPIDPHY0_BITCLKDIV8_PHY, "phyclk_mipidphy0_bitclkdiv8_phy", + NULL, 0, 188000000), + FRATE(CLK_PHYCLK_MIPIDPHY0_RXCLKESC0_PHY, "phyclk_mipidphy0_rxclkesc0_phy", + NULL, 0, 100000000), /* PHY clocks from HDMI_PHY */ FRATE(CLK_PHYCLK_HDMIPHY_TMDS_CLKO_PHY, "phyclk_hdmiphy_tmds_clko_phy", NULL, 0, 300000000), diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 8ca07fe8d3f3f506e871ede702488f193806afc9..9fe0939c1273ea64eeb13a9e9082e9bcc859960a 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -468,8 +468,8 @@ static SUNXI_CCU_MUX_WITH_GATE(daudio0_clk, "daudio0", daudio_parents, static SUNXI_CCU_MUX_WITH_GATE(daudio1_clk, "daudio1", daudio_parents, 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT); -static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", - 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_MUX_WITH_GATE(spdif_clk, "spdif", daudio_parents, + 0x0c0, 16, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0x0cc, BIT(8), 0); @@ -556,7 +556,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(lcd0_ch1_clk, "lcd0-ch1", lcd_ch1_parents, 0x12c, 0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(lcd1_ch1_clk, "lcd1-ch1", lcd_ch1_parents, - 0x12c, 0, 4, 24, 3, BIT(31), + 0x130, 0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT); static const char * const csi_sclk_parents[] = { "pll-video0", "pll-video1", @@ -608,7 +608,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents, 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); -static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0); +static SUNXI_CCU_GATE(hdmi_ddc_clk, "ddc", "osc24M", 0x150, BIT(30), 0); static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index 9bd1f78a05471955890e41da51e1b81811c00d64..e1dc4e5b34e18d4d3ade66f7ccdbb07a208001ae 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -752,6 +752,13 @@ static const struct sunxi_ccu_desc sun8i_a33_ccu_desc = { .num_resets = ARRAY_SIZE(sun8i_a33_ccu_resets), }; +static struct ccu_mux_nb sun8i_a33_cpu_nb = { + .common = &cpux_clk.common, + .cm = &cpux_clk.mux, + .delay_us = 1, /* > 8 clock cycles at 24 MHz */ + .bypass_index = 1, /* index of 24 MHz oscillator */ +}; + static void __init sun8i_a33_ccu_setup(struct device_node *node) { void __iomem *reg; @@ -775,6 +782,9 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node) writel(val, reg + SUN8I_A33_PLL_MIPI_REG); sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc); + + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, + &sun8i_a33_cpu_nb); } CLK_OF_DECLARE(sun8i_a33_ccu, "allwinner,sun8i-a33-ccu", sun8i_a33_ccu_setup); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 21c427d86f289b2a588cc41190525c408e2be3bf..a26c8a19fe93a2b8f1f768b414cb678f364d5542 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -803,6 +803,13 @@ static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = { .num_resets = ARRAY_SIZE(sun8i_h3_ccu_resets), }; +static struct ccu_mux_nb sun8i_h3_cpu_nb = { + .common = &cpux_clk.common, + .cm = &cpux_clk.mux, + .delay_us = 1, /* > 8 clock cycles at 24 MHz */ + .bypass_index = 1, /* index of 24 MHz oscillator */ +}; + static void __init sun8i_h3_ccu_setup(struct device_node *node) { void __iomem *reg; @@ -821,6 +828,9 @@ static void __init sun8i_h3_ccu_setup(struct device_node *node) writel(val | (3 << 16), reg + SUN8I_H3_PLL_AUDIO_REG); sunxi_ccu_probe(node, reg, &sun8i_h3_ccu_desc); + + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, + &sun8i_h3_cpu_nb); } CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu", sun8i_h3_ccu_setup); diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 51d4bac97ab301f9d0213ff40327325622fd2109..01d0594c9716be8659b9585cce422ef954a2292d 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -70,6 +70,11 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, goto err_clk_unreg; reset = kzalloc(sizeof(*reset), GFP_KERNEL); + if (!reset) { + ret = -ENOMEM; + goto err_alloc_reset; + } + reset->rcdev.of_node = node; reset->rcdev.ops = &ccu_reset_ops; reset->rcdev.owner = THIS_MODULE; @@ -85,6 +90,16 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, return 0; err_of_clk_unreg: + kfree(reset); +err_alloc_reset: + of_clk_del_provider(node); err_clk_unreg: + while (--i >= 0) { + struct clk_hw *hw = desc->hw_clks->hws[i]; + + if (!hw) + continue; + clk_hw_unregister(hw); + } return ret; } diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c index 6041bdba2e971ecb93c3047c14854e676750bf5e..f69f9e8c6f38060f9eae357e89a0f549e68c1b64 100644 --- a/drivers/clk/sunxi/clk-sun9i-mmc.c +++ b/drivers/clk/sunxi/clk-sun9i-mmc.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -83,9 +84,20 @@ static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev, return 0; } +static int sun9i_mmc_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + sun9i_mmc_reset_assert(rcdev, id); + udelay(10); + sun9i_mmc_reset_deassert(rcdev, id); + + return 0; +} + static const struct reset_control_ops sun9i_mmc_reset_ops = { .assert = sun9i_mmc_reset_assert, .deassert = sun9i_mmc_reset_deassert, + .reset = sun9i_mmc_reset_reset, }; static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev) diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 8e2db5ead8da683500826a2968bd165ca88943b6..af520d81525fa9856f9550c73a2de820e9309f24 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -963,7 +963,7 @@ static void __init tegra30_super_clk_init(void) * U71 divider of cclk_lp. */ clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", - clk_base + SUPER_CCLKG_DIVIDER, 0, + clk_base + SUPER_CCLKLP_DIVIDER, 0, TEGRA_DIVIDER_INT, 16, 8, 1, NULL); clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index c77333230bdf22d20dac90611aa4461a28c86321..7d060ffe8975f49b7e1a9b9a16e9abfbb24174e4 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -265,8 +265,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) /* Get configuration for the ATL instances */ snprintf(prop, sizeof(prop), "atl%u", i); - of_node_get(node); - cfg_node = of_find_node_by_name(node, prop); + cfg_node = of_get_child_by_name(node, prop); if (cfg_node) { ret = of_property_read_u32(cfg_node, "bws", &cdesc->bws); diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 5d029991047ddb7fdda7807d11d2d3dc99978279..481225adef8772406ae07604383f1d8bf6ff1836 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -98,7 +98,7 @@ const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("spll", -1, "ref", 120, 1), /* 2400 MHz */ UNIPHIER_CLK_FACTOR("dapll1", -1, "ref", 128, 1), /* 2560 MHz */ - UNIPHIER_CLK_FACTOR("dapll2", -1, "ref", 144, 125), /* 2949.12 MHz */ + UNIPHIER_CLK_FACTOR("dapll2", -1, "dapll1", 144, 125), /* 2949.12 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "dapll2", 1, 40), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_SD, diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e2c6e43cf8ca31e27af1b6c8630f7a0c590e8b7a..cd6d3077d4580b29f1d3c13dfbf3f6ff92ab12fb 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -305,6 +305,14 @@ config ARM_ARCH_TIMER_EVTSTREAM This must be disabled for hardware validation purposes to detect any hardware anomalies of missing events. +config ARM_ARCH_TIMER_VCT_ACCESS + bool "Support for ARM architected timer virtual counter access in userspace" + default !ARM64 + depends on ARM_ARCH_TIMER + help + This option enables support for reading the ARM architected timer's + virtual counter in userspace. + config FSL_ERRATUM_A008585 bool "Workaround for Freescale/NXP Erratum A-008585" default y @@ -315,6 +323,14 @@ config FSL_ERRATUM_A008585 value"). The workaround will only be active if the fsl,erratum-a008585 property is found in the timer node. +config ARM_ARCH_TIMER_VCT_ACCESS + bool "Support for ARM architected timer virtual counter access in userspace" + default !ARM64 + depends on ARM_ARCH_TIMER + help + This option enables support for reading the ARM architected timer's + virtual counter in userspace. + config ARM_GLOBAL_TIMER bool "Support for the ARM global timer" if COMPILE_TEST select CLKSRC_OF if OF diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5db1897242477436f049e9ce6d61f5b90c36a310..5aa9914d494ec4d5087a3af435aae5bde22e09b0 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -48,6 +48,8 @@ #define CNTFRQ 0x10 #define CNTP_TVAL 0x28 #define CNTP_CTL 0x2c +#define CNTCVAL_LO 0x30 +#define CNTCVAL_HI 0x34 #define CNTV_TVAL 0x38 #define CNTV_CTL 0x3c @@ -441,14 +443,18 @@ static void arch_counter_set_user_access(void) { u32 cntkctl = arch_timer_get_cntkctl(); - /* Disable user access to the timers */ + /* Disable user access to the timers and the physical counter */ /* Also disable virtual event stream */ cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN | ARCH_TIMER_USR_VT_ACCESS_EN - | ARCH_TIMER_VIRT_EVT_EN); + | ARCH_TIMER_VIRT_EVT_EN + | ARCH_TIMER_USR_PCT_ACCESS_EN); - /* Enable user access to the virtual and physical counters */ - cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN | ARCH_TIMER_USR_PCT_ACCESS_EN; + /* Enable user access to the virtual counter */ + if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS)) + cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; + else + cntkctl &= ~ARCH_TIMER_USR_VCT_ACCESS_EN; arch_timer_set_cntkctl(cntkctl); } @@ -541,6 +547,23 @@ u32 arch_timer_get_rate(void) return arch_timer_rate; } +void arch_timer_mem_get_cval(u32 *lo, u32 *hi) +{ + u32 ctrl; + + *lo = *hi = ~0U; + + if (!arch_counter_base) + return; + + ctrl = readl_relaxed_no_log(arch_counter_base + CNTV_CTL); + + if (ctrl & ARCH_TIMER_CTRL_ENABLE) { + *lo = readl_relaxed_no_log(arch_counter_base + CNTCVAL_LO); + *hi = readl_relaxed_no_log(arch_counter_base + CNTCVAL_HI); + } +} + static u64 arch_counter_get_cntvct_mem(void) { u32 vct_lo, vct_hi, tmp_hi; @@ -873,7 +896,7 @@ static int __init arch_timer_init(void) return ret; arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI]; - + return 0; } diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index 9a7e37cf56b01a601e022b8ba5c6495d895b9898..e1d7373e63e0dfdcf0d66fa2b52c845a5b276124 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c @@ -117,7 +117,8 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) /* Turn off the clock (and clear the event) */ disable_timer(cs5535_event_clock); - if (clockevent_state_shutdown(&cs5535_clockevent)) + if (clockevent_state_detached(&cs5535_clockevent) || + clockevent_state_shutdown(&cs5535_clockevent)) return IRQ_HANDLED; /* Clear the counter */ diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index e2023bdca14dab387f4de9009d57fa78a1f3cf76..fd5984f41bee8fc25e9de66044fb7d58ba0cc9ec 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -244,7 +244,7 @@ config ARM_PXA2xx_CPUFREQ config ACPI_CPPC_CPUFREQ tristate "CPUFreq driver based on the ACPI CPPC spec" - depends on ACPI + depends on ACPI_PROCESSOR select ACPI_CPPC_LIB default n help diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c index 07603feddc1525a39013f3b617ff132114134837..6a4008c1c52693a89fa50e652f92fd5758d6871e 100644 --- a/drivers/cpufreq/cpu-boost.c +++ b/drivers/cpufreq/cpu-boost.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015,2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,8 +39,8 @@ static bool input_boost_enabled; static unsigned int input_boost_ms = 40; module_param(input_boost_ms, uint, 0644); -static bool sched_boost_on_input; -module_param(sched_boost_on_input, bool, 0644); +static unsigned int sched_boost_on_input; +module_param(sched_boost_on_input, uint, 0644); static bool sched_boost_active; @@ -75,7 +75,7 @@ static int set_input_boost_freq(const char *buf, const struct kernel_param *kp) for (i = 0; i < ntokens; i += 2) { if (sscanf(cp, "%u:%u", &cpu, &val) != 2) return -EINVAL; - if (cpu > num_possible_cpus()) + if (cpu >= num_possible_cpus()) return -EINVAL; per_cpu(sync_info, cpu).input_boost_freq = val; @@ -209,8 +209,8 @@ static void do_input_boost(struct work_struct *work) update_policy_online(); /* Enable scheduler boost to migrate tasks to big cluster */ - if (sched_boost_on_input) { - ret = sched_set_boost(1); + if (sched_boost_on_input > 0) { + ret = sched_set_boost(sched_boost_on_input); if (ret) pr_err("cpu-boost: HMP boost enable failed\n"); else diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b315236842fa69c16243670a3d3475a1a602c056..1d5dba9a12ee892ddb6032087565d2924e2025a4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -990,11 +990,19 @@ static struct kobj_type ktype_cpufreq = { .release = cpufreq_sysfs_release, }; -static int add_cpu_dev_symlink(struct cpufreq_policy *policy, - struct device *dev) +static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu) { + struct device *dev = get_cpu_device(cpu); + + if (!dev) + return; + + if (cpumask_test_and_set_cpu(cpu, policy->real_cpus)) + return; + dev_dbg(dev, "%s: Adding symlink\n", __func__); - return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); + if (sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq")) + dev_err(dev, "cpufreq symlink creation failed\n"); } static void remove_cpu_dev_symlink(struct cpufreq_policy *policy, @@ -1245,8 +1253,6 @@ static int cpufreq_online(unsigned int cpu) if (new_policy) { /* related_cpus should at least include policy->cpus. */ cpumask_copy(policy->related_cpus, policy->cpus); - /* Clear mask of registered CPUs */ - cpumask_clear(policy->real_cpus); } /* @@ -1259,10 +1265,10 @@ static int cpufreq_online(unsigned int cpu) policy->user_policy.min = policy->min; policy->user_policy.max = policy->max; - write_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu(j, policy->related_cpus) + for_each_cpu(j, policy->related_cpus) { per_cpu(cpufreq_cpu_data, j) = policy; - write_unlock_irqrestore(&cpufreq_driver_lock, flags); + add_cpu_dev_symlink(policy, j); + } } else { policy->min = policy->user_policy.min; policy->max = policy->user_policy.max; @@ -1359,13 +1365,15 @@ static int cpufreq_online(unsigned int cpu) if (cpufreq_driver->exit) cpufreq_driver->exit(policy); + + for_each_cpu(j, policy->real_cpus) + remove_cpu_dev_symlink(policy, get_cpu_device(j)); + out_free_policy: cpufreq_policy_free(policy, !new_policy); return ret; } -static int cpufreq_offline(unsigned int cpu); - /** * cpufreq_add_dev - the cpufreq interface for a CPU device. * @dev: CPU device. @@ -1387,16 +1395,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) /* Create sysfs link on CPU registration */ policy = per_cpu(cpufreq_cpu_data, cpu); - if (!policy || cpumask_test_and_set_cpu(cpu, policy->real_cpus)) - return 0; + if (policy) + add_cpu_dev_symlink(policy, cpu); - ret = add_cpu_dev_symlink(policy, dev); - if (ret) { - cpumask_clear_cpu(cpu, policy->real_cpus); - cpufreq_offline(cpu); - } - - return ret; + return 0; } static int cpufreq_offline(unsigned int cpu) @@ -2550,6 +2552,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) if (!(cpufreq_driver->flags & CPUFREQ_STICKY) && list_empty(&cpufreq_policy_list)) { /* if all ->init() calls failed, unregister */ + ret = -ENODEV; pr_debug("%s: No CPU initialized for driver %s\n", __func__, driver_data->name); goto err_if_unreg; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index e8e16a5dbd1e4d52584864720ca439ece0062555..0fe251865ac6a468963637f4f3be6676c7d985c8 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -169,8 +169,8 @@ static ssize_t store_down_threshold(struct gov_attr_set *attr_set, int ret; ret = sscanf(buf, "%u", &input); - /* cannot be lower than 11 otherwise freq will not fall */ - if (ret != 1 || input < 11 || input > 100 || + /* cannot be lower than 1 otherwise freq will not fall */ + if (ret != 1 || input < 1 || input > 100 || input >= dbs_data->up_threshold) return -EINVAL; diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 12eb6d84c7084729c8338b5ec326d71244d1f678..c59e980ba2021db934e689945036b46dea321e11 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -455,15 +455,11 @@ static u64 update_load(int cpu) struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); struct cpufreq_interactive_tunables *tunables = ppol->policy->governor_data; - u64 now; - u64 now_idle; - unsigned int delta_idle; - unsigned int delta_time; - u64 active_time; + u64 now_idle, now, active_time, delta_idle, delta_time; now_idle = get_cpu_idle_time(cpu, &now, tunables->io_is_busy); - delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle); - delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp); + delta_idle = (now_idle - pcpu->time_in_idle); + delta_time = (now - pcpu->time_in_idle_timestamp); if (delta_time <= delta_idle) active_time = 0; @@ -699,7 +695,8 @@ static void cpufreq_interactive_timer(int data) spin_lock_irqsave(&speedchange_cpumask_lock, flags); cpumask_set_cpu(max_cpu, &speedchange_cpumask); spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); - wake_up_process_no_notif(speedchange_task); + + wake_up_process(speedchange_task); rearm: cpufreq_interactive_timer_resched(data, false); @@ -814,7 +811,7 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]); if (anyboost) - wake_up_process_no_notif(speedchange_task); + wake_up_process(speedchange_task); } static int load_change_callback(struct notifier_block *nb, unsigned long val, @@ -1926,7 +1923,7 @@ static int __init cpufreq_interactive_gov_init(void) get_task_struct(speedchange_task); /* NB: wake up so the thread does not look hung to the freezer */ - wake_up_process_no_notif(speedchange_task); + wake_up_process(speedchange_task); return cpufreq_register_governor(CPU_FREQ_GOV_INTERACTIVE); } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 80fa656da5ab43e4e7013351c6828fe3e9748f84..a59ae8e24d3d80616d4c33fa91bc48cd426bfbb8 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -609,6 +609,7 @@ static void intel_pstate_hwp_set_online_cpus(void) static int pid_param_set(void *data, u64 val) { *(u32 *)data = val; + pid_params.sample_rate_ns = pid_params.sample_rate_ms * NSEC_PER_MSEC; intel_pstate_reset_all_pid(); return 0; } diff --git a/drivers/cpufreq/qcom-cpufreq.c b/drivers/cpufreq/qcom-cpufreq.c index f968ffd9f6afc8969c43f16304dddbd2f3e42ebf..8a5ad7061197d72d5a231806890a528704d0ef38 100644 --- a/drivers/cpufreq/qcom-cpufreq.c +++ b/drivers/cpufreq/qcom-cpufreq.c @@ -27,10 +27,13 @@ #include #include #include +#include +#include #include static DEFINE_MUTEX(l2bw_lock); +static struct thermal_cooling_device *cdev[NR_CPUS]; static struct clk *cpu_clk[NR_CPUS]; static struct clk *l2_clk; static DEFINE_PER_CPU(struct cpufreq_frequency_table *, freq_table); @@ -42,6 +45,8 @@ struct cpufreq_suspend_t { }; static DEFINE_PER_CPU(struct cpufreq_suspend_t, suspend_data); +static DEFINE_PER_CPU(int, cached_resolve_idx); +static DEFINE_PER_CPU(unsigned int, cached_resolve_freq); static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq, unsigned int index) @@ -74,6 +79,7 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, int ret = 0; int index; struct cpufreq_frequency_table *table; + int first_cpu = cpumask_first(policy->related_cpus); mutex_lock(&per_cpu(suspend_data, policy->cpu).suspend_mutex); @@ -88,13 +94,11 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, } table = policy->freq_table; - if (!table) { - pr_err("cpufreq: Failed to get frequency table for CPU%u\n", - policy->cpu); - ret = -ENODEV; - goto done; - } - index = cpufreq_frequency_table_target(policy, target_freq, relation); + if (per_cpu(cached_resolve_freq, first_cpu) == target_freq) + index = per_cpu(cached_resolve_idx, first_cpu); + else + index = cpufreq_frequency_table_target(policy, target_freq, + relation); pr_debug("CPU[%d] target %d relation %d (%d-%d) selected %d\n", policy->cpu, target_freq, relation, @@ -107,6 +111,23 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, return ret; } +static unsigned int msm_cpufreq_resolve_freq(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + int index; + int first_cpu = cpumask_first(policy->related_cpus); + unsigned int freq; + + index = cpufreq_frequency_table_target(policy, target_freq, + CPUFREQ_RELATION_L); + freq = policy->freq_table[index].frequency; + + per_cpu(cached_resolve_idx, first_cpu) = index; + per_cpu(cached_resolve_freq, first_cpu) = freq; + + return freq; +} + static int msm_cpufreq_verify(struct cpufreq_policy *policy) { cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, @@ -290,15 +311,63 @@ static struct freq_attr *msm_freq_attr[] = { NULL, }; +static void msm_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct device_node *np, *lmh_node; + unsigned int cpu = 0; + + if (cdev[policy->cpu]) + return; + + np = of_cpu_device_node_get(policy->cpu); + if (WARN_ON(!np)) + return; + + /* + * For now, just loading the cooling device; + * thermal DT code takes care of matching them. + */ + if (of_find_property(np, "#cooling-cells", NULL)) { + lmh_node = of_parse_phandle(np, "qcom,lmh-dcvs", 0); + if (lmh_node) { + of_node_put(lmh_node); + goto ready_exit; + } + + for_each_cpu(cpu, policy->related_cpus) { + cpumask_t cpu_mask = CPU_MASK_NONE; + + of_node_put(np); + np = of_cpu_device_node_get(cpu); + if (WARN_ON(!np)) + return; + + cpumask_set_cpu(cpu, &cpu_mask); + cdev[cpu] = of_cpufreq_cooling_register(np, &cpu_mask); + if (IS_ERR(cdev[cpu])) { + pr_err( + "running cpufreq for CPU%d without cooling dev: %ld\n", + cpu, PTR_ERR(cdev[cpu])); + cdev[cpu] = NULL; + } + } + } + +ready_exit: + of_node_put(np); +} + static struct cpufreq_driver msm_cpufreq_driver = { /* lps calculations are handled here. */ .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .init = msm_cpufreq_init, .verify = msm_cpufreq_verify, .target = msm_cpufreq_target, + .resolve_freq = msm_cpufreq_resolve_freq, .get = msm_cpufreq_get_freq, .name = "msm", .attr = msm_freq_attr, + .ready = msm_cpufreq_ready, }; static struct cpufreq_frequency_table *cpufreq_parse_dt(struct device *dev, @@ -391,7 +460,7 @@ static int msm_cpufreq_probe(struct platform_device *pdev) if (!IS_ERR(ftbl)) { for_each_possible_cpu(cpu) per_cpu(freq_table, cpu) = ftbl; - return 0; + goto out_register; } /* @@ -431,6 +500,7 @@ static int msm_cpufreq_probe(struct platform_device *pdev) per_cpu(freq_table, cpu) = ftbl; } +out_register: ret = register_pm_notifier(&msm_cpufreq_pm_notifier); if (ret) return ret; @@ -462,6 +532,7 @@ static int __init msm_cpufreq_register(void) for_each_possible_cpu(cpu) { mutex_init(&(per_cpu(suspend_data, cpu).suspend_mutex)); per_cpu(suspend_data, cpu).device_suspended = 0; + per_cpu(cached_resolve_freq, cpu) = UINT_MAX; } rc = platform_driver_register(&msm_cpufreq_plat_driver); diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index d6d425773fa497274301eaa88f247fb8dd770e89..5b2db3c6568f691429fce3d636ac955e06b0bec9 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -400,7 +400,6 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) rate = clk_get_rate(s3c_freq->hclk); if (rate < 133 * 1000 * 1000) { pr_err("cpufreq: HCLK not at 133MHz\n"); - clk_put(s3c_freq->hclk); ret = -EINVAL; goto err_armclk; } diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index 7fe442ca38f4b793cef0f70731a62e215d5d37fc..854a567811002329e9b39068ad8d4834e9b8cf71 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -164,6 +164,24 @@ static int powernv_cpuidle_driver_init(void) drv->state_count += 1; } + /* + * On the PowerNV platform cpu_present may be less than cpu_possible in + * cases when firmware detects the CPU, but it is not available to the + * OS. If CONFIG_HOTPLUG_CPU=n, then such CPUs are not hotplugable at + * run time and hence cpu_devices are not created for those CPUs by the + * generic topology_init(). + * + * drv->cpumask defaults to cpu_possible_mask in + * __cpuidle_driver_init(). This breaks cpuidle on PowerNV where + * cpu_devices are not created for CPUs in cpu_possible_mask that + * cannot be hot-added later at run time. + * + * Trying cpuidle_register_device() on a CPU without a cpu_device is + * incorrect, so pass a correct CPU mask to the generic cpuidle driver. + */ + + drv->cpumask = (struct cpumask *)cpu_present_mask; + return 0; } diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 78ab946d946a7cf21d0ec77d6fdefc9d21b639f9..3eddf4375929d2e35a13ddfbfeb2968bb5af40e8 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -189,6 +189,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, return -EBUSY; } target_state = &drv->states[index]; + broadcast = false; } /* Take note of the planned idle state. */ @@ -613,16 +614,36 @@ EXPORT_SYMBOL_GPL(cpuidle_register); #ifdef CONFIG_SMP +static void wake_up_idle_cpus(void *v) +{ + int cpu; + struct cpumask cpus; + + preempt_disable(); + if (v) { + cpumask_andnot(&cpus, v, cpu_isolated_mask); + cpumask_and(&cpus, &cpus, cpu_online_mask); + } else + cpumask_andnot(&cpus, cpu_online_mask, cpu_isolated_mask); + + for_each_cpu(cpu, &cpus) { + if (cpu == smp_processor_id()) + continue; + wake_up_if_idle(cpu); + } + preempt_enable(); +} + /* * This function gets called when a part of the kernel has a new latency - * requirement. This means we need to get all processors out of their C-state, - * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that - * wakes them all right up. + * requirement. This means we need to get only those processors out of their + * C-state for which qos requirement is changed, and then recalculate a new + * suitable C-state. Just do a cross-cpu IPI; that wakes them all right up. */ static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - wake_up_all_idle_cpus(); + wake_up_idle_cpus(v); return NOTIFY_OK; } diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 2404e176075e4e8c69b32c91a322ba1a8c15d01a..61c0ae853a435ca94076d1ebe197a46998c3d45c 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -10,6 +10,9 @@ * GNU General Public License for more details. * */ + +#define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME + #include #include #include @@ -21,10 +24,10 @@ #include #include "lpm-levels.h" -bool use_psci; enum lpm_type { IDLE = 0, SUSPEND, + LATENCY, LPM_TYPE_NR }; @@ -36,6 +39,7 @@ struct lpm_type_str { static const struct lpm_type_str lpm_types[] = { {IDLE, "idle_enabled"}, {SUSPEND, "suspend_enabled"}, + {LATENCY, "latency_us"}, }; static DEFINE_PER_CPU(uint32_t *, max_residency); @@ -67,6 +71,9 @@ static struct lpm_level_avail *get_avail_ptr(struct kobject *kobj, else if (!strcmp(attr->attr.name, lpm_types[SUSPEND].str)) avail = container_of(attr, struct lpm_level_avail, suspend_enabled_attr); + else if (!strcmp(attr->attr.name, lpm_types[LATENCY].str)) + avail = container_of(attr, struct lpm_level_avail, + latency_attr); return avail; } @@ -163,6 +170,28 @@ uint32_t *get_per_cpu_min_residency(int cpu) { return per_cpu(min_residency, cpu); } + +static ssize_t lpm_latency_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int ret = 0; + struct kernel_param kp; + struct lpm_level_avail *avail = get_avail_ptr(kobj, attr); + + if (!avail) + pr_info("Error\n"); + + kp.arg = &avail->latency_us; + + ret = param_get_uint(buf, &kp); + if (ret > 0) { + strlcat(buf, "\n", PAGE_SIZE); + ret++; + } + + return ret; +} + ssize_t lpm_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -189,6 +218,7 @@ ssize_t lpm_enable_store(struct kobject *kobj, struct kobj_attribute *attr, avail = get_avail_ptr(kobj, attr); if (WARN_ON(!avail)) return -EINVAL; + kp.arg = get_enabled_ptr(attr, avail); ret = param_set_bool(buf, &kp); @@ -239,9 +269,16 @@ static int create_lvl_avail_nodes(const char *name, avail->suspend_enabled_attr.show = lpm_enable_show; avail->suspend_enabled_attr.store = lpm_enable_store; + sysfs_attr_init(&avail->latency_attr.attr); + avail->latency_attr.attr.name = lpm_types[LATENCY].str; + avail->latency_attr.attr.mode = 0444; + avail->latency_attr.show = lpm_latency_show; + avail->latency_attr.store = NULL; + attr[0] = &avail->idle_enabled_attr.attr; attr[1] = &avail->suspend_enabled_attr.attr; - attr[2] = NULL; + attr[2] = &avail->latency_attr.attr; + attr[3] = NULL; attr_group->attrs = attr; ret = sysfs_create_group(kobj, attr_group); @@ -272,6 +309,7 @@ static int create_cpu_lvl_nodes(struct lpm_cluster *p, struct kobject *parent) struct lpm_level_avail *level_list = NULL; char cpu_name[20] = {0}; int ret = 0; + struct list_head *pos; cpu_kobj = devm_kzalloc(&lpm_pdev->dev, sizeof(*cpu_kobj) * cpumask_weight(&p->child_cpus), GFP_KERNEL); @@ -279,37 +317,45 @@ static int create_cpu_lvl_nodes(struct lpm_cluster *p, struct kobject *parent) return -ENOMEM; cpu_idx = 0; - for_each_cpu(cpu, &p->child_cpus) { - snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu); - cpu_kobj[cpu_idx] = kobject_create_and_add(cpu_name, parent); - if (!cpu_kobj[cpu_idx]) { - ret = -ENOMEM; - goto release_kobj; - } + list_for_each(pos, &p->cpu) { + struct lpm_cpu *lpm_cpu = list_entry(pos, struct lpm_cpu, list); + + for_each_cpu(cpu, &lpm_cpu->related_cpus) { + snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu); + cpu_kobj[cpu_idx] = kobject_create_and_add(cpu_name, + parent); + if (!cpu_kobj[cpu_idx]) { + ret = -ENOMEM; + goto release_kobj; + } - level_list = devm_kzalloc(&lpm_pdev->dev, - p->cpu->nlevels * sizeof(*level_list), - GFP_KERNEL); - if (!level_list) { - ret = -ENOMEM; - goto release_kobj; - } + level_list = devm_kzalloc(&lpm_pdev->dev, + lpm_cpu->nlevels * sizeof(*level_list), + GFP_KERNEL); + if (!level_list) { + ret = -ENOMEM; + goto release_kobj; + } - /* - * Skip enable/disable for WFI. cpuidle expects WFI to be - * available at all times. - */ - for (i = 1; i < p->cpu->nlevels; i++) { + /* + * Skip enable/disable for WFI. cpuidle expects WFI to + * be available at all times. + */ + for (i = 1; i < lpm_cpu->nlevels; i++) { + level_list[i].latency_us = + p->levels[i].pwr.latency_us; + ret = create_lvl_avail_nodes( + lpm_cpu->levels[i].name, + cpu_kobj[cpu_idx], + &level_list[i], + (void *)lpm_cpu, cpu, true); + if (ret) + goto release_kobj; + } - ret = create_lvl_avail_nodes(p->cpu->levels[i].name, - cpu_kobj[cpu_idx], &level_list[i], - (void *)p->cpu, cpu, true); - if (ret) - goto release_kobj; + cpu_level_available[cpu] = level_list; + cpu_idx++; } - - cpu_level_available[cpu] = level_list; - cpu_idx++; } return ret; @@ -336,6 +382,7 @@ int create_cluster_lvl_nodes(struct lpm_cluster *p, struct kobject *kobj) return -ENOMEM; for (i = 0; i < p->nlevels; i++) { + p->levels[i].available.latency_us = p->levels[i].pwr.latency_us; ret = create_lvl_avail_nodes(p->levels[i].level_name, cluster_kobj, &p->levels[i].available, (void *)p, 0, false); @@ -349,13 +396,13 @@ int create_cluster_lvl_nodes(struct lpm_cluster *p, struct kobject *kobj) return ret; } - if (p->cpu) { + if (!list_empty(&p->cpu)) { ret = create_cpu_lvl_nodes(p, cluster_kobj); if (ret) return ret; } - return 0; + return ret; } bool lpm_cpu_mode_allow(unsigned int cpu, @@ -363,6 +410,9 @@ bool lpm_cpu_mode_allow(unsigned int cpu, { struct lpm_level_avail *avail = cpu_level_available[cpu]; + if (lpm_pdev && !index) + return 1; + if (!lpm_pdev || !avail) return !from_idle; @@ -390,36 +440,27 @@ static int parse_cluster_params(struct device_node *node, key = "label"; ret = of_property_read_string(node, key, &c->cluster_name); - if (ret) { - pr_err("%s(): Cannot read required param %s\n", __func__, key); - return ret; - } + if (ret) + goto fail; - if (use_psci) { - key = "qcom,psci-mode-shift"; - ret = of_property_read_u32(node, key, - &c->psci_mode_shift); - if (ret) { - pr_err("%s(): Failed to read param: %s\n", - __func__, key); - return ret; - } + key = "qcom,psci-mode-shift"; + ret = of_property_read_u32(node, key, &c->psci_mode_shift); + if (ret) + goto fail; - key = "qcom,psci-mode-mask"; - ret = of_property_read_u32(node, key, - &c->psci_mode_mask); - if (ret) { - pr_err("%s(): Failed to read param: %s\n", - __func__, key); - return ret; - } + key = "qcom,psci-mode-mask"; + ret = of_property_read_u32(node, key, &c->psci_mode_mask); + if (ret) + goto fail; - /* Set ndevice to 1 as default */ - c->ndevices = 1; + /* Set default_level to 0 as default */ + c->default_level = 0; - } else - pr_warn("Target supports PSCI only\n"); - return 0; + return ret; +fail: + pr_err("Failed to read key: %s ret: %d\n", key, ret); + + return ret; } static int parse_power_params(struct device_node *node, @@ -448,10 +489,10 @@ static int parse_power_params(struct device_node *node, if (ret) goto fail; + return ret; fail: - if (ret) - pr_err("%s(): %s Error reading %s\n", __func__, node->name, - key); + pr_err("Failed to read key: %s node: %s\n", key, node->name); + return ret; } @@ -467,26 +508,16 @@ static int parse_cluster_level(struct device_node *node, if (ret) goto failed; - if (use_psci) { - char *k = "qcom,psci-mode"; - - ret = of_property_read_u32(node, k, &level->psci_id); - if (ret) - goto failed; - - level->is_reset = of_property_read_bool(node, "qcom,is-reset"); - } else - pr_warn("Build supports PSCI targets only"); - - key = "label"; - ret = of_property_read_string(node, key, &level->level_name); + key = "qcom,psci-mode"; + ret = of_property_read_u32(node, key, &level->psci_id); if (ret) goto failed; + level->is_reset = of_property_read_bool(node, "qcom,is-reset"); + if (cluster->nlevels != cluster->default_level) { - key = "min child idx"; - ret = of_property_read_u32(node, "qcom,min-child-idx", - &level->min_child_level); + key = "qcom,min-child-idx"; + ret = of_property_read_u32(node, key, &level->min_child_level); if (ret) goto failed; @@ -495,10 +526,6 @@ static int parse_cluster_level(struct device_node *node, } level->notify_rpm = of_property_read_bool(node, "qcom,notify-rpm"); - level->disable_dynamic_routing = of_property_read_bool(node, - "qcom,disable-dynamic-int-routing"); - level->last_core_only = of_property_read_bool(node, - "qcom,last-core-only"); key = "parse_power_params"; ret = parse_power_params(node, &level->pwr); @@ -513,11 +540,11 @@ static int parse_cluster_level(struct device_node *node, goto failed; cluster->nlevels++; + return 0; failed: - pr_err("Failed %s() key = %s ret = %d\n", __func__, key, ret); - kfree(level->mode); - level->mode = NULL; + pr_err("Failed to read key: %s ret: %d\n", key, ret); + return ret; } @@ -526,29 +553,21 @@ static int parse_cpu_mode(struct device_node *n, struct lpm_cpu_level *l) char *key; int ret; - key = "qcom,spm-cpu-mode"; - ret = of_property_read_string(n, key, &l->name); - if (ret) { - pr_err("Failed %s %d\n", n->name, __LINE__); - return ret; - } - - if (use_psci) { - key = "qcom,psci-cpu-mode"; + key = "label"; + ret = of_property_read_string(n, key, &l->name); + if (ret) + goto fail; - ret = of_property_read_u32(n, key, &l->psci_id); - if (ret) { - pr_err("Failed reading %s on device %s\n", key, - n->name); - return ret; - } - key = "qcom,hyp-psci"; + key = "qcom,psci-cpu-mode"; + ret = of_property_read_u32(n, key, &l->psci_id); + if (ret) + goto fail; - l->hyp_psci = of_property_read_bool(n, key); - } else - pr_warn("Build supports PSCI targets only"); - return 0; + return ret; +fail: + pr_err("Failed to read key: %s level: %s\n", key, l->name); + return ret; } static int get_cpumask_for_node(struct device_node *node, struct cpumask *mask) @@ -594,8 +613,7 @@ static int calculate_residency(struct power_params *base_pwr, residency /= (int32_t)(base_pwr->ss_power - next_pwr->ss_power); if (residency < 0) { - pr_err("%s: residency < 0 for LPM\n", - __func__); + pr_err("Residency < 0 for LPM\n"); return next_pwr->time_overhead_us; } @@ -603,125 +621,141 @@ static int calculate_residency(struct power_params *base_pwr, next_pwr->time_overhead_us : residency; } -static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) +static int parse_cpu(struct device_node *node, struct lpm_cpu *cpu) { - struct device_node *n; - int ret = -ENOMEM; - int i, j; - char *key; - - c->cpu = devm_kzalloc(&lpm_pdev->dev, sizeof(*c->cpu), GFP_KERNEL); - if (!c->cpu) - return ret; - - c->cpu->parent = c; - if (use_psci) { - - key = "qcom,psci-mode-shift"; - - ret = of_property_read_u32(node, key, &c->cpu->psci_mode_shift); - if (ret) { - pr_err("Failed reading %s on device %s\n", key, - node->name); - return ret; - } - key = "qcom,psci-mode-mask"; - ret = of_property_read_u32(node, key, &c->cpu->psci_mode_mask); - if (ret) { - pr_err("Failed reading %s on device %s\n", key, - node->name); - return ret; - } - } + struct device_node *n; + int ret, i, j; + const char *key; for_each_child_of_node(node, n) { - struct lpm_cpu_level *l = &c->cpu->levels[c->cpu->nlevels]; + struct lpm_cpu_level *l = &cpu->levels[cpu->nlevels]; - c->cpu->nlevels++; + cpu->nlevels++; ret = parse_cpu_mode(n, l); - if (ret < 0) { - pr_info("Failed %s\n", l->name); - goto failed; - } + if (ret) + return ret; ret = parse_power_params(n, &l->pwr); if (ret) - goto failed; + return ret; key = "qcom,use-broadcast-timer"; l->use_bc_timer = of_property_read_bool(n, key); - l->is_reset = of_property_read_bool(n, "qcom,is-reset"); - - key = "qcom,jtag-save-restore"; - l->jtag_save_restore = of_property_read_bool(n, key); + key = "qcom,is-reset"; + l->is_reset = of_property_read_bool(n, key); key = "qcom,reset-level"; ret = of_property_read_u32(n, key, &l->reset_level); if (ret == -EINVAL) l->reset_level = LPM_RESET_LVL_NONE; else if (ret) - goto failed; + return ret; } - for (i = 0; i < c->cpu->nlevels; i++) { - for (j = 0; j < c->cpu->nlevels; j++) { + + for (i = 0; i < cpu->nlevels; i++) { + for (j = 0; j < cpu->nlevels; j++) { if (i >= j) { - c->cpu->levels[i].pwr.residencies[j] = 0; + cpu->levels[i].pwr.residencies[j] = 0; continue; } - c->cpu->levels[i].pwr.residencies[j] = - calculate_residency(&c->cpu->levels[i].pwr, - &c->cpu->levels[j].pwr); + cpu->levels[i].pwr.residencies[j] = + calculate_residency(&cpu->levels[i].pwr, + &cpu->levels[j].pwr); - pr_err("%s: idx %d %u\n", __func__, j, - c->cpu->levels[i].pwr.residencies[j]); + pr_info("idx %d %u\n", j, + cpu->levels[i].pwr.residencies[j]); } } + for_each_cpu(i, &cpu->related_cpus) { + + per_cpu(max_residency, i) = devm_kzalloc(&lpm_pdev->dev, + sizeof(uint32_t) * cpu->nlevels, GFP_KERNEL); + if (!per_cpu(max_residency, i)) + return -ENOMEM; + + per_cpu(min_residency, i) = devm_kzalloc(&lpm_pdev->dev, + sizeof(uint32_t) * cpu->nlevels, GFP_KERNEL); + if (!per_cpu(min_residency, i)) + return -ENOMEM; + + set_optimum_cpu_residency(cpu, i, true); + } + return 0; -failed: - for (i = 0; i < c->cpu->nlevels; i++) { - kfree(c->cpu->levels[i].name); - c->cpu->levels[i].name = NULL; +} + +static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) +{ + int ret, i; + char *key; + struct lpm_cpu *cpu; + + cpu = devm_kzalloc(&lpm_pdev->dev, sizeof(*cpu), GFP_KERNEL); + if (!cpu) + return -ENOMEM; + + if (get_cpumask_for_node(node, &cpu->related_cpus)) + return -EINVAL; + + cpu->parent = c; + + key = "qcom,psci-mode-shift"; + ret = of_property_read_u32(node, key, &cpu->psci_mode_shift); + if (ret) + goto failed_parse_params; + + key = "qcom,psci-mode-mask"; + ret = of_property_read_u32(node, key, &cpu->psci_mode_mask); + if (ret) + goto failed_parse_params; + + key = "qcom,use-prediction"; + cpu->lpm_prediction = of_property_read_bool(node, key); + + key = "parse_cpu"; + ret = parse_cpu(node, cpu); + if (ret) + goto failed_parse_cpu; + + cpumask_or(&c->child_cpus, &c->child_cpus, &cpu->related_cpus); + list_add(&cpu->list, &c->cpu); + + return ret; + +failed_parse_cpu: + for (i = 0; i < cpu->nlevels; i++) { + kfree(cpu->levels[i].name); + cpu->levels[i].name = NULL; } - kfree(c->cpu); - c->cpu = NULL; - pr_err("%s(): Failed with error code:%d\n", __func__, ret); + +failed_parse_params: + pr_err("Failed to read key: %s node: %s\n", key, node->name); return ret; } void free_cluster_node(struct lpm_cluster *cluster) { - struct list_head *list; - int i; + struct lpm_cpu *cpu, *n; + struct lpm_cluster *cl, *m; - list_for_each(list, &cluster->child) { - struct lpm_cluster *n; - - n = list_entry(list, typeof(*n), list); - list_del(list); - free_cluster_node(n); + list_for_each_entry_safe(cl, m, &cluster->child, list) { + list_del(&cl->list); + free_cluster_node(cl); }; - if (cluster->cpu) { - for (i = 0; i < cluster->cpu->nlevels; i++) { - kfree(cluster->cpu->levels[i].name); - cluster->cpu->levels[i].name = NULL; + list_for_each_entry_safe(cpu, n, &cluster->cpu, list) { + int i; + + list_del(&cpu->list); + for (i = 0; i < cpu->nlevels; i++) { + kfree(cpu->levels[i].name); + cpu->levels[i].name = NULL; } } - for (i = 0; i < cluster->nlevels; i++) { - kfree(cluster->levels[i].mode); - cluster->levels[i].mode = NULL; - } - kfree(cluster->cpu); - kfree(cluster->name); - kfree(cluster->lpm_dev); - cluster->cpu = NULL; - cluster->name = NULL; - cluster->lpm_dev = NULL; - cluster->ndevices = 0; } /* @@ -744,11 +778,12 @@ struct lpm_cluster *parse_cluster(struct device_node *node, return ERR_PTR(-ENOMEM); ret = parse_cluster_params(node, c); - if (ret) goto failed_parse_params; + INIT_LIST_HEAD(&c->list); INIT_LIST_HEAD(&c->child); + INIT_LIST_HEAD(&c->cpu); c->parent = parent; spin_lock_init(&c->sync_lock); c->min_child_level = NR_LPM_LEVELS; @@ -757,9 +792,9 @@ struct lpm_cluster *parse_cluster(struct device_node *node, if (!n->name) continue; + key = "qcom,pm-cluster-level"; if (!of_node_cmp(n->name, key)) { - WARN_ON(!use_psci && c->no_saw_devices); if (parse_cluster_level(n, c)) goto failed_parse_cluster; continue; @@ -769,7 +804,6 @@ struct lpm_cluster *parse_cluster(struct device_node *node, if (!of_node_cmp(n->name, key)) { struct lpm_cluster *child; - WARN_ON(!use_psci && c->no_saw_devices); child = parse_cluster(n, c); if (!child) goto failed_parse_cluster; @@ -783,34 +817,10 @@ struct lpm_cluster *parse_cluster(struct device_node *node, key = "qcom,pm-cpu"; if (!of_node_cmp(n->name, key)) { - /* - * Parse the the cpu node only if a pm-cpu node - * is available, though the mask is defined @ the - * cluster level - */ - if (get_cpumask_for_node(node, &c->child_cpus)) - goto failed_parse_cluster; - if (parse_cpu_levels(n, c)) goto failed_parse_cluster; c->aff_level = 1; - - for_each_cpu(i, &c->child_cpus) { - per_cpu(max_residency, i) = devm_kzalloc( - &lpm_pdev->dev, - sizeof(uint32_t) * c->cpu->nlevels, - GFP_KERNEL); - if (!per_cpu(max_residency, i)) - return ERR_PTR(-ENOMEM); - per_cpu(min_residency, i) = devm_kzalloc( - &lpm_pdev->dev, - sizeof(uint32_t) * c->cpu->nlevels, - GFP_KERNEL); - if (!per_cpu(min_residency, i)) - return ERR_PTR(-ENOMEM); - set_optimum_cpu_residency(c->cpu, i, true); - } } } @@ -840,15 +850,12 @@ struct lpm_cluster *parse_cluster(struct device_node *node, failed_parse_params: c->parent = NULL; pr_err("Failed parse params\n"); - kfree(c); return NULL; } struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev) { struct device_node *top = NULL; - use_psci = of_property_read_bool(pdev->dev.of_node, "qcom,use-psci"); - top = of_find_node_by_name(pdev->dev.of_node, "qcom,pm-cluster"); if (!top) { pr_err("Failed to find root node\n"); @@ -862,6 +869,7 @@ struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev) void cluster_dt_walkthrough(struct lpm_cluster *cluster) { struct list_head *list; + struct lpm_cpu *cpu; int i, j; static int id; char str[10] = {0}; @@ -875,19 +883,15 @@ void cluster_dt_walkthrough(struct lpm_cluster *cluster) for (i = 0; i < cluster->nlevels; i++) { struct lpm_cluster_level *l = &cluster->levels[i]; - - pr_info("%d ndevices:%d\n", __LINE__, cluster->ndevices); - for (j = 0; j < cluster->ndevices; j++) - pr_info("%sDevice: %p id:%p\n", str, - &cluster->name[j], &l->mode[i]); + pr_info("cluster: %s \t level: %s\n", cluster->cluster_name, + l->level_name); } - if (cluster->cpu) { + list_for_each_entry(cpu, &cluster->cpu, list) { pr_info("%d\n", __LINE__); - for (j = 0; j < cluster->cpu->nlevels; j++) - pr_info("%s\tCPU mode: %s id:%d\n", str, - cluster->cpu->levels[j].name, - cluster->cpu->levels[j].mode); + for (j = 0; j < cpu->nlevels; j++) + pr_info("%s\tCPU level name: %s\n", str, + cpu->levels[j].name); } id++; diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 8b59beee4b4a55ab1907157136a9d54b84873f41..19fe2236ee0d8e76c11a3e70a342bd9a83b59234 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2006-2007 Adam Belay * Copyright (C) 2009 Intel Corporation * @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME + #include #include #include @@ -28,35 +30,33 @@ #include #include #include -#include -#include #include -#include #include #include #include #include -#include #include #include #include -#include #include -#include +#include #include -#include #include #include #include "lpm-levels.h" #include +#if defined(CONFIG_COMMON_CLK) +#include "../clk/clk.h" +#elif defined(CONFIG_COMMON_CLK_MSM) +#include "../../drivers/clk/msm/clock.h" +#endif /* CONFIG_COMMON_CLK */ #define CREATE_TRACE_POINTS #include #define SCLK_HZ (32768) -#define SCM_HANDOFF_LOCK_ID "S:7" #define PSCI_POWER_STATE(reset) (reset << 30) #define PSCI_AFFINITY_LEVEL(lvl) ((lvl & 0x3) << 24) -static remote_spinlock_t scm_handoff_lock; +#define BIAS_HYST (bias_hyst * NSEC_PER_MSEC) enum { MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0), @@ -68,7 +68,8 @@ enum debug_event { CPU_EXIT, CLUSTER_ENTER, CLUSTER_EXIT, - PRE_PC_CB, + CPU_HP_STARTING, + CPU_HP_DYING, }; struct lpm_debug { @@ -88,12 +89,16 @@ struct lpm_cluster *lpm_root_node; static bool lpm_prediction = true; module_param_named(lpm_prediction, lpm_prediction, bool, 0664); -static uint32_t ref_stddev = 100; +static uint32_t ref_stddev = 500; module_param_named(ref_stddev, ref_stddev, uint, 0664); -static uint32_t tmr_add = 100; +static uint32_t tmr_add = 1000; module_param_named(tmr_add, tmr_add, uint, 0664); +static uint32_t ref_premature_cnt = 1; +static uint32_t bias_hyst; +module_param_named(bias_hyst, bias_hyst, uint, 0664); + struct lpm_history { uint32_t resi[MAXSAMPLES]; int mode[MAXSAMPLES]; @@ -106,7 +111,7 @@ struct lpm_history { static DEFINE_PER_CPU(struct lpm_history, hist); -static DEFINE_PER_CPU(struct lpm_cluster*, cpu_cluster); +static DEFINE_PER_CPU(struct lpm_cpu*, cpu_lpm); static bool suspend_in_progress; static struct hrtimer lpm_hrtimer; static struct hrtimer histtimer; @@ -121,9 +126,6 @@ static void cluster_prepare(struct lpm_cluster *cluster, const struct cpumask *cpu, int child_idx, bool from_idle, int64_t time); -static bool menu_select; -module_param_named(menu_select, menu_select, bool, 0664); - static int msm_pm_sleep_time_override; module_param_named(sleep_time_override, msm_pm_sleep_time_override, int, 0664); @@ -135,10 +137,16 @@ module_param_named(print_parsed_dt, print_parsed_dt, bool, 0664); static bool sleep_disabled; module_param_named(sleep_disabled, sleep_disabled, bool, 0664); +/** + * msm_cpuidle_get_deep_idle_latency - Get deep idle latency value + * + * Returns an s32 latency value + */ s32 msm_cpuidle_get_deep_idle_latency(void) { return 10; } +EXPORT_SYMBOL(msm_cpuidle_get_deep_idle_latency); void lpm_suspend_wake_time(uint64_t wakeup_time) { @@ -209,7 +217,7 @@ static uint32_t least_cpu_latency(struct list_head *child, struct power_params *pwr_params; struct lpm_cpu *cpu; struct lpm_cluster *n; - uint32_t latency = 0; + uint32_t lat = 0; int i; list_for_each(list, child) { @@ -218,19 +226,21 @@ static uint32_t least_cpu_latency(struct list_head *child, if (strcmp(lat_level->level_name, n->cluster_name)) continue; } - cpu = n->cpu; - for (i = 0; i < cpu->nlevels; i++) { - level = &cpu->levels[i]; - pwr_params = &level->pwr; - if (lat_level->reset_level == level->reset_level) { - if ((latency > pwr_params->latency_us) - || (!latency)) - latency = pwr_params->latency_us; - break; + list_for_each_entry(cpu, &n->cpu, list) { + for (i = 0; i < cpu->nlevels; i++) { + level = &cpu->levels[i]; + pwr_params = &level->pwr; + if (lat_level->reset_level + == level->reset_level) { + if ((lat > pwr_params->latency_us) + || (!lat)) + lat = pwr_params->latency_us; + break; + } } } } - return latency; + return lat; } static struct lpm_cluster *cluster_aff_match(struct lpm_cluster *cluster, @@ -239,9 +249,9 @@ static struct lpm_cluster *cluster_aff_match(struct lpm_cluster *cluster, struct lpm_cluster *n; if ((cluster->aff_level == affinity_level) - || ((cluster->cpu) && (affinity_level == 0))) + || ((!list_empty(&cluster->cpu)) && (affinity_level == 0))) return cluster; - else if (!cluster->cpu) { + else if (list_empty(&cluster->cpu)) { n = list_entry(cluster->child.next, typeof(*n), list); return cluster_aff_match(n, affinity_level); } else @@ -254,7 +264,7 @@ int lpm_get_latency(struct latency_level *level, uint32_t *latency) uint32_t val; if (!lpm_root_node) { - pr_err("%s: lpm_probe not completed\n", __func__); + pr_err("lpm_probe not completed\n"); return -EAGAIN; } @@ -267,8 +277,8 @@ int lpm_get_latency(struct latency_level *level, uint32_t *latency) cluster = cluster_aff_match(lpm_root_node, level->affinity_level); if (!cluster) { - pr_err("%s:No matching cluster found for affinity_level:%d\n", - __func__, level->affinity_level); + pr_err("No matching cluster found for affinity_level:%d\n", + level->affinity_level); return -EINVAL; } @@ -278,8 +288,8 @@ int lpm_get_latency(struct latency_level *level, uint32_t *latency) val = least_cluster_latency(cluster, level); if (!val) { - pr_err("%s:No mode with affinity_level:%d reset_level:%d\n", - __func__, level->affinity_level, level->reset_level); + pr_err("No mode with affinity_level:%d reset_level:%d\n", + level->affinity_level, level->reset_level); return -EINVAL; } @@ -316,16 +326,22 @@ static void update_debug_pc_event(enum debug_event event, uint32_t arg1, static int lpm_dying_cpu(unsigned int cpu) { - struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu); + struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent; + update_debug_pc_event(CPU_HP_DYING, cpu, + cluster->num_children_in_sync.bits[0], + cluster->child_cpus.bits[0], false); cluster_prepare(cluster, get_cpu_mask(cpu), NR_LPM_LEVELS, false, 0); return 0; } static int lpm_starting_cpu(unsigned int cpu) { - struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu); + struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent; + update_debug_pc_event(CPU_HP_STARTING, cpu, + cluster->num_children_in_sync.bits[0], + cluster->child_cpus.bits[0], false); cluster_unprepare(cluster, get_cpu_mask(cpu), NR_LPM_LEVELS, false, 0); return 0; } @@ -378,7 +394,7 @@ static void cluster_timer_init(struct lpm_cluster *cluster) static void clusttimer_cancel(void) { int cpu = raw_smp_processor_id(); - struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu); + struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent; hrtimer_try_to_cancel(&cluster->histtimer); @@ -414,22 +430,6 @@ static void msm_pm_set_timer(uint32_t modified_time_us) hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED); } -static int set_device_mode(struct lpm_cluster *cluster, int ndevice, - struct lpm_cluster_level *level) -{ - struct low_power_ops *ops; - - if (use_psci) - return 0; - - ops = &cluster->lpm_dev[ndevice]; - if (ops && ops->set_mode) - return ops->set_mode(ops, level->mode[ndevice], - level->notify_rpm); - else - return -EINVAL; -} - static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, struct lpm_cpu *cpu, int *idx_restrict, uint32_t *idx_restrict_time) @@ -439,8 +439,9 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, int64_t thresh = LLONG_MAX; struct lpm_history *history = &per_cpu(hist, dev->cpu); uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu); + uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu); - if (!lpm_prediction) + if (!lpm_prediction || !cpu->lpm_prediction) return 0; /* @@ -525,9 +526,17 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, total += history->resi[i]; } } - if (failed > (MAXSAMPLES/2)) { + if (failed >= ref_premature_cnt) { *idx_restrict = j; do_div(total, failed); + for (i = 0; i < j; i++) { + if (total < max_residency[i]) { + *idx_restrict = i+1; + total = max_residency[i]; + break; + } + } + *idx_restrict_time = total; history->stime = ktime_to_us(ktime_get()) + *idx_restrict_time; @@ -575,41 +584,50 @@ static void clear_predict_history(void) static void update_history(struct cpuidle_device *dev, int idx); +static inline bool is_cpu_biased(int cpu) +{ + u64 now = sched_clock(); + u64 last = sched_get_cpu_last_busy_time(cpu); + + if (!last) + return false; + + return (now - last) < BIAS_HYST; +} + static int cpu_power_select(struct cpuidle_device *dev, struct lpm_cpu *cpu) { - int best_level = -1; + int best_level = 0; uint32_t latency_us = pm_qos_request_for_cpu(PM_QOS_CPU_DMA_LATENCY, dev->cpu); - uint32_t sleep_us = - (uint32_t)(ktime_to_us(tick_nohz_get_sleep_length())); + s64 sleep_us = ktime_to_us(tick_nohz_get_sleep_length()); uint32_t modified_time_us = 0; uint32_t next_event_us = 0; int i, idx_restrict; uint32_t lvl_latency_us = 0; uint64_t predicted = 0; uint32_t htime = 0, idx_restrict_time = 0; - uint32_t next_wakeup_us = sleep_us; + uint32_t next_wakeup_us = (uint32_t)sleep_us; uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu); uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu); - if (!cpu) - return -EINVAL; - - if (sleep_disabled) - return 0; + if ((sleep_disabled && !cpu_isolated(dev->cpu)) || sleep_us < 0) + return best_level; idx_restrict = cpu->nlevels + 1; next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu))); + if (is_cpu_biased(dev->cpu) && (!cpu_isolated(dev->cpu))) + goto done_select; + for (i = 0; i < cpu->nlevels; i++) { struct lpm_cpu_level *level = &cpu->levels[i]; struct power_params *pwr_params = &level->pwr; - enum msm_pm_sleep_mode mode = level->mode; bool allow; - allow = lpm_cpu_mode_allow(dev->cpu, i, true); + allow = i ? lpm_cpu_mode_allow(dev->cpu, i, true) : true; if (!allow) continue; @@ -628,7 +646,7 @@ static int cpu_power_select(struct cpuidle_device *dev, next_wakeup_us = next_event_us - lvl_latency_us; } - if (!i) { + if (!i && !cpu_isolated(dev->cpu)) { /* * If the next_wake_us itself is not sufficient for * deeper low power modes than clock gating do not @@ -637,8 +655,8 @@ static int cpu_power_select(struct cpuidle_device *dev, if (next_wakeup_us > max_residency[i]) { predicted = lpm_cpuidle_predict(dev, cpu, &idx_restrict, &idx_restrict_time); - if (predicted < min_residency[i]) - predicted = 0; + if (predicted && (predicted < min_residency[i])) + predicted = min_residency[i]; } else invalidate_predict_history(dev); } @@ -648,10 +666,8 @@ static int cpu_power_select(struct cpuidle_device *dev, best_level = i; - if (next_event_us && next_event_us < sleep_us && - (mode != MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)) - modified_time_us - = next_event_us - lvl_latency_us; + if (next_event_us && next_event_us < sleep_us && !i) + modified_time_us = next_event_us - lvl_latency_us; else modified_time_us = 0; @@ -681,6 +697,7 @@ static int cpu_power_select(struct cpuidle_device *dev, histtimer_start(htime); } +done_select: trace_cpu_power_select(best_level, sleep_us, latency_us, next_event_us); trace_cpu_pred_select(idx_restrict_time ? 2 : (predicted ? 1 : 0), @@ -846,9 +863,8 @@ static void update_cluster_history(struct cluster_history *history, int idx) history->htmr_wkup = 0; tmr = 1; - } else { + } else history->resi[history->hptr] = residency; - } history->mode[history->hptr] = idx; @@ -877,6 +893,7 @@ static void clear_cl_history_each(struct cluster_history *history) history->mode[i] = -1; history->stime[i] = 0; } + history->hptr = 0; history->nsamp = 0; history->flag = 0; @@ -953,10 +970,6 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (!lpm_cluster_mode_allow(cluster, i, from_idle)) continue; - if (level->last_core_only && - cpumask_weight(cpu_online_mask) > 1) - continue; - if (!cpumask_equal(&cluster->num_children_in_sync, &level->num_cpu_votes)) continue; @@ -970,10 +983,14 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (suspend_in_progress && from_idle && level->notify_rpm) continue; + if (level->notify_rpm && !system_sleep_allowed()) + continue; + best_level = i; - if (predicted ? (pred_us <= pwr_params->max_residency) - : (sleep_us <= pwr_params->max_residency)) + if (from_idle && + (predicted ? (pred_us <= pwr_params->max_residency) + : (sleep_us <= pwr_params->max_residency))) break; } @@ -1001,10 +1018,13 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, bool from_idle, int predicted) { struct lpm_cluster_level *level = &cluster->levels[idx]; - int ret, i; + struct cpumask online_cpus; + + cpumask_and(&online_cpus, &cluster->num_children_in_sync, + cpu_online_mask); if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus) - || is_IPI_pending(&cluster->num_children_in_sync)) { + || is_IPI_pending(&online_cpus)) { return -EPERM; } @@ -1022,31 +1042,11 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, ktime_to_us(ktime_get())); } - for (i = 0; i < cluster->ndevices; i++) { - ret = set_device_mode(cluster, i, level); - if (ret) - goto failed_set_mode; - } if (level->notify_rpm) { - struct cpumask nextcpu, *cpumask; - uint64_t us; - uint32_t pred_us; - - us = get_cluster_sleep_time(cluster, &nextcpu, - from_idle, &pred_us); - cpumask = level->disable_dynamic_routing ? NULL : &nextcpu; - - if (ret) { - pr_info("Failed msm_rpm_enter_sleep() rc = %d\n", ret); - goto failed_set_mode; - } - - us = us + 1; clear_predict_history(); clear_cl_predict_history(); - - do_div(us, USEC_PER_SEC/SCLK_HZ); - system_sleep_enter(us); + if (system_sleep_enter()) + return -EBUSY; } /* Notify cluster enter event after successfully config completion */ cluster_notify(cluster, level, true); @@ -1056,23 +1056,10 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, if (predicted && (idx < (cluster->nlevels - 1))) { struct power_params *pwr_params = &cluster->levels[idx].pwr; - tick_broadcast_exit(); clusttimer_start(cluster, pwr_params->max_residency + tmr_add); - tick_broadcast_enter(); } return 0; -failed_set_mode: - - for (i = 0; i < cluster->ndevices; i++) { - int rc = 0; - - level = &cluster->levels[cluster->default_level]; - // rc = set_device_mode(cluster, i, level); - WARN_ON(rc); - } - - return ret; } static void cluster_prepare(struct lpm_cluster *cluster, @@ -1122,10 +1109,10 @@ static void cluster_prepare(struct lpm_cluster *cluster, struct power_params *pwr_params = &cluster->levels[0].pwr; - tick_broadcast_exit(); clusttimer_start(cluster, pwr_params->max_residency + tmr_add); - tick_broadcast_enter(); + + goto failed; } } @@ -1152,7 +1139,7 @@ static void cluster_unprepare(struct lpm_cluster *cluster, { struct lpm_cluster_level *level; bool first_cpu; - int last_level, i, ret; + int last_level, i; if (!cluster) return; @@ -1202,14 +1189,6 @@ static void cluster_unprepare(struct lpm_cluster *cluster, last_level = cluster->last_level; cluster->last_level = cluster->default_level; - for (i = 0; i < cluster->ndevices; i++) { - level = &cluster->levels[cluster->default_level]; - ret = set_device_mode(cluster, i, level); - - WARN_ON(ret); - - } - cluster_notify(cluster, &cluster->levels[last_level], false); if (from_idle) @@ -1221,12 +1200,10 @@ static void cluster_unprepare(struct lpm_cluster *cluster, spin_unlock(&cluster->sync_lock); } -static inline void cpu_prepare(struct lpm_cluster *cluster, int cpu_index, +static inline void cpu_prepare(struct lpm_cpu *cpu, int cpu_index, bool from_idle) { - struct lpm_cpu_level *cpu_level = &cluster->cpu->levels[cpu_index]; - bool jtag_save_restore = - cluster->cpu->levels[cpu_index].jtag_save_restore; + struct lpm_cpu_level *cpu_level = &cpu->levels[cpu_index]; /* Use broadcast timer for aggregating sleep mode within a cluster. * A broadcast timer could be used in the following scenarios @@ -1238,43 +1215,19 @@ static inline void cpu_prepare(struct lpm_cluster *cluster, int cpu_index, * next wakeup within a cluster, in which case, CPU switches over to * use broadcast timer. */ - if (from_idle && cpu_level->use_bc_timer) - tick_broadcast_enter(); - if (from_idle && ((cpu_level->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) - || (cpu_level->mode == - MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE) - || (cpu_level->is_reset))) + if (from_idle && cpu_level->is_reset) cpu_pm_enter(); - /* - * Save JTAG registers for 8996v1.0 & 8996v2.x in C4 LPM - */ - if (jtag_save_restore) - msm_jtag_save_state(); } -static inline void cpu_unprepare(struct lpm_cluster *cluster, int cpu_index, +static inline void cpu_unprepare(struct lpm_cpu *cpu, int cpu_index, bool from_idle) { - struct lpm_cpu_level *cpu_level = &cluster->cpu->levels[cpu_index]; - bool jtag_save_restore = - cluster->cpu->levels[cpu_index].jtag_save_restore; + struct lpm_cpu_level *cpu_level = &cpu->levels[cpu_index]; - if (from_idle && cpu_level->use_bc_timer) - tick_broadcast_exit(); - - if (from_idle && ((cpu_level->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) - || (cpu_level->mode == - MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE) - || cpu_level->is_reset)) + if (from_idle && cpu_level->is_reset) cpu_pm_exit(); - - /* - * Restore JTAG registers for 8996v1.0 & 8996v2.x in C4 LPM - */ - if (jtag_save_restore) - msm_jtag_restore_state(); } int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) @@ -1299,23 +1252,27 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) state_id |= (level->psci_id & cluster->psci_mode_mask) << cluster->psci_mode_shift; (*aff_lvl)++; + + /* + * We may have updated the broadcast timers, update + * the wakeup value by reading the bc timer directly. + */ + if (level->notify_rpm) + system_sleep_update_wakeup(); } unlock_and_return: spin_unlock(&cluster->sync_lock); return state_id; } -#if !defined(CONFIG_CPU_V7) -bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) +static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle) { - int affinity_level = 0; - int state_id = get_cluster_id(cluster, &affinity_level); - int power_state = - PSCI_POWER_STATE(cluster->cpu->levels[idx].is_reset); + int affinity_level = 0, state_id = 0, power_state = 0; bool success = false; /* * idx = 0 is the default LPM state */ + if (!idx) { stop_critical_timings(); wfi(); @@ -1323,70 +1280,41 @@ bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) return 1; } - affinity_level = PSCI_AFFINITY_LEVEL(affinity_level); - state_id |= (power_state | affinity_level - | cluster->cpu->levels[idx].psci_id); - - update_debug_pc_event(CPU_ENTER, state_id, - 0xdeaffeed, 0xdeaffeed, true); - stop_critical_timings(); - success = !arm_cpuidle_suspend(state_id); - start_critical_timings(); - update_debug_pc_event(CPU_EXIT, state_id, - success, 0xdeaffeed, true); - return success; -} -#elif defined(CONFIG_ARM_PSCI) -bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) -{ - int affinity_level = 0; - int state_id = get_cluster_id(cluster, &affinity_level); - int power_state = - PSCI_POWER_STATE(cluster->cpu->levels[idx].is_reset); - bool success = false; - - if (!idx) { - stop_critical_timings(); - wfi(); - start_critical_timings(); - return 1; + if (from_idle && cpu->levels[idx].use_bc_timer) { + if (tick_broadcast_enter()) + return success; } + state_id = get_cluster_id(cpu->parent, &affinity_level); + power_state = PSCI_POWER_STATE(cpu->levels[idx].is_reset); affinity_level = PSCI_AFFINITY_LEVEL(affinity_level); - state_id |= (power_state | affinity_level - | cluster->cpu->levels[idx].psci_id); + state_id |= power_state | affinity_level | cpu->levels[idx].psci_id; update_debug_pc_event(CPU_ENTER, state_id, - 0xdeaffeed, 0xdeaffeed, true); + 0xdeaffeed, 0xdeaffeed, from_idle); stop_critical_timings(); + success = !arm_cpuidle_suspend(state_id); + start_critical_timings(); update_debug_pc_event(CPU_EXIT, state_id, - success, 0xdeaffeed, true); -} -#else -bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) -{ - WARN_ONCE(true, "PSCI cpu_suspend ops not supported\n"); - return false; + success, 0xdeaffeed, from_idle); + + if (from_idle && cpu->levels[idx].use_bc_timer) + tick_broadcast_exit(); + + return success; } -#endif static int lpm_cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { - struct lpm_cluster *cluster = per_cpu(cpu_cluster, dev->cpu); - int idx; - - if (!cluster) - return 0; + struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu); - idx = cpu_power_select(dev, cluster->cpu); - - if (idx < 0) + if (!cpu) return 0; - return idx; + return cpu_power_select(dev, cpu); } static void update_history(struct cpuidle_device *dev, int idx) @@ -1425,38 +1353,36 @@ static void update_history(struct cpuidle_device *dev, int idx) static int lpm_cpuidle_enter(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { - struct lpm_cluster *cluster = per_cpu(cpu_cluster, dev->cpu); - bool success = true; + struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu); + bool success = false; const struct cpumask *cpumask = get_cpu_mask(dev->cpu); - int64_t start_time = ktime_to_ns(ktime_get()), end_time; + ktime_t start = ktime_get(); + uint64_t start_time = ktime_to_ns(start), end_time; struct power_params *pwr_params; - pwr_params = &cluster->cpu->levels[idx].pwr; - - pwr_params = &cluster->cpu->levels[idx].pwr; + pwr_params = &cpu->levels[idx].pwr; + sched_set_cpu_cstate(dev->cpu, idx + 1, + pwr_params->energy_overhead, pwr_params->latency_us); - cpu_prepare(cluster, idx, true); - cluster_prepare(cluster, cpumask, idx, true, ktime_to_ns(ktime_get())); + cpu_prepare(cpu, idx, true); + cluster_prepare(cpu->parent, cpumask, idx, true, start_time); trace_cpu_idle_enter(idx); lpm_stats_cpu_enter(idx, start_time); - if (need_resched() || (idx < 0)) + if (need_resched()) goto exit; - WARN_ON(!use_psci); - success = psci_enter_sleep(cluster, idx, true); + success = psci_enter_sleep(cpu, idx, true); exit: end_time = ktime_to_ns(ktime_get()); lpm_stats_cpu_exit(idx, end_time, success); - cluster_unprepare(cluster, cpumask, idx, true, end_time); - cpu_unprepare(cluster, idx, true); + cluster_unprepare(cpu->parent, cpumask, idx, true, end_time); + cpu_unprepare(cpu, idx, true); sched_set_cpu_cstate(smp_processor_id(), 0, 0, 0); - end_time = ktime_to_ns(ktime_get()) - start_time; - do_div(end_time, 1000); - dev->last_residency = end_time; + dev->last_residency = ktime_us_delta(ktime_get(), start); update_history(dev, idx); trace_cpu_idle_exit(idx, success); local_irq_enable(); @@ -1522,8 +1448,9 @@ static int cluster_cpuidle_register(struct lpm_cluster *cl) int i = 0, ret = 0; unsigned int cpu; struct lpm_cluster *p = NULL; + struct lpm_cpu *lpm_cpu; - if (!cl->cpu) { + if (list_empty(&cl->cpu)) { struct lpm_cluster *n; list_for_each_entry(n, &cl->child, list) { @@ -1534,51 +1461,57 @@ static int cluster_cpuidle_register(struct lpm_cluster *cl) return ret; } - cl->drv = kcalloc(1, sizeof(*cl->drv), GFP_KERNEL); - if (!cl->drv) - return -ENOMEM; - - cl->drv->name = "msm_idle"; - - for (i = 0; i < cl->cpu->nlevels; i++) { - struct cpuidle_state *st = &cl->drv->states[i]; - struct lpm_cpu_level *cpu_level = &cl->cpu->levels[i]; - - snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i); - snprintf(st->desc, CPUIDLE_DESC_LEN, cpu_level->name); - st->flags = 0; - st->exit_latency = cpu_level->pwr.latency_us; - st->power_usage = cpu_level->pwr.ss_power; - st->target_residency = 0; - st->enter = lpm_cpuidle_enter; - } + list_for_each_entry(lpm_cpu, &cl->cpu, list) { + lpm_cpu->drv = kcalloc(1, sizeof(*lpm_cpu->drv), GFP_KERNEL); + if (!lpm_cpu->drv) + return -ENOMEM; + + lpm_cpu->drv->name = "msm_idle"; + + for (i = 0; i < lpm_cpu->nlevels; i++) { + struct cpuidle_state *st = &lpm_cpu->drv->states[i]; + struct lpm_cpu_level *cpu_level = &lpm_cpu->levels[i]; + + snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i); + snprintf(st->desc, CPUIDLE_DESC_LEN, "%s", + cpu_level->name); + st->flags = 0; + st->exit_latency = cpu_level->pwr.latency_us; + st->power_usage = cpu_level->pwr.ss_power; + st->target_residency = 0; + st->enter = lpm_cpuidle_enter; + } - cl->drv->state_count = cl->cpu->nlevels; - cl->drv->safe_state_index = 0; - for_each_cpu(cpu, &cl->child_cpus) - per_cpu(cpu_cluster, cpu) = cl; + lpm_cpu->drv->state_count = lpm_cpu->nlevels; + lpm_cpu->drv->safe_state_index = 0; + for_each_cpu(cpu, &lpm_cpu->related_cpus) + per_cpu(cpu_lpm, cpu) = lpm_cpu; - for_each_possible_cpu(cpu) { - if (cpu_online(cpu)) - continue; - p = per_cpu(cpu_cluster, cpu); - while (p) { - int j; - - spin_lock(&p->sync_lock); - cpumask_set_cpu(cpu, &p->num_children_in_sync); - for (j = 0; j < p->nlevels; j++) - cpumask_copy(&p->levels[j].num_cpu_votes, + for_each_possible_cpu(cpu) { + if (cpu_online(cpu)) + continue; + if (per_cpu(cpu_lpm, cpu)) + p = per_cpu(cpu_lpm, cpu)->parent; + while (p) { + int j; + + spin_lock(&p->sync_lock); + cpumask_set_cpu(cpu, &p->num_children_in_sync); + for (j = 0; j < p->nlevels; j++) + cpumask_copy( + &p->levels[j].num_cpu_votes, &p->num_children_in_sync); - spin_unlock(&p->sync_lock); - p = p->parent; + spin_unlock(&p->sync_lock); + p = p->parent; + } } - } - ret = cpuidle_register_cpu(cl->drv, &cl->child_cpus); + ret = cpuidle_register_cpu(lpm_cpu->drv, + &lpm_cpu->related_cpus); - if (ret) { - kfree(cl->drv); - return -ENOMEM; + if (ret) { + kfree(lpm_cpu->drv); + return -ENOMEM; + } } return 0; } @@ -1608,7 +1541,7 @@ static void register_cpu_lpm_stats(struct lpm_cpu *cpu, level_name[i] = cpu->levels[i].name; lpm_stats_config_level("cpu", level_name, cpu->nlevels, - parent->stats, &parent->child_cpus); + parent->stats, &cpu->related_cpus); kfree(level_name); } @@ -1617,8 +1550,9 @@ static void register_cluster_lpm_stats(struct lpm_cluster *cl, struct lpm_cluster *parent) { const char **level_name; - int i; struct lpm_cluster *child; + struct lpm_cpu *cpu; + int i; if (!cl) return; @@ -1636,10 +1570,12 @@ static void register_cluster_lpm_stats(struct lpm_cluster *cl, kfree(level_name); - if (cl->cpu) { - register_cpu_lpm_stats(cl->cpu, cl); - return; + list_for_each_entry(cpu, &cl->cpu, list) { + pr_err("%s()\n", __func__); + register_cpu_lpm_stats(cpu, cl); } + if (!list_empty(&cl->cpu)) + return; list_for_each_entry(child, &cl->child, list) register_cluster_lpm_stats(child, cl); @@ -1662,13 +1598,12 @@ static void lpm_suspend_wake(void) static int lpm_suspend_enter(suspend_state_t state) { int cpu = raw_smp_processor_id(); - struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu); - struct lpm_cpu *lpm_cpu = cluster->cpu; + struct lpm_cpu *lpm_cpu = per_cpu(cpu_lpm, cpu); + struct lpm_cluster *cluster = lpm_cpu->parent; const struct cpumask *cpumask = get_cpu_mask(cpu); int idx; for (idx = lpm_cpu->nlevels - 1; idx >= 0; idx--) { - if (lpm_cpu_mode_allow(cpu, idx, false)) break; } @@ -1676,11 +1611,8 @@ static int lpm_suspend_enter(suspend_state_t state) pr_err("Failed suspend\n"); return 0; } - cpu_prepare(cluster, idx, false); + cpu_prepare(lpm_cpu, idx, false); cluster_prepare(cluster, cpumask, idx, false, 0); - if (idx > 0) - update_debug_pc_event(CPU_ENTER, idx, 0xdeaffeed, - 0xdeaffeed, false); /* * Print the clocks which are enabled during system suspend @@ -1688,16 +1620,12 @@ static int lpm_suspend_enter(suspend_state_t state) * clocks that are enabled and preventing the system level * LPMs(XO and Vmin). */ + clock_debug_print_enabled(true); - WARN_ON(!use_psci); - psci_enter_sleep(cluster, idx, true); - - if (idx > 0) - update_debug_pc_event(CPU_EXIT, idx, true, 0xdeaffeed, - false); + psci_enter_sleep(lpm_cpu, idx, false); cluster_unprepare(cluster, cpumask, idx, false, 0); - cpu_unprepare(cluster, idx, false); + cpu_unprepare(lpm_cpu, idx, false); return 0; } @@ -1713,12 +1641,13 @@ static int lpm_probe(struct platform_device *pdev) int ret; int size; struct kobject *module_kobj = NULL; + struct md_region md_entry; get_online_cpus(); lpm_root_node = lpm_of_parse_cluster(pdev); if (IS_ERR_OR_NULL(lpm_root_node)) { - pr_err("%s(): Failed to probe low power modes\n", __func__); + pr_err("Failed to probe low power modes\n"); put_online_cpus(); return PTR_ERR(lpm_root_node); } @@ -1737,26 +1666,19 @@ static int lpm_probe(struct platform_device *pdev) hrtimer_init(&histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cluster_timer_init(lpm_root_node); - ret = remote_spin_lock_init(&scm_handoff_lock, SCM_HANDOFF_LOCK_ID); - if (ret) { - pr_err("%s: Failed initializing scm_handoff_lock (%d)\n", - __func__, ret); - put_online_cpus(); - return ret; - } - size = num_dbg_elements * sizeof(struct lpm_debug); lpm_debug = dma_alloc_coherent(&pdev->dev, size, &lpm_debug_phys, GFP_KERNEL); + register_cluster_lpm_stats(lpm_root_node, NULL); ret = cluster_cpuidle_register(lpm_root_node); put_online_cpus(); if (ret) { - pr_err("%s()Failed to register with cpuidle framework\n", - __func__); + pr_err("Failed to register with cpuidle framework\n"); goto failed; } + ret = cpuhp_setup_state(CPUHP_AP_QCOM_SLEEP_STARTING, "AP_QCOM_SLEEP_STARTING", lpm_starting_cpu, lpm_dying_cpu); @@ -1765,19 +1687,25 @@ static int lpm_probe(struct platform_device *pdev) module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME); if (!module_kobj) { - pr_err("%s: cannot find kobject for module %s\n", - __func__, KBUILD_MODNAME); + pr_err("Cannot find kobject for module %s\n", KBUILD_MODNAME); ret = -ENOENT; goto failed; } ret = create_cluster_lvl_nodes(lpm_root_node, module_kobj); if (ret) { - pr_err("%s(): Failed to create cluster level nodes\n", - __func__); + pr_err("Failed to create cluster level nodes\n"); goto failed; } + /* Add lpm_debug to Minidump*/ + strlcpy(md_entry.name, "KLPMDEBUG", sizeof(md_entry.name)); + md_entry.virt_addr = (uintptr_t)lpm_debug; + md_entry.phys_addr = lpm_debug_phys; + md_entry.size = size; + if (msm_minidump_add_region(&md_entry)) + pr_info("Failed to add lpm_debug in Minidump\n"); + return 0; failed: free_cluster_node(lpm_root_node); @@ -1813,54 +1741,3 @@ static int __init lpm_levels_module_init(void) return rc; } late_initcall(lpm_levels_module_init); - -enum msm_pm_l2_scm_flag lpm_cpu_pre_pc_cb(unsigned int cpu) -{ - struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu); - enum msm_pm_l2_scm_flag retflag = MSM_SCM_L2_ON; - - /* - * No need to acquire the lock if probe isn't completed yet - * In the event of the hotplug happening before lpm probe, we want to - * flush the cache to make sure that L2 is flushed. In particular, this - * could cause incoherencies for a cluster architecture. This wouldn't - * affect the idle case as the idle driver wouldn't be registered - * before the probe function - */ - if (!cluster) - return MSM_SCM_L2_OFF; - - /* - * Assumes L2 only. What/How parameters gets passed into TZ will - * determine how this function reports this info back in msm-pm.c - */ - spin_lock(&cluster->sync_lock); - - if (!cluster->lpm_dev) { - retflag = MSM_SCM_L2_OFF; - goto unlock_and_return; - } - - if (!cpumask_equal(&cluster->num_children_in_sync, - &cluster->child_cpus)) - goto unlock_and_return; - - if (cluster->lpm_dev) - retflag = cluster->lpm_dev->tz_flag; - /* - * The scm_handoff_lock will be release by the secure monitor. - * It is used to serialize power-collapses from this point on, - * so that both Linux and the secure context have a consistent - * view regarding the number of running cpus (cpu_count). - * - * It must be acquired before releasing the cluster lock. - */ -unlock_and_return: - update_debug_pc_event(PRE_PC_CB, retflag, 0xdeadbeef, 0xdeadbeef, - 0xdeadbeef); - trace_pre_pc_cb(retflag); - remote_spin_lock_rlock_id(&scm_handoff_lock, - REMOTE_SPINLOCK_TID_START + cpu); - spin_unlock(&cluster->sync_lock); - return retflag; -} diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 6c9a50b34112e6f021b482e92a8f91f4ae3a047f..2f7a55d195a86b80ae8d71cf2b46a0b77d00007b 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 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 @@ -17,13 +17,6 @@ #define MAXSAMPLES 5 #define CLUST_SMPL_INVLD_TIME 40000 -extern bool use_psci; - -struct lpm_lookup_table { - uint32_t modes; - const char *mode_name; -}; - struct power_params { uint32_t latency_us; /* Enter + Exit latency */ uint32_t ss_power; /* Steady state power */ @@ -36,30 +29,33 @@ struct power_params { struct lpm_cpu_level { const char *name; - enum msm_pm_sleep_mode mode; bool use_bc_timer; struct power_params pwr; unsigned int psci_id; bool is_reset; - bool jtag_save_restore; - bool hyp_psci; int reset_level; }; struct lpm_cpu { + struct list_head list; + struct cpumask related_cpus; struct lpm_cpu_level levels[NR_LPM_LEVELS]; int nlevels; unsigned int psci_mode_shift; unsigned int psci_mode_mask; + bool lpm_prediction; + struct cpuidle_driver *drv; struct lpm_cluster *parent; }; struct lpm_level_avail { bool idle_enabled; bool suspend_enabled; + uint32_t latency_us; struct kobject *kobj; struct kobj_attribute idle_enabled_attr; struct kobj_attribute suspend_enabled_attr; + struct kobj_attribute latency_attr; void *data; int idx; bool cpu_node; @@ -67,26 +63,17 @@ struct lpm_level_avail { struct lpm_cluster_level { const char *level_name; - int *mode; /* SPM mode to enter */ int min_child_level; struct cpumask num_cpu_votes; struct power_params pwr; bool notify_rpm; - bool disable_dynamic_routing; bool sync_level; - bool last_core_only; struct lpm_level_avail available; unsigned int psci_id; bool is_reset; int reset_level; }; -struct low_power_ops { - struct msm_spm_device *spm; - int (*set_mode)(struct low_power_ops *ops, int mode, bool notify_rpm); - enum msm_pm_l2_scm_flag tz_flag; -}; - struct cluster_history { uint32_t resi[MAXSAMPLES]; int mode[MAXSAMPLES]; @@ -104,18 +91,13 @@ struct lpm_cluster { struct list_head list; struct list_head child; const char *cluster_name; - const char **name; unsigned long aff_level; /* Affinity level of the node */ - struct low_power_ops *lpm_dev; - int ndevices; struct lpm_cluster_level levels[NR_LPM_LEVELS]; int nlevels; - enum msm_pm_l2_scm_flag l2_flag; int min_child_level; int default_level; int last_level; - struct lpm_cpu *cpu; - struct cpuidle_driver *drv; + struct list_head cpu; spinlock_t sync_lock; struct cpumask child_cpus; struct cpumask num_children_in_sync; @@ -123,14 +105,10 @@ struct lpm_cluster { struct lpm_stats *stats; unsigned int psci_mode_shift; unsigned int psci_mode_mask; - bool no_saw_devices; struct cluster_history history; struct hrtimer histtimer; }; -int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm); -int set_system_mode(struct low_power_ops *ops, int mode, bool notify_rpm); -int set_l3_mode(struct low_power_ops *ops, int mode, bool notify_rpm); void lpm_suspend_wake_time(uint64_t wakeup_time); struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev); @@ -146,7 +124,7 @@ uint32_t *get_per_cpu_max_residency(int cpu); uint32_t *get_per_cpu_min_residency(int cpu); extern struct lpm_cluster *lpm_root_node; -#if CONFIG_SMP +#if defined(CONFIG_SMP) extern DEFINE_PER_CPU(bool, pending_ipi); static inline bool is_IPI_pending(const struct cpumask *mask) { diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 832a2c3f01ffccf691842507955078299799eb86..9e98a5fbbc1d7fadafc7861ceae1967d8032f956 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -613,6 +613,18 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; + /* + * Return if cpu_device is not setup for this CPU. + * + * This could happen if the arch did not set up cpu_device + * since this CPU is not in cpu_present mask and the + * driver did not send a correct CPU mask during registration. + * Without this check we would end up passing bogus + * value for &cpu_dev->kobj in kobject_init_and_add() + */ + if (!cpu_dev) + return -ENODEV; + kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); if (!kdev) return -ENOMEM; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index fd02ebada2824f561ab35102e53c7fc624f442d0..f61b78ab5660d5d33bad8efd1a4e56268472891c 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -385,58 +385,6 @@ config CRYPTO_DEV_S5P Select this to offload Samsung S5PV210 or S5PC110, Exynos from AES algorithms execution. -config CRYPTO_DEV_QCE50 - bool - -config FIPS_ENABLE - bool "FIPS140-2 compliant build" - default n - help - This flag is used to make current build FIPS140-2 - compliant. This flag will enable the patch of code - which will perform this task. Please select Y here - to enable. - -config CRYPTO_DEV_QCRYPTO - tristate "QTI Crypto accelerator" - select CRYPTO_DES - select CRYPTO_ALGAPI - select CRYPTO_AUTHENC - select CRYPTO_BLKCIPHER - default n - help - This driver supports QTI crypto acceleration - for kernel clients. To compile this driver as a module, - choose M here: the module will be called qcrypto. Please - select Y here to enable. - -config CRYPTO_DEV_QCOM_MSM_QCE - tristate "QTI Crypto Engine (QCE) module" - default n - help - This driver supports QTI Crypto Engine 5.0. - To compile this driver as a module, choose M here: the - module is called qce50. - -config CRYPTO_DEV_QCEDEV - tristate "QCEDEV Interface to CE module" - default n - help - This driver supports QTI QCEDEV Crypto Engine 5.0. - This exposes the interface to the QCE hardware accelerator - via IOCTLs. - - To compile this driver as a module, choose M here: the - module will be called qcedev. - -config CRYPTO_DEV_OTA_CRYPTO - tristate "OTA Crypto module" - help - This driver supports QTI OTA Crypto in the FSM9xxx. - To compile this driver as a module, choose M here: the - module will be called ota_crypto. Please select Y here - to enable. - config CRYPTO_DEV_NX bool "Support for IBM PowerPC Nest (NX) cryptographic acceleration" depends on PPC64 @@ -550,7 +498,49 @@ config CRYPTO_DEV_QCE help This driver supports Qualcomm crypto engine accelerator hardware. To compile this driver as a module, choose M here. The - module will be called qcrypto. + module will be called qcrypt. + +config CRYPTO_DEV_QCOM_MSM_QCE + tristate "QTI Crypto Engine (QCE) module" + depends on ARCH_QCOM + help + This driver supports QTI Crypto Engine accelerator hardware, which + is present on SDM845. This is the core crypto driver which adds + CE5.0 functionalities. To compile this driver as a module, choose + M here. The module will be called QCE50. + +config CRYPTO_DEV_QCRYPTO + tristate "QTI Crypto accelerator" + depends on ARCH_QCOM + select CRYPTO_DES + select CRYPTO_ALGAPI + select CRYPTO_AUTHENC + select CRYPTO_BLKCIPHER + help + This driver supports QTI crypto acceleration + for kernel clients. To compile this driver as a module, + choose M here: the module will be called qcrypto. Please + select Y here to enable. + +config CRYPTO_DEV_QCEDEV + tristate "QCEDEV Interface to CE module" + depends on ARCH_QCOM + help + This driver supports QTI QCEDEV Crypto Engine 5.0. + This exposes the interface to the QCE hardware accelerator + via IOCTLs. + + To compile this driver as a module, choose M here: the + module will be called qcedev. + +config CRYPTO_DEV_OTA_CRYPTO + tristate "OTA Crypto module" + depends on ARCH_QCOM + help + This driver supports QTI OTA Crypto in the FSM9xxx. + To compile this driver as a module, choose M here: the + module will be called ota_crypto. Please select Y here + to enable. config CRYPTO_DEV_VMX bool "Support for VMX cryptographic acceleration instructions" diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index ecfdcfe3698d62204ffa3f4f9096d0769c4094b5..4f41d6da5acca7d1dedbb3419619a8b327b53564 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -34,12 +34,12 @@ #define PPC405EX_CE_RESET 0x00000008 #define CRYPTO4XX_CRYPTO_PRIORITY 300 -#define PPC4XX_LAST_PD 63 -#define PPC4XX_NUM_PD 64 -#define PPC4XX_LAST_GD 1023 +#define PPC4XX_NUM_PD 256 +#define PPC4XX_LAST_PD (PPC4XX_NUM_PD - 1) #define PPC4XX_NUM_GD 1024 -#define PPC4XX_LAST_SD 63 -#define PPC4XX_NUM_SD 64 +#define PPC4XX_LAST_GD (PPC4XX_NUM_GD - 1) +#define PPC4XX_NUM_SD 256 +#define PPC4XX_LAST_SD (PPC4XX_NUM_SD - 1) #define PPC4XX_SD_BUFFER_SIZE 2048 #define PD_ENTRY_INUSE 1 diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 97e34799e077cacf80140c024f360cb23a92d1b0..6fcf25f795d43e42dd87befd487758b27bcf5b0d 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1000,7 +1000,9 @@ static int atmel_sha_finup(struct ahash_request *req) ctx->flags |= SHA_FLAGS_FINUP; err1 = atmel_sha_update(req); - if (err1 == -EINPROGRESS || err1 == -EBUSY) + if (err1 == -EINPROGRESS || + (err1 == -EBUSY && (ahash_request_flags(req) & + CRYPTO_TFM_REQ_MAY_BACKLOG))) return err1; /* diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index c310318b34ddced2b286d82f9007150219526efa..0d743c634f25aa9231c5e000290f9360fe76edec 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -2014,10 +2014,10 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct ablkcipher_request *req = context; struct ablkcipher_edesc *edesc; -#ifdef DEBUG struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); +#ifdef DEBUG dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif @@ -2037,6 +2037,14 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, #endif ablkcipher_unmap(jrdev, edesc, req); + + /* + * The crypto API expects us to set the IV (req->info) to the last + * ciphertext block. This is used e.g. by the CTS mode. + */ + scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, + ivsize, 0); + kfree(edesc); ablkcipher_request_complete(req, err); @@ -2047,10 +2055,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct ablkcipher_request *req = context; struct ablkcipher_edesc *edesc; -#ifdef DEBUG struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); +#ifdef DEBUG dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif @@ -2069,6 +2077,14 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, #endif ablkcipher_unmap(jrdev, edesc, req); + + /* + * The crypto API expects us to set the IV (req->info) to the last + * ciphertext block. + */ + scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize, + ivsize, 0); + kfree(edesc); ablkcipher_request_complete(req, err); @@ -2601,8 +2617,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; int src_nents, dst_nents = 0, sec4_sg_bytes; struct ablkcipher_edesc *edesc; diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 660dc206969faa509ae8b858d2c2c8296e097d32..631337c2e4a74e07d375d8fe17a5c705afafeb88 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -154,6 +154,7 @@ static inline int map_seq_out_ptr_ctx(u32 *desc, struct device *jrdev, ctx_len, DMA_FROM_DEVICE); if (dma_mapping_error(jrdev, state->ctx_dma)) { dev_err(jrdev, "unable to map ctx\n"); + state->ctx_dma = 0; return -ENOMEM; } @@ -214,6 +215,7 @@ static inline int ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev, state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, flag); if (dma_mapping_error(jrdev, state->ctx_dma)) { dev_err(jrdev, "unable to map ctx\n"); + state->ctx_dma = 0; return -ENOMEM; } @@ -489,7 +491,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); if (!ret) { /* in progress */ - wait_for_completion_interruptible(&result.completion); + wait_for_completion(&result.completion); ret = result.err; #ifdef DEBUG print_hex_dump(KERN_ERR, @@ -620,8 +622,10 @@ static inline void ahash_unmap_ctx(struct device *dev, struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct caam_hash_state *state = ahash_request_ctx(req); - if (state->ctx_dma) + if (state->ctx_dma) { dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag); + state->ctx_dma = 0; + } ahash_unmap(dev, edesc, req, dst_len); } @@ -1605,6 +1609,7 @@ static int ahash_init(struct ahash_request *req) state->finup = ahash_finup_first; state->final = ahash_final_no_ctx; + state->ctx_dma = 0; state->current_buf = 0; state->buf_dma = 0; state->buflen_0 = 0; diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 5d4c05074a5c222b03011db9b0cc41b1078a7725..e2bcacc1a921675cf30f70a40816e1306a8c3ef9 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -41,6 +41,7 @@ struct caam_drv_private_jr { struct device *dev; int ridx; struct caam_job_ring __iomem *rregs; /* JobR's register space */ + struct tasklet_struct irqtask; int irq; /* One per queue */ /* Number of scatterlist crypt transforms active on the JobR */ diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 757c27f9953d52aa4b662f317b7c0d5ff508a685..9e7f28122bb7fe5a88eb80d7ed6f9dcbe98cd0d5 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -73,6 +73,8 @@ static int caam_jr_shutdown(struct device *dev) ret = caam_reset_hw_jr(dev); + tasklet_kill(&jrp->irqtask); + /* Release interrupt */ free_irq(jrp->irq, dev); @@ -128,7 +130,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) /* * Check the output ring for ready responses, kick - * the threaded irq if jobs done. + * tasklet if jobs done. */ irqstate = rd_reg32(&jrp->rregs->jrintstatus); if (!irqstate) @@ -150,13 +152,18 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) /* Have valid interrupt at this point, just ACK and trigger */ wr_reg32(&jrp->rregs->jrintstatus, irqstate); - return IRQ_WAKE_THREAD; + preempt_disable(); + tasklet_schedule(&jrp->irqtask); + preempt_enable(); + + return IRQ_HANDLED; } -static irqreturn_t caam_jr_threadirq(int irq, void *st_dev) +/* Deferred service handler, run as interrupt-fired tasklet */ +static void caam_jr_dequeue(unsigned long devarg) { int hw_idx, sw_idx, i, head, tail; - struct device *dev = st_dev; + struct device *dev = (struct device *)devarg; struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); u32 *userdesc, userstatus; @@ -230,8 +237,6 @@ static irqreturn_t caam_jr_threadirq(int irq, void *st_dev) /* reenable / unmask IRQs */ clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0); - - return IRQ_HANDLED; } /** @@ -389,10 +394,11 @@ static int caam_jr_init(struct device *dev) jrp = dev_get_drvdata(dev); + tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); + /* Connect job ring interrupt handler. */ - error = request_threaded_irq(jrp->irq, caam_jr_interrupt, - caam_jr_threadirq, IRQF_SHARED, - dev_name(dev), dev); + error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, + dev_name(dev), dev); if (error) { dev_err(dev, "can't connect JobR %d interrupt (%d)\n", jrp->ridx, jrp->irq); @@ -454,6 +460,7 @@ static int caam_jr_init(struct device *dev) out_free_irq: free_irq(jrp->irq, dev); out_kill_deq: + tasklet_kill(&jrp->irqtask); return error; } diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index e1eaf4ff9762646acac020c85c77bb122c570f0e..3ce1d5cdcbd22ec18677b48c40b2b008c4d7d657 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -103,7 +103,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); if (!ret) { /* in progress */ - wait_for_completion_interruptible(&result.completion); + wait_for_completion(&result.completion); ret = result.err; #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index 58a4244b4752997fdc645304db0f1f881451e67f..3f26a415ef44b4f4115e695005498db5efc3363a 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -1,8 +1,9 @@ /* * AMD Cryptographic Coprocessor (CCP) AES XTS crypto API support * - * Copyright (C) 2013 Advanced Micro Devices, Inc. + * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. * + * Author: Gary R Hook * Author: Tom Lendacky * * This program is free software; you can redistribute it and/or modify @@ -164,6 +165,7 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, memset(&rctx->cmd, 0, sizeof(rctx->cmd)); INIT_LIST_HEAD(&rctx->cmd.entry); rctx->cmd.engine = CCP_ENGINE_XTS_AES_128; + rctx->cmd.u.xts.type = CCP_AES_TYPE_128; rctx->cmd.u.xts.action = (encrypt) ? CCP_AES_ACTION_ENCRYPT : CCP_AES_ACTION_DECRYPT; rctx->cmd.u.xts.unit_size = unit_size; diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 8d2dbacc6161fd071a5ef64f063f49ccba7e5c36..e68966bbfa587a184ed431898364f3bd3fc86596 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -315,17 +315,73 @@ static int ccp_perform_ecc(struct ccp_op *op) return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); } +static void ccp_disable_queue_interrupts(struct ccp_device *ccp) +{ + iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG); +} + +static void ccp_enable_queue_interrupts(struct ccp_device *ccp) +{ + iowrite32(ccp->qim, ccp->io_regs + IRQ_MASK_REG); +} + +static void ccp_irq_bh(unsigned long data) +{ + struct ccp_device *ccp = (struct ccp_device *)data; + struct ccp_cmd_queue *cmd_q; + u32 q_int, status; + unsigned int i; + + status = ioread32(ccp->io_regs + IRQ_STATUS_REG); + + for (i = 0; i < ccp->cmd_q_count; i++) { + cmd_q = &ccp->cmd_q[i]; + + q_int = status & (cmd_q->int_ok | cmd_q->int_err); + if (q_int) { + cmd_q->int_status = status; + cmd_q->q_status = ioread32(cmd_q->reg_status); + cmd_q->q_int_status = ioread32(cmd_q->reg_int_status); + + /* On error, only save the first error value */ + if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error) + cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status); + + cmd_q->int_rcvd = 1; + + /* Acknowledge the interrupt and wake the kthread */ + iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG); + wake_up_interruptible(&cmd_q->int_queue); + } + } + ccp_enable_queue_interrupts(ccp); +} + +static irqreturn_t ccp_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct ccp_device *ccp = dev_get_drvdata(dev); + + ccp_disable_queue_interrupts(ccp); + if (ccp->use_tasklet) + tasklet_schedule(&ccp->irq_tasklet); + else + ccp_irq_bh((unsigned long)ccp); + + return IRQ_HANDLED; +} + static int ccp_init(struct ccp_device *ccp) { struct device *dev = ccp->dev; struct ccp_cmd_queue *cmd_q; struct dma_pool *dma_pool; char dma_pool_name[MAX_DMAPOOL_NAME_LEN]; - unsigned int qmr, qim, i; + unsigned int qmr, i; int ret; /* Find available queues */ - qim = 0; + ccp->qim = 0; qmr = ioread32(ccp->io_regs + Q_MASK_REG); for (i = 0; i < MAX_HW_QUEUES; i++) { if (!(qmr & (1 << i))) @@ -370,7 +426,7 @@ static int ccp_init(struct ccp_device *ccp) init_waitqueue_head(&cmd_q->int_queue); /* Build queue interrupt mask (two interrupts per queue) */ - qim |= cmd_q->int_ok | cmd_q->int_err; + ccp->qim |= cmd_q->int_ok | cmd_q->int_err; #ifdef CONFIG_ARM64 /* For arm64 set the recommended queue cache settings */ @@ -388,14 +444,14 @@ static int ccp_init(struct ccp_device *ccp) dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count); /* Disable and clear interrupts until ready */ - iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG); + ccp_disable_queue_interrupts(ccp); for (i = 0; i < ccp->cmd_q_count; i++) { cmd_q = &ccp->cmd_q[i]; ioread32(cmd_q->reg_int_status); ioread32(cmd_q->reg_status); } - iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG); + iowrite32(ccp->qim, ccp->io_regs + IRQ_STATUS_REG); /* Request an irq */ ret = ccp->get_irq(ccp); @@ -408,6 +464,11 @@ static int ccp_init(struct ccp_device *ccp) init_waitqueue_head(&ccp->sb_queue); init_waitqueue_head(&ccp->suspend_queue); + /* Initialize the ISR tasklet? */ + if (ccp->use_tasklet) + tasklet_init(&ccp->irq_tasklet, ccp_irq_bh, + (unsigned long)ccp); + dev_dbg(dev, "Starting threads...\n"); /* Create a kthread for each queue */ for (i = 0; i < ccp->cmd_q_count; i++) { @@ -430,7 +491,7 @@ static int ccp_init(struct ccp_device *ccp) dev_dbg(dev, "Enabling interrupts...\n"); /* Enable interrupts */ - iowrite32(qim, ccp->io_regs + IRQ_MASK_REG); + ccp_enable_queue_interrupts(ccp); dev_dbg(dev, "Registering device...\n"); ccp_add_device(ccp); @@ -467,7 +528,7 @@ static void ccp_destroy(struct ccp_device *ccp) { struct ccp_cmd_queue *cmd_q; struct ccp_cmd *cmd; - unsigned int qim, i; + unsigned int i; /* Unregister the DMA engine */ ccp_dmaengine_unregister(ccp); @@ -478,22 +539,15 @@ static void ccp_destroy(struct ccp_device *ccp) /* Remove this device from the list of available units */ ccp_del_device(ccp); - /* Build queue interrupt mask (two interrupt masks per queue) */ - qim = 0; - for (i = 0; i < ccp->cmd_q_count; i++) { - cmd_q = &ccp->cmd_q[i]; - qim |= cmd_q->int_ok | cmd_q->int_err; - } - /* Disable and clear interrupts */ - iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG); + ccp_disable_queue_interrupts(ccp); for (i = 0; i < ccp->cmd_q_count; i++) { cmd_q = &ccp->cmd_q[i]; ioread32(cmd_q->reg_int_status); ioread32(cmd_q->reg_status); } - iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG); + iowrite32(ccp->qim, ccp->io_regs + IRQ_STATUS_REG); /* Stop the queue kthreads */ for (i = 0; i < ccp->cmd_q_count; i++) @@ -520,40 +574,6 @@ static void ccp_destroy(struct ccp_device *ccp) } } -static irqreturn_t ccp_irq_handler(int irq, void *data) -{ - struct device *dev = data; - struct ccp_device *ccp = dev_get_drvdata(dev); - struct ccp_cmd_queue *cmd_q; - u32 q_int, status; - unsigned int i; - - status = ioread32(ccp->io_regs + IRQ_STATUS_REG); - - for (i = 0; i < ccp->cmd_q_count; i++) { - cmd_q = &ccp->cmd_q[i]; - - q_int = status & (cmd_q->int_ok | cmd_q->int_err); - if (q_int) { - cmd_q->int_status = status; - cmd_q->q_status = ioread32(cmd_q->reg_status); - cmd_q->q_int_status = ioread32(cmd_q->reg_int_status); - - /* On error, only save the first error value */ - if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error) - cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status); - - cmd_q->int_rcvd = 1; - - /* Acknowledge the interrupt and wake the kthread */ - iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG); - wake_up_interruptible(&cmd_q->int_queue); - } - } - - return IRQ_HANDLED; -} - static const struct ccp_actions ccp3_actions = { .aes = ccp_perform_aes, .xts_aes = ccp_perform_xts_aes, diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index a388bf2d67f47ac27d6f4a0f6579f11f71af1457..71980c41283bf985b1a2d4c4556aed449dd5e522 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -131,6 +131,7 @@ union ccp_function { #define CCP_AES_MODE(p) ((p)->aes.mode) #define CCP_AES_TYPE(p) ((p)->aes.type) #define CCP_XTS_SIZE(p) ((p)->aes_xts.size) +#define CCP_XTS_TYPE(p) ((p)->aes_xts.type) #define CCP_XTS_ENCRYPT(p) ((p)->aes_xts.encrypt) #define CCP_SHA_TYPE(p) ((p)->sha.type) #define CCP_RSA_SIZE(p) ((p)->rsa.size) @@ -277,8 +278,7 @@ static int ccp5_perform_aes(struct ccp_op *op) CCP_AES_ENCRYPT(&function) = op->u.aes.action; CCP_AES_MODE(&function) = op->u.aes.mode; CCP_AES_TYPE(&function) = op->u.aes.type; - if (op->u.aes.mode == CCP_AES_MODE_CFB) - CCP_AES_SIZE(&function) = 0x7f; + CCP_AES_SIZE(&function) = op->u.aes.size; CCP5_CMD_FUNCTION(&desc) = function.raw; @@ -318,6 +318,7 @@ static int ccp5_perform_xts_aes(struct ccp_op *op) CCP5_CMD_PROT(&desc) = 0; function.raw = 0; + CCP_XTS_TYPE(&function) = op->u.xts.type; CCP_XTS_ENCRYPT(&function) = op->u.xts.action; CCP_XTS_SIZE(&function) = op->u.xts.unit_size; CCP5_CMD_FUNCTION(&desc) = function.raw; @@ -644,6 +645,65 @@ static int ccp_assign_lsbs(struct ccp_device *ccp) return rc; } +static void ccp5_disable_queue_interrupts(struct ccp_device *ccp) +{ + unsigned int i; + + for (i = 0; i < ccp->cmd_q_count; i++) + iowrite32(0x0, ccp->cmd_q[i].reg_int_enable); +} + +static void ccp5_enable_queue_interrupts(struct ccp_device *ccp) +{ + unsigned int i; + + for (i = 0; i < ccp->cmd_q_count; i++) + iowrite32(SUPPORTED_INTERRUPTS, ccp->cmd_q[i].reg_int_enable); +} + +static void ccp5_irq_bh(unsigned long data) +{ + struct ccp_device *ccp = (struct ccp_device *)data; + u32 status; + unsigned int i; + + for (i = 0; i < ccp->cmd_q_count; i++) { + struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i]; + + status = ioread32(cmd_q->reg_interrupt_status); + + if (status) { + cmd_q->int_status = status; + cmd_q->q_status = ioread32(cmd_q->reg_status); + cmd_q->q_int_status = ioread32(cmd_q->reg_int_status); + + /* On error, only save the first error value */ + if ((status & INT_ERROR) && !cmd_q->cmd_error) + cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status); + + cmd_q->int_rcvd = 1; + + /* Acknowledge the interrupt and wake the kthread */ + iowrite32(status, cmd_q->reg_interrupt_status); + wake_up_interruptible(&cmd_q->int_queue); + } + } + ccp5_enable_queue_interrupts(ccp); +} + +static irqreturn_t ccp5_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct ccp_device *ccp = dev_get_drvdata(dev); + + ccp5_disable_queue_interrupts(ccp); + if (ccp->use_tasklet) + tasklet_schedule(&ccp->irq_tasklet); + else + ccp5_irq_bh((unsigned long)ccp); + return IRQ_HANDLED; +} + static int ccp5_init(struct ccp_device *ccp) { struct device *dev = ccp->dev; @@ -728,19 +788,18 @@ static int ccp5_init(struct ccp_device *ccp) dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count); /* Turn off the queues and disable interrupts until ready */ + ccp5_disable_queue_interrupts(ccp); for (i = 0; i < ccp->cmd_q_count; i++) { cmd_q = &ccp->cmd_q[i]; cmd_q->qcontrol = 0; /* Start with nothing */ iowrite32(cmd_q->qcontrol, cmd_q->reg_control); - /* Disable the interrupts */ - iowrite32(0x00, cmd_q->reg_int_enable); ioread32(cmd_q->reg_int_status); ioread32(cmd_q->reg_status); - /* Clear the interrupts */ - iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status); + /* Clear the interrupt status */ + iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status); } dev_dbg(dev, "Requesting an IRQ...\n"); @@ -750,6 +809,10 @@ static int ccp5_init(struct ccp_device *ccp) dev_err(dev, "unable to allocate an IRQ\n"); goto e_pool; } + /* Initialize the ISR tasklet */ + if (ccp->use_tasklet) + tasklet_init(&ccp->irq_tasklet, ccp5_irq_bh, + (unsigned long)ccp); /* Initialize the queue used to suspend */ init_waitqueue_head(&ccp->suspend_queue); @@ -821,11 +884,7 @@ static int ccp5_init(struct ccp_device *ccp) } dev_dbg(dev, "Enabling interrupts...\n"); - /* Enable interrupts */ - for (i = 0; i < ccp->cmd_q_count; i++) { - cmd_q = &ccp->cmd_q[i]; - iowrite32(ALL_INTERRUPTS, cmd_q->reg_int_enable); - } + ccp5_enable_queue_interrupts(ccp); dev_dbg(dev, "Registering device...\n"); /* Put this on the unit list to make it available */ @@ -877,17 +936,15 @@ static void ccp5_destroy(struct ccp_device *ccp) ccp_del_device(ccp); /* Disable and clear interrupts */ + ccp5_disable_queue_interrupts(ccp); for (i = 0; i < ccp->cmd_q_count; i++) { cmd_q = &ccp->cmd_q[i]; /* Turn off the run bit */ iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control); - /* Disable the interrupts */ - iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status); - /* Clear the interrupt status */ - iowrite32(0x00, cmd_q->reg_int_enable); + iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status); ioread32(cmd_q->reg_int_status); ioread32(cmd_q->reg_status); } @@ -920,38 +977,6 @@ static void ccp5_destroy(struct ccp_device *ccp) } } -static irqreturn_t ccp5_irq_handler(int irq, void *data) -{ - struct device *dev = data; - struct ccp_device *ccp = dev_get_drvdata(dev); - u32 status; - unsigned int i; - - for (i = 0; i < ccp->cmd_q_count; i++) { - struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i]; - - status = ioread32(cmd_q->reg_interrupt_status); - - if (status) { - cmd_q->int_status = status; - cmd_q->q_status = ioread32(cmd_q->reg_status); - cmd_q->q_int_status = ioread32(cmd_q->reg_int_status); - - /* On error, only save the first error value */ - if ((status & INT_ERROR) && !cmd_q->cmd_error) - cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status); - - cmd_q->int_rcvd = 1; - - /* Acknowledge the interrupt and wake the kthread */ - iowrite32(ALL_INTERRUPTS, cmd_q->reg_interrupt_status); - wake_up_interruptible(&cmd_q->int_queue); - } - } - - return IRQ_HANDLED; -} - static void ccp5_config(struct ccp_device *ccp) { /* Public side */ diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 340aef14d616fd6ab06b82a7a4cac149e92efc8a..347b77108baa62774f8fe1f7ce8f155be354c077 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -109,9 +109,8 @@ #define INT_COMPLETION 0x1 #define INT_ERROR 0x2 #define INT_QUEUE_STOPPED 0x4 -#define ALL_INTERRUPTS (INT_COMPLETION| \ - INT_ERROR| \ - INT_QUEUE_STOPPED) +#define INT_EMPTY_QUEUE 0x8 +#define SUPPORTED_INTERRUPTS (INT_COMPLETION | INT_ERROR) #define LSB_REGION_WIDTH 5 #define MAX_LSB_CNT 8 @@ -188,6 +187,7 @@ #define CCP_AES_CTX_SB_COUNT 1 #define CCP_XTS_AES_KEY_SB_COUNT 1 +#define CCP5_XTS_AES_KEY_SB_COUNT 2 #define CCP_XTS_AES_CTX_SB_COUNT 1 #define CCP_SHA_SB_COUNT 1 @@ -333,7 +333,10 @@ struct ccp_device { void *dev_specific; int (*get_irq)(struct ccp_device *ccp); void (*free_irq)(struct ccp_device *ccp); + unsigned int qim; unsigned int irq; + bool use_tasklet; + struct tasklet_struct irq_tasklet; /* I/O area used for device communication. The register mapping * starts at an offset into the mapped bar. @@ -467,9 +470,11 @@ struct ccp_aes_op { enum ccp_aes_type type; enum ccp_aes_mode mode; enum ccp_aes_action action; + unsigned int size; }; struct ccp_xts_aes_op { + enum ccp_aes_type type; enum ccp_aes_action action; enum ccp_xts_aes_unit_size unit_size; }; diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 50fae4442801ca76f0411d7023c915895661fe5a..7d4cd518e6022c255a7e22b21d28771654f126fd 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -692,6 +692,14 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) goto e_ctx; } } + switch (aes->mode) { + case CCP_AES_MODE_CFB: /* CFB128 only */ + case CCP_AES_MODE_CTR: + op.u.aes.size = AES_BLOCK_SIZE * BITS_PER_BYTE - 1; + break; + default: + op.u.aes.size = 0; + } /* Prepare the input and output data workareas. For in-place * operations we need to set the dma direction to BIDIRECTIONAL @@ -779,6 +787,8 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_op op; unsigned int unit_size, dm_offset; bool in_place = false; + unsigned int sb_count; + enum ccp_aes_type aestype; int ret; switch (xts->unit_size) { @@ -802,7 +812,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, return -EINVAL; } - if (xts->key_len != AES_KEYSIZE_128) + if (xts->key_len == AES_KEYSIZE_128) + aestype = CCP_AES_TYPE_128; + else return -EINVAL; if (!xts->final && (xts->src_len & (AES_BLOCK_SIZE - 1))) @@ -824,23 +836,44 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, op.sb_key = cmd_q->sb_key; op.sb_ctx = cmd_q->sb_ctx; op.init = 1; + op.u.xts.type = aestype; op.u.xts.action = xts->action; op.u.xts.unit_size = xts->unit_size; - /* All supported key sizes fit in a single (32-byte) SB entry - * and must be in little endian format. Use the 256-bit byte - * swap passthru option to convert from big endian to little - * endian. + /* A version 3 device only supports 128-bit keys, which fits into a + * single SB entry. A version 5 device uses a 512-bit vector, so two + * SB entries. */ + if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) + sb_count = CCP_XTS_AES_KEY_SB_COUNT; + else + sb_count = CCP5_XTS_AES_KEY_SB_COUNT; ret = ccp_init_dm_workarea(&key, cmd_q, - CCP_XTS_AES_KEY_SB_COUNT * CCP_SB_BYTES, + sb_count * CCP_SB_BYTES, DMA_TO_DEVICE); if (ret) return ret; - dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128; - ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len); - ccp_set_dm_area(&key, 0, xts->key, dm_offset, xts->key_len); + if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) { + /* All supported key sizes must be in little endian format. + * Use the 256-bit byte swap passthru option to convert from + * big endian to little endian. + */ + dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128; + ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len); + ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len); + } else { + /* Version 5 CCPs use a 512-bit space for the key: each portion + * occupies 256 bits, or one entire slot, and is zero-padded. + */ + unsigned int pad; + + dm_offset = CCP_SB_BYTES; + pad = dm_offset - xts->key_len; + ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len); + ccp_set_dm_area(&key, dm_offset + pad, xts->key, xts->key_len, + xts->key_len); + } ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key, CCP_PASSTHRU_BYTESWAP_256BIT); if (ret) { diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c index 28a9996c1085624cc325bbdec39c67d5000eb519..e880d4cf4ada867d96e01ad8784c71fd4b58aac7 100644 --- a/drivers/crypto/ccp/ccp-pci.c +++ b/drivers/crypto/ccp/ccp-pci.c @@ -69,6 +69,7 @@ static int ccp_get_msix_irqs(struct ccp_device *ccp) goto e_irq; } } + ccp->use_tasklet = true; return 0; @@ -100,6 +101,7 @@ static int ccp_get_msi_irq(struct ccp_device *ccp) dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret); goto e_msi; } + ccp->use_tasklet = true; return 0; diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 7868765a70c5f8d780dfea9bb1f6057348be170f..b54af97a20bb3c7e61e9c3d94414ae463a546a71 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -1074,7 +1074,7 @@ static int aead_perform(struct aead_request *req, int encrypt, req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags, &crypt->icv_rev_aes); if (unlikely(!req_ctx->hmac_virt)) - goto free_buf_src; + goto free_buf_dst; if (!encrypt) { scatterwalk_map_and_copy(req_ctx->hmac_virt, req->src, cryptlen, authsize, 0); @@ -1089,10 +1089,10 @@ static int aead_perform(struct aead_request *req, int encrypt, BUG_ON(qmgr_stat_overflow(SEND_QID)); return -EINPROGRESS; -free_buf_src: - free_buf_chain(dev, req_ctx->src, crypt->src_buf); free_buf_dst: free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); +free_buf_src: + free_buf_chain(dev, req_ctx->src, crypt->src_buf); crypt->ctl_flags = CTL_FLAG_UNUSED; return -ENOMEM; } diff --git a/drivers/crypto/marvell/cesa.h b/drivers/crypto/marvell/cesa.h index e423d33decd44a87bfef880aa1deef87f45df622..36291840a12c3e180f0035c45b0e2cbf66d9b4e1 100644 --- a/drivers/crypto/marvell/cesa.h +++ b/drivers/crypto/marvell/cesa.h @@ -273,7 +273,8 @@ struct mv_cesa_op_ctx { #define CESA_TDMA_SRC_IN_SRAM BIT(30) #define CESA_TDMA_END_OF_REQ BIT(29) #define CESA_TDMA_BREAK_CHAIN BIT(28) -#define CESA_TDMA_TYPE_MSK GENMASK(27, 0) +#define CESA_TDMA_SET_STATE BIT(27) +#define CESA_TDMA_TYPE_MSK GENMASK(26, 0) #define CESA_TDMA_DUMMY 0 #define CESA_TDMA_DATA 1 #define CESA_TDMA_OP 2 diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 77712b375b8428a88ad127d689a4e3a99e6b0640..662cf4ddb04b8a71a9e98a06990887cfc44b43e9 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -280,13 +280,32 @@ static void mv_cesa_ahash_std_prepare(struct ahash_request *req) sreq->offset = 0; } +static void mv_cesa_ahash_dma_step(struct ahash_request *req) +{ + struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); + struct mv_cesa_req *base = &creq->base; + + /* We must explicitly set the digest state. */ + if (base->chain.first->flags & CESA_TDMA_SET_STATE) { + struct mv_cesa_engine *engine = base->engine; + int i; + + /* Set the hash state in the IVDIG regs. */ + for (i = 0; i < ARRAY_SIZE(creq->state); i++) + writel_relaxed(creq->state[i], engine->regs + + CESA_IVDIG(i)); + } + + mv_cesa_dma_step(base); +} + static void mv_cesa_ahash_step(struct crypto_async_request *req) { struct ahash_request *ahashreq = ahash_request_cast(req); struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) - mv_cesa_dma_step(&creq->base); + mv_cesa_ahash_dma_step(ahashreq); else mv_cesa_ahash_std_step(ahashreq); } @@ -562,11 +581,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) struct mv_cesa_ahash_dma_iter iter; struct mv_cesa_op_ctx *op = NULL; unsigned int frag_len; + bool set_state = false; int ret; basereq->chain.first = NULL; basereq->chain.last = NULL; + if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl)) + set_state = true; + if (creq->src_nents) { ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE); @@ -650,6 +673,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) basereq->chain.last->flags |= (CESA_TDMA_END_OF_REQ | CESA_TDMA_BREAK_CHAIN); + if (set_state) { + /* + * Put the CESA_TDMA_SET_STATE flag on the first tdma desc to + * let the step logic know that the IVDIG registers should be + * explicitly set before launching a TDMA chain. + */ + basereq->chain.first->flags |= CESA_TDMA_SET_STATE; + } + return 0; err_free_tdma: diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index 9fd7a5fbaa1bd4077ca2ef1a5ecf2c493eb22079..0cda6e3f2b4bda9ee3d81ba3dddcb977f42a09f0 100644 --- a/drivers/crypto/marvell/tdma.c +++ b/drivers/crypto/marvell/tdma.c @@ -112,7 +112,14 @@ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine, last->next = dreq->chain.first; engine->chain.last = dreq->chain.last; - if (!(last->flags & CESA_TDMA_BREAK_CHAIN)) + /* + * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on + * the last element of the current chain, or if the request + * being queued needs the IV regs to be set before lauching + * the request. + */ + if (!(last->flags & CESA_TDMA_BREAK_CHAIN) && + !(dreq->chain.first->flags & CESA_TDMA_SET_STATE)) last->next_dma = dreq->chain.first->cur_dma; } } diff --git a/drivers/crypto/msm/Kconfig b/drivers/crypto/msm/Kconfig index 0f4568b4646884bbeed105b31616598ec3bffd76..3011aa6215ba8f4f029c762b7ebe5439966a04c4 100644 --- a/drivers/crypto/msm/Kconfig +++ b/drivers/crypto/msm/Kconfig @@ -2,7 +2,7 @@ config CRYPTO_DEV_QCOM_ICE tristate "Inline Crypto Module" default n - depends on PFK && BLK_DEV_DM + depends on BLK_DEV_DM help This driver supports Inline Crypto Engine for QTI chipsets, MSM8994 and later, to accelerate crypto operations for storage needs. diff --git a/drivers/crypto/msm/compat_qcedev.c b/drivers/crypto/msm/compat_qcedev.c index 0ca28bed01341e15d77463a7dcf35e65342ebc8b..d61b6f398696c80c418469e29b18c7576d0dc3bf 100644 --- a/drivers/crypto/msm/compat_qcedev.c +++ b/drivers/crypto/msm/compat_qcedev.c @@ -96,7 +96,6 @@ static int compat_get_qcedev_vbuf_info( for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { err |= get_user(vaddr, &vbuf32->src[i].vaddr); - vbuf->src[i].vaddr = NULL; err |= put_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr); err |= get_user(len, &vbuf32->src[i].len); err |= put_user(len, &vbuf->src[i].len); @@ -104,7 +103,6 @@ static int compat_get_qcedev_vbuf_info( for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { err |= get_user(vaddr, &vbuf32->dst[i].vaddr); - vbuf->dst[i].vaddr = NULL; err |= put_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr); err |= get_user(len, &vbuf32->dst[i].len); err |= put_user(len, &vbuf->dst[i].len); @@ -122,7 +120,6 @@ static int compat_put_qcedev_vbuf_info( for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { err |= get_user(vaddr, (compat_uptr_t *)&vbuf->src[i].vaddr); - vbuf32->src[i].vaddr = 0; err |= put_user(vaddr, &vbuf32->src[i].vaddr); err |= get_user(len, &vbuf->src[i].len); err |= put_user(len, &vbuf32->src[i].len); @@ -130,7 +127,6 @@ static int compat_put_qcedev_vbuf_info( for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { err |= get_user(vaddr, (compat_uptr_t *)&vbuf->dst[i].vaddr); - vbuf32->dst[i].vaddr = 0; err |= put_user(vaddr, &vbuf32->dst[i].vaddr); err |= get_user(len, &vbuf->dst[i].len); err |= put_user(len, &vbuf32->dst[i].len); @@ -275,7 +271,6 @@ static int compat_get_qcedev_sha_op_req( for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { err |= get_user(vaddr, &data32->data[i].vaddr); - data->data[i].vaddr = 0; err |= put_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr); err |= get_user(len, &data32->data[i].len); err |= put_user(len, &data->data[i].len); @@ -294,7 +289,6 @@ static int compat_get_qcedev_sha_op_req( err |= get_user(diglen, &data32->diglen); err |= put_user(diglen, &data->diglen); err |= get_user(authkey, &data32->authkey); - data->authkey = NULL; err |= put_user(authkey, (compat_uptr_t *)&data->authkey); err |= get_user(authklen, &data32->authklen); err |= put_user(authklen, &data->authklen); @@ -321,7 +315,6 @@ static int compat_put_qcedev_sha_op_req( for (i = 0; i < QCEDEV_MAX_BUFFERS; i++) { err |= get_user(vaddr, (compat_uptr_t *)&data->data[i].vaddr); - data32->data[i].vaddr = 0; err |= put_user(vaddr, &data32->data[i].vaddr); err |= get_user(len, &data->data[i].len); err |= put_user(len, &data32->data[i].len); @@ -340,7 +333,6 @@ static int compat_put_qcedev_sha_op_req( err |= get_user(diglen, &data->diglen); err |= put_user(diglen, &data32->diglen); err |= get_user(authkey, (compat_uptr_t *)&data->authkey); - data32->authkey = 0; err |= put_user(authkey, &data32->authkey); err |= get_user(authklen, &data->authklen); err |= put_user(authklen, &data32->authklen); diff --git a/drivers/crypto/msm/compat_qcedev.h b/drivers/crypto/msm/compat_qcedev.h index 4cc3933f1280ada945a788d4ff7bad44b26e9f4d..6c041cba6e4c89584f74a0ef832e02076a8b3082 100644 --- a/drivers/crypto/msm/compat_qcedev.h +++ b/drivers/crypto/msm/compat_qcedev.h @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2014, 2017 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 _UAPI_COMPAT_QCEDEV__H #define _UAPI_COMPAT_QCEDEV__H diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index ba6825e9e03a41c01923c474bf5744394d8bd246..182097ccd0bb81352f63e3783694b186422fea61 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -21,11 +21,12 @@ #include #include #include -#include #include #include #include #include "iceregs.h" +#include + #define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \ ((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff))) @@ -125,6 +126,9 @@ static int qti_ice_setting_config(struct request *req, return -EPERM; } + if (!setting) + return -EINVAL; + if ((short)(crypto_data->key_index) >= 0) { memcpy(&setting->crypto_data, crypto_data, @@ -440,7 +444,7 @@ static int qcom_ice_enable(struct ice_device *ice_dev) (ICE_REV(ice_dev->ice_hw_version, MINOR) >= 1))) { reg = qcom_ice_readl(ice_dev, QCOM_ICE_REGS_BYPASS_STATUS); if ((reg & 0x80000000) != 0x0) { - pr_err("%s: Bypass failed for ice = %p", + pr_err("%s: Bypass failed for ice = %pK", __func__, (void *)ice_dev); WARN_ON(1); } @@ -466,7 +470,7 @@ static int qcom_ice_verify_ice(struct ice_device *ice_dev) } ice_dev->ice_hw_version = rev; - dev_info(ice_dev->pdev, "QC ICE %d.%d.%d device found @0x%p\n", + dev_info(ice_dev->pdev, "QC ICE %d.%d.%d device found @0x%pK\n", maj_rev, min_rev, step_rev, ice_dev->mmio); @@ -869,7 +873,7 @@ static int qcom_ice_restore_key_config(struct ice_device *ice_dev) static int qcom_ice_init_clocks(struct ice_device *ice) { int ret = -EINVAL; - struct ice_clk_info *clki; + struct ice_clk_info *clki = NULL; struct device *dev = ice->pdev; struct list_head *head = &ice->clk_list_head; @@ -913,7 +917,7 @@ static int qcom_ice_init_clocks(struct ice_device *ice) static int qcom_ice_enable_clocks(struct ice_device *ice, bool enable) { int ret = 0; - struct ice_clk_info *clki; + struct ice_clk_info *clki = NULL; struct device *dev = ice->pdev; struct list_head *head = &ice->clk_list_head; @@ -1256,7 +1260,7 @@ static void qcom_ice_debug(struct platform_device *pdev) goto out; } - pr_err("%s: =========== REGISTER DUMP (%p)===========\n", + pr_err("%s: =========== REGISTER DUMP (%pK)===========\n", ice_dev->ice_instance_type, ice_dev); pr_err("%s: ICE Control: 0x%08x | ICE Reset: 0x%08x\n", @@ -1432,7 +1436,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, int ret = 0; bool is_pfe = false; - if (!pdev || !req || !setting) { + if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); return -EINVAL; } @@ -1451,6 +1455,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, /* It is not an error to have a request with no bio */ return 0; } + //pr_err("%s bio is %pK\n", __func__, req->bio); ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, async); if (is_pfe) { @@ -1570,7 +1575,7 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node) struct ice_device *ice_dev = NULL; if (!node) { - pr_err("%s: invalid node %p", __func__, node); + pr_err("%s: invalid node %pK", __func__, node); goto out; } @@ -1587,13 +1592,16 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node) list_for_each_entry(ice_dev, &ice_devices, list) { if (ice_dev->pdev->of_node == node) { - pr_info("%s: found ice device %p\n", __func__, ice_dev); + pr_info("%s: found ice device %pK\n", __func__, + ice_dev); + ice_pdev = to_platform_device(ice_dev->pdev); break; } } - ice_pdev = to_platform_device(ice_dev->pdev); - pr_info("%s: matching platform device %p\n", __func__, ice_pdev); + if (ice_pdev) + pr_info("%s: matching platform device %pK\n", __func__, + ice_pdev); out: return ice_pdev; } @@ -1611,12 +1619,12 @@ static struct ice_device *get_ice_device_from_storage_type list_for_each_entry(ice_dev, &ice_devices, list) { if (!strcmp(ice_dev->ice_instance_type, storage_type)) { - pr_info("%s: found ice device %p\n", __func__, ice_dev); - break; + pr_debug("%s: ice device %pK\n", __func__, ice_dev); + return ice_dev; } } out: - return ice_dev; + return NULL; } static int enable_ice_setup(struct ice_device *ice_dev) @@ -1631,7 +1639,7 @@ static int enable_ice_setup(struct ice_device *ice_dev) } ret = regulator_enable(ice_dev->reg); if (ret) { - pr_err("%s:%p: Could not enable regulator\n", + pr_err("%s:%pK: Could not enable regulator\n", __func__, ice_dev); goto out; } @@ -1639,7 +1647,7 @@ static int enable_ice_setup(struct ice_device *ice_dev) /* Setup Clocks */ if (qcom_ice_enable_clocks(ice_dev, true)) { - pr_err("%s:%p:%s Could not enable clocks\n", __func__, + pr_err("%s:%pK:%s Could not enable clocks\n", __func__, ice_dev, ice_dev->ice_instance_type); goto out_reg; } @@ -1651,7 +1659,7 @@ static int enable_ice_setup(struct ice_device *ice_dev) ret = qcom_ice_set_bus_vote(ice_dev, vote); if (ret) { - pr_err("%s:%p: failed %d\n", __func__, ice_dev, ret); + pr_err("%s:%pK: failed %d\n", __func__, ice_dev, ret); goto out_clocks; } @@ -1683,19 +1691,19 @@ static int disable_ice_setup(struct ice_device *ice_dev) /* Setup Bus Vote */ vote = qcom_ice_get_bus_vote(ice_dev, "MIN"); if (vote < 0) { - pr_err("%s:%p: Unable to get bus vote\n", __func__, ice_dev); + pr_err("%s:%pK: Unable to get bus vote\n", __func__, ice_dev); goto out_disable_clocks; } ret = qcom_ice_set_bus_vote(ice_dev, vote); if (ret) - pr_err("%s:%p: failed %d\n", __func__, ice_dev, ret); + pr_err("%s:%pK: failed %d\n", __func__, ice_dev, ret); out_disable_clocks: /* Setup Clocks */ if (qcom_ice_enable_clocks(ice_dev, false)) - pr_err("%s:%p:%s Could not disable clocks\n", __func__, + pr_err("%s:%pK:%s Could not disable clocks\n", __func__, ice_dev, ice_dev->ice_instance_type); /* Setup Regulator */ @@ -1706,7 +1714,7 @@ static int disable_ice_setup(struct ice_device *ice_dev) } ret = regulator_disable(ice_dev->reg); if (ret) { - pr_err("%s:%p: Could not disable regulator\n", + pr_err("%s:%pK: Could not disable regulator\n", __func__, ice_dev); goto out; } diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c index 3a2a51d6a3e3ea7549fce3994a37c5a1a390f16c..d4778156cb421b39c2b2f830e00d8589d92e99c9 100644 --- a/drivers/crypto/msm/ota_crypto.c +++ b/drivers/crypto/msm/ota_crypto.c @@ -172,7 +172,7 @@ static int qcota_release(struct inode *inode, struct file *file) podev = file->private_data; if (podev != NULL && podev->magic != OTA_MAGIC) { - pr_err("%s: invalid handle %p\n", + pr_err("%s: invalid handle %pK\n", __func__, podev); } @@ -440,7 +440,7 @@ static long qcota_ioctl(struct file *file, podev = file->private_data; if (podev == NULL || podev->magic != OTA_MAGIC) { - pr_err("%s: invalid handle %p\n", + pr_err("%s: invalid handle %pK\n", __func__, podev); return -ENOENT; } diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h index 7b4ca249478ca342a018817d84ce9d007819d430..c3b96f021bebc0927b46068a65c5c29c72d502df 100644 --- a/drivers/crypto/msm/qce.h +++ b/drivers/crypto/msm/qce.h @@ -56,6 +56,12 @@ /* Maximum Nonce bytes */ #define MAX_NONCE 16 +/* Crypto clock control flags */ +#define QCE_CLK_ENABLE_FIRST 1 +#define QCE_BW_REQUEST_FIRST 2 +#define QCE_CLK_DISABLE_FIRST 3 +#define QCE_BW_REQUEST_RESET_FIRST 4 + typedef void (*qce_comp_func_ptr_t)(void *areq, unsigned char *icv, unsigned char *iv, int ret); @@ -124,6 +130,7 @@ struct ce_hw_support { bool use_sw_hmac_algo; bool use_sw_aes_ccm_algo; bool clk_mgmt_sus_res; + bool req_bw_before_clk; unsigned int ce_device; unsigned int ce_hw_instance; unsigned int max_request; diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 0cf4386437805bdacf18e17db21dfe36c68eb9b2..4426bc719cfa606fd024fb8f012051d9dfd33027 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -33,12 +33,17 @@ #include #include #include +#include +#include #include "qce.h" #include "qce50.h" #include "qcryptohw_50.h" #include "qce_ota.h" +#define CRYPTO_SMMU_IOVA_START 0x10000000 +#define CRYPTO_SMMU_IOVA_SIZE 0x40000000 + #define CRYPTO_CONFIG_RESET 0xE01EF #define MAX_SPS_DESC_FIFO_SIZE 0xfff0 #define QCE_MAX_NUM_DSCR 0x200 @@ -121,6 +126,7 @@ struct qce_device { bool support_hw_key; bool support_clk_mgmt_sus_res; bool support_only_core_src_clk; + bool request_bw_before_clk; void __iomem *iobase; /* Virtual io base of CE HW */ unsigned int phy_iobase; /* Physical io base of CE HW */ @@ -155,6 +161,8 @@ struct qce_device { atomic_t last_intr_seq; bool cadence_flag; uint8_t *dummyreq_in_buf; + struct dma_iommu_mapping *smmu_mapping; + bool enable_s1_smmu; }; static void print_notify_debug(struct sps_event_notify *notify); @@ -298,7 +306,7 @@ static int _probe_ce_engine(struct qce_device *pce_dev) pce_dev->ce_bam_info.ce_burst_size = MAX_CE_BAM_BURST_SIZE; - dev_info(pce_dev->pdev, "CE device = 0x%x\n, IO base, CE = 0x%p\n, Consumer (IN) PIPE %d, Producer (OUT) PIPE %d\n IO base BAM = 0x%p\n BAM IRQ %d\n Engines Availability = 0x%x\n", + dev_info(pce_dev->pdev, "CE device = %#x IO base, CE = %pK Consumer (IN) PIPE %d,\nProducer (OUT) PIPE %d IO base BAM = %pK\nBAM IRQ %d Engines Availability = %#x\n", pce_dev->ce_bam_info.ce_device, pce_dev->iobase, pce_dev->ce_bam_info.dest_pipe_index, pce_dev->ce_bam_info.src_pipe_index, @@ -1156,7 +1164,7 @@ static void _qce_dump_descr_fifos_dbg(struct qce_device *pce_dev, int req_info) #define QCE_WRITE_REG(val, addr) \ { \ - pr_info(" [0x%p] 0x%x\n", addr, (uint32_t)val); \ + pr_info(" [0x%pK] 0x%x\n", addr, (uint32_t)val); \ writel_relaxed(val, addr); \ } @@ -2152,6 +2160,10 @@ static int _sha_complete(struct qce_device *pce_dev, int req_info) pce_sps_data = &preq_info->ce_sps; qce_callback = preq_info->qce_cb; areq = (struct ahash_request *) preq_info->areq; + if (!areq) { + pr_err("sha operation error. areq is NULL\n"); + return -ENXIO; + } qce_dma_unmap_sg(pce_dev->pdev, areq->src, preq_info->src_nents, DMA_TO_DEVICE); memcpy(digest, (char *)(&pce_sps_data->result->auth_iv[0]), @@ -2727,7 +2739,7 @@ static int qce_sps_init_ep_conn(struct qce_device *pce_dev, sps_event->callback = NULL; } - pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%p\n", + pr_debug("success, %s : pipe_handle=0x%lx, desc fifo base (phy) = 0x%pK\n", is_producer ? "PRODUCER(RX/OUT)" : "CONSUMER(TX/IN)", (uintptr_t)sps_pipe_info, &sps_connect_info->desc.phys_base); goto out; @@ -2889,7 +2901,7 @@ static int qce_sps_get_bam(struct qce_device *pce_dev) bam.ipc_loglevel = QCE_BAM_DEFAULT_IPC_LOGLVL; bam.options |= SPS_BAM_CACHED_WP; pr_debug("bam physical base=0x%lx\n", (uintptr_t)bam.phys_addr); - pr_debug("bam virtual base=0x%p\n", bam.virt_addr); + pr_debug("bam virtual base=0x%pK\n", bam.virt_addr); /* Register CE Peripheral BAM device to SPS driver */ rc = sps_register_bam_device(&bam, &pbam->handle); @@ -2964,7 +2976,7 @@ static inline int qce_alloc_req_info(struct qce_device *pce_dev) request_index++; if (request_index >= MAX_QCE_BAM_REQ) request_index = 0; - if (xchg(&pce_dev->ce_request_info[request_index]. + if (atomic_xchg(&pce_dev->ce_request_info[request_index]. in_use, true) == false) { pce_dev->ce_request_index = request_index; return request_index; @@ -2980,7 +2992,8 @@ static inline void qce_free_req_info(struct qce_device *pce_dev, int req_info, bool is_complete) { pce_dev->ce_request_info[req_info].xfer_type = QCE_XFER_TYPE_LAST; - if (xchg(&pce_dev->ce_request_info[req_info].in_use, false) == true) { + if (atomic_xchg(&pce_dev->ce_request_info[req_info].in_use, + false) == true) { if (req_info < MAX_QCE_BAM_REQ && is_complete) atomic_dec(&pce_dev->no_of_queued_req); } else @@ -2992,7 +3005,7 @@ static void print_notify_debug(struct sps_event_notify *notify) phys_addr_t addr = DESC_FULL_ADDR((phys_addr_t) notify->data.transfer.iovec.flags, notify->data.transfer.iovec.addr); - pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%p\n", + pr_debug("sps ev_id=%d, addr=0x%pa, size=0x%x, flags=0x%x user=0x%pK\n", notify->event_id, &addr, notify->data.transfer.iovec.size, notify->data.transfer.iovec.flags, @@ -4604,7 +4617,7 @@ static int qce_dummy_req(struct qce_device *pce_dev) { int ret = 0; - if (!(xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX]. + if (!(atomic_xchg(&pce_dev->ce_request_info[DUMMY_REQ_INDEX]. in_use, true) == false)) return -EBUSY; ret = qce_process_sha_req(pce_dev, NULL); @@ -4876,15 +4889,12 @@ static int _qce_suspend(void *handle) if (handle == NULL) return -ENODEV; - qce_enable_clk(pce_dev); - sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe; sps_disconnect(sps_pipe_info); sps_pipe_info = pce_dev->ce_bam_info.producer.pipe; sps_disconnect(sps_pipe_info); - qce_disable_clk(pce_dev); return 0; } @@ -4898,8 +4908,6 @@ static int _qce_resume(void *handle) if (handle == NULL) return -ENODEV; - qce_enable_clk(pce_dev); - sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe; sps_connect_info = &pce_dev->ce_bam_info.consumer.connect; memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size); @@ -4922,7 +4930,6 @@ static int _qce_resume(void *handle) if (rc) pr_err("Producer callback registration failed rc = %d\n", rc); - qce_disable_clk(pce_dev); return rc; } @@ -5675,6 +5682,8 @@ static int __qce_get_device_tree_data(struct platform_device *pdev, (&pdev->dev)->of_node, "qcom,clk-mgmt-sus-res"); pce_dev->support_only_core_src_clk = of_property_read_bool( (&pdev->dev)->of_node, "qcom,support-core-clk-only"); + pce_dev->request_bw_before_clk = of_property_read_bool( + (&pdev->dev)->of_node, "qcom,request-bw-before-clk"); if (of_property_read_u32((&pdev->dev)->of_node, "qcom,bam-pipe-pair", @@ -5706,6 +5715,10 @@ static int __qce_get_device_tree_data(struct platform_device *pdev, pr_info("CE operating frequency is not defined, setting to default 100MHZ\n"); pce_dev->ce_opp_freq_hz = CE_CLK_100MHZ; } + + if (of_property_read_bool((&pdev->dev)->of_node, "qcom,smmu-s1-enable")) + pce_dev->enable_s1_smmu = true; + pce_dev->ce_bam_info.dest_pipe_index = 2 * pce_dev->ce_bam_info.pipe_pair_index; pce_dev->ce_bam_info.src_pipe_index = @@ -5762,6 +5775,9 @@ static int __qce_init_clk(struct qce_device *pce_dev) pce_dev->ce_core_src_clk = clk_get(pce_dev->pdev, "core_clk_src"); if (!IS_ERR(pce_dev->ce_core_src_clk)) { + if (pce_dev->request_bw_before_clk) + goto skip_set_rate; + rc = clk_set_rate(pce_dev->ce_core_src_clk, pce_dev->ce_opp_freq_hz); if (rc) { @@ -5780,6 +5796,7 @@ static int __qce_init_clk(struct qce_device *pce_dev) pce_dev->ce_core_src_clk = NULL; } +skip_set_rate: if (pce_dev->support_only_core_src_clk) { pce_dev->ce_core_clk = NULL; pce_dev->ce_clk = NULL; @@ -5935,6 +5952,55 @@ static int setup_dummy_req(struct qce_device *pce_dev) return 0; } +static void qce_iommu_release_iomapping(struct qce_device *pce_dev) +{ + if (pce_dev->smmu_mapping) + arm_iommu_release_mapping(pce_dev->smmu_mapping); + + pce_dev->smmu_mapping = NULL; +} + +static int qce_smmu_init(struct qce_device *pce_dev) +{ + struct dma_iommu_mapping *mapping; + int attr = 1; + int ret = 0; + + mapping = arm_iommu_create_mapping(&platform_bus_type, + CRYPTO_SMMU_IOVA_START, CRYPTO_SMMU_IOVA_SIZE); + if (IS_ERR(mapping)) { + ret = PTR_ERR(mapping); + pr_err("Create mapping failed, err = %d\n", ret); + return ret; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_ATOMIC, &attr); + if (ret < 0) { + pr_err("Set ATOMIC attr failed, err = %d\n", ret); + goto ext_fail_set_attr; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR, &attr); + if (ret < 0) { + pr_err("Set UPSTREAM_IOVA_ALLOCATOR failed, err = %d\n", ret); + goto ext_fail_set_attr; + } + + ret = arm_iommu_attach_device(pce_dev->pdev, mapping); + if (ret < 0) { + pr_err("Attach device failed, err = %d\n", ret); + goto ext_fail_set_attr; + } + pce_dev->smmu_mapping = mapping; + return ret; + +ext_fail_set_attr: + qce_iommu_release_iomapping(pce_dev); + return ret; +} + /* crypto engine open function. */ void *qce_open(struct platform_device *pdev, int *rc) { @@ -5961,8 +6027,15 @@ void *qce_open(struct platform_device *pdev, int *rc) goto err_pce_dev; } + if (pce_dev->enable_s1_smmu) { + if (qce_smmu_init(pce_dev)) { + *rc = -EIO; + goto err_pce_dev; + } + } + for (i = 0; i < MAX_QCE_ALLOC_BAM_REQ; i++) - pce_dev->ce_request_info[i].in_use = false; + atomic_set(&pce_dev->ce_request_info[i].in_use, false); pce_dev->ce_request_index = 0; pce_dev->memsize = 10 * PAGE_SIZE * MAX_QCE_ALLOC_BAM_REQ; @@ -6030,6 +6103,9 @@ void *qce_open(struct platform_device *pdev, int *rc) dma_free_coherent(pce_dev->pdev, pce_dev->memsize, pce_dev->coh_vmem, pce_dev->coh_pmem); err_iobase: + if (pce_dev->enable_s1_smmu) + qce_iommu_release_iomapping(pce_dev); + if (pce_dev->iobase) iounmap(pce_dev->iobase); err_pce_dev: @@ -6059,6 +6135,9 @@ int qce_close(void *handle) kfree(pce_dev->dummyreq_in_buf); kfree(pce_dev->iovec_vmem); + if (pce_dev->enable_s1_smmu) + qce_iommu_release_iomapping(pce_dev); + qce_disable_clk(pce_dev); __qce_deinit_clk(pce_dev); mutex_unlock(&qce_iomap_mutex); @@ -6096,6 +6175,7 @@ int qce_hw_support(void *handle, struct ce_hw_support *ce_support) ce_support->hw_key = pce_dev->support_hw_key; ce_support->aes_ccm = true; ce_support->clk_mgmt_sus_res = pce_dev->support_clk_mgmt_sus_res; + ce_support->req_bw_before_clk = pce_dev->request_bw_before_clk; if (pce_dev->ce_bam_info.minor_version) ce_support->aligned_only = false; else @@ -6126,12 +6206,13 @@ EXPORT_SYMBOL(qce_hw_support); void qce_dump_req(void *handle) { int i; + bool req_in_use; struct qce_device *pce_dev = (struct qce_device *)handle; for (i = 0; i < MAX_QCE_BAM_REQ; i++) { - pr_info("qce_dump_req %d %d\n", i, - pce_dev->ce_request_info[i].in_use); - if (pce_dev->ce_request_info[i].in_use == true) + req_in_use = atomic_read(&pce_dev->ce_request_info[i].in_use); + pr_info("qce_dump_req %d %d\n", i, req_in_use); + if (req_in_use == true) _qce_dump_descr_fifos(pce_dev, i); } } diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h index 0e60bd290788386fad0c78ee60d0de6cd36564df..ab0d21da72c5c8fa15f2e60ce3abcc29198fd059 100644 --- a/drivers/crypto/msm/qce50.h +++ b/drivers/crypto/msm/qce50.h @@ -214,7 +214,7 @@ struct ce_sps_data { }; struct ce_request_info { - bool in_use; + atomic_t in_use; bool in_prog; enum qce_xfer_type_enum xfer_type; struct ce_sps_data ce_sps; diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 0860e59541f5a5bf1213c8c08a888fd549772c66..958fb9160c2df2ff2444cbdc2067f307f4a8efed 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -57,6 +57,98 @@ static uint8_t _std_init_vector_sha256_uint8[] = { static DEFINE_MUTEX(send_cmd_lock); static DEFINE_MUTEX(qcedev_sent_bw_req); +static DEFINE_MUTEX(hash_access_lock); + +static int qcedev_control_clocks(struct qcedev_control *podev, bool enable) +{ + unsigned int control_flag; + int ret = 0; + + if (podev->ce_support.req_bw_before_clk) { + if (enable) + control_flag = QCE_BW_REQUEST_FIRST; + else + control_flag = QCE_CLK_DISABLE_FIRST; + } else { + if (enable) + control_flag = QCE_CLK_ENABLE_FIRST; + else + control_flag = QCE_BW_REQUEST_RESET_FIRST; + } + + switch (control_flag) { + case QCE_CLK_ENABLE_FIRST: + ret = qce_enable_clk(podev->qce); + if (ret) { + pr_err("%s Unable enable clk\n", __func__); + return ret; + } + ret = msm_bus_scale_client_update_request( + podev->bus_scale_handle, 1); + if (ret) { + pr_err("%s Unable to set high bw\n", __func__); + ret = qce_disable_clk(podev->qce); + if (ret) + pr_err("%s Unable disable clk\n", __func__); + return ret; + } + break; + case QCE_BW_REQUEST_FIRST: + ret = msm_bus_scale_client_update_request( + podev->bus_scale_handle, 1); + if (ret) { + pr_err("%s Unable to set high bw\n", __func__); + return ret; + } + ret = qce_enable_clk(podev->qce); + if (ret) { + pr_err("%s Unable enable clk\n", __func__); + ret = msm_bus_scale_client_update_request( + podev->bus_scale_handle, 0); + if (ret) + pr_err("%s Unable to set low bw\n", __func__); + return ret; + } + break; + case QCE_CLK_DISABLE_FIRST: + ret = qce_disable_clk(podev->qce); + if (ret) { + pr_err("%s Unable to disable clk\n", __func__); + return ret; + } + ret = msm_bus_scale_client_update_request( + podev->bus_scale_handle, 0); + if (ret) { + pr_err("%s Unable to set low bw\n", __func__); + ret = qce_enable_clk(podev->qce); + if (ret) + pr_err("%s Unable enable clk\n", __func__); + return ret; + } + break; + case QCE_BW_REQUEST_RESET_FIRST: + ret = msm_bus_scale_client_update_request( + podev->bus_scale_handle, 0); + if (ret) { + pr_err("%s Unable to set low bw\n", __func__); + return ret; + } + ret = qce_disable_clk(podev->qce); + if (ret) { + pr_err("%s Unable to disable clk\n", __func__); + ret = msm_bus_scale_client_update_request( + podev->bus_scale_handle, 1); + if (ret) + pr_err("%s Unable to set high bw\n", __func__); + return ret; + } + break; + default: + return -ENOENT; + } + + return 0; +} static void qcedev_ce_high_bw_req(struct qcedev_control *podev, bool high_bw_req) @@ -66,47 +158,21 @@ static void qcedev_ce_high_bw_req(struct qcedev_control *podev, mutex_lock(&qcedev_sent_bw_req); if (high_bw_req) { if (podev->high_bw_req_count == 0) { - ret = qce_enable_clk(podev->qce); - if (ret) { - pr_err("%s Unable enable clk\n", __func__); - mutex_unlock(&qcedev_sent_bw_req); - return; - } - ret = msm_bus_scale_client_update_request( - podev->bus_scale_handle, 1); - if (ret) { - pr_err("%s Unable to set to high bandwidth\n", - __func__); - ret = qce_disable_clk(podev->qce); - mutex_unlock(&qcedev_sent_bw_req); - return; - } + ret = qcedev_control_clocks(podev, true); + if (ret) + goto exit_unlock_mutex; } podev->high_bw_req_count++; } else { if (podev->high_bw_req_count == 1) { - ret = msm_bus_scale_client_update_request( - podev->bus_scale_handle, 0); - if (ret) { - pr_err("%s Unable to set to low bandwidth\n", - __func__); - mutex_unlock(&qcedev_sent_bw_req); - return; - } - ret = qce_disable_clk(podev->qce); - if (ret) { - pr_err("%s Unable disable clk\n", __func__); - ret = msm_bus_scale_client_update_request( - podev->bus_scale_handle, 1); - if (ret) - pr_err("%s Unable to set to high bandwidth\n", - __func__); - mutex_unlock(&qcedev_sent_bw_req); - return; - } + ret = qcedev_control_clocks(podev, false); + if (ret) + goto exit_unlock_mutex; } podev->high_bw_req_count--; } + +exit_unlock_mutex: mutex_unlock(&qcedev_sent_bw_req); } @@ -204,7 +270,7 @@ static int qcedev_release(struct inode *inode, struct file *file) handle = file->private_data; podev = handle->cntl; if (podev != NULL && podev->magic != QCEDEV_MAGIC) { - pr_err("%s: invalid handle %p\n", + pr_err("%s: invalid handle %pK\n", __func__, podev); } kzfree(handle); @@ -274,8 +340,6 @@ void qcedev_sha_req_cb(void *cookie, unsigned char *digest, if (authdata) { handle->sha_ctxt.auth_data[0] = auth32[0]; handle->sha_ctxt.auth_data[1] = auth32[1]; - handle->sha_ctxt.auth_data[2] = auth32[2]; - handle->sha_ctxt.auth_data[3] = auth32[3]; } tasklet_schedule(&pdev->done_tasklet); @@ -839,6 +903,7 @@ static int qcedev_sha_final(struct qcedev_async_req *qcedev_areq, memset(&handle->sha_ctxt.trailing_buf[0], 0, 64); kzfree(k_buf_src); + qcedev_areq->sha_req.sreq.src = NULL; return err; } @@ -1002,6 +1067,7 @@ static int qcedev_hmac_get_ohash(struct qcedev_async_req *qcedev_areq, handle->sha_ctxt.first_blk = 0; kzfree(k_src); + qcedev_areq->sha_req.sreq.src = NULL; return err; } @@ -1156,8 +1222,10 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), - creq->vbuf.dst[dst_i].len)) - return -EFAULT; + creq->vbuf.dst[dst_i].len)) { + err = -EFAULT; + goto exit; + } k_align_dst += creq->vbuf.dst[dst_i].len + byteoffset; @@ -1167,8 +1235,10 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, if (err == 0 && copy_to_user( (void __user *)creq->vbuf.dst[dst_i].vaddr, (k_align_dst + byteoffset), - creq->data_len)) - return -EFAULT; + creq->data_len)) { + err = -EFAULT; + goto exit; + } k_align_dst += creq->data_len; creq->vbuf.dst[dst_i].len -= creq->data_len; @@ -1177,7 +1247,9 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq, } } *di = dst_i; - +exit: + areq->cipher_req.creq.src = NULL; + areq->cipher_req.creq.dst = NULL; return err; }; @@ -1592,7 +1664,7 @@ static inline long qcedev_ioctl(struct file *file, podev = handle->cntl; qcedev_areq.handle = handle; if (podev == NULL || podev->magic != QCEDEV_MAGIC) { - pr_err("%s: invalid handle %p\n", + pr_err("%s: invalid handle %pK\n", __func__, podev); return -ENOENT; } @@ -1634,12 +1706,18 @@ static inline long qcedev_ioctl(struct file *file, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; err = qcedev_hash_init(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1657,32 +1735,42 @@ static inline long qcedev_ioctl(struct file *file, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; if (qcedev_areq.sha_op_req.alg == QCEDEV_ALG_AES_CMAC) { err = qcedev_hash_cmac(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } } else { if (handle->sha_ctxt.init_done == false) { pr_err("%s Init was not called\n", __func__); + mutex_unlock(&hash_access_lock); return -EINVAL; } err = qcedev_hash_update(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } } if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { pr_err("Invalid sha_ctxt.diglen %d\n", handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); return -EINVAL; } memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1699,16 +1787,28 @@ static inline long qcedev_ioctl(struct file *file, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; err = qcedev_hash_final(&qcedev_areq, handle); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); + return -EINVAL; + } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1723,20 +1823,34 @@ static inline long qcedev_ioctl(struct file *file, (void __user *)arg, sizeof(struct qcedev_sha_op_req))) return -EFAULT; - if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) + mutex_lock(&hash_access_lock); + if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) { + mutex_unlock(&hash_access_lock); return -EINVAL; + } qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA; qcedev_hash_init(&qcedev_areq, handle, &sg_src); err = qcedev_hash_update(&qcedev_areq, handle, &sg_src); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } err = qcedev_hash_final(&qcedev_areq, handle); - if (err) + if (err) { + mutex_unlock(&hash_access_lock); return err; + } + if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) { + pr_err("Invalid sha_ctxt.diglen %d\n", + handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); + return -EINVAL; + } qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen; memcpy(&qcedev_areq.sha_op_req.digest[0], &handle->sha_ctxt.digest[0], handle->sha_ctxt.diglen); + mutex_unlock(&hash_access_lock); if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req, sizeof(struct qcedev_sha_op_req))) return -EFAULT; @@ -1767,32 +1881,47 @@ static int qcedev_probe(struct platform_device *pdev) tasklet_init(&podev->done_tasklet, req_done, (unsigned long)podev); - /* open qce */ + podev->platform_support.bus_scale_table = (struct msm_bus_scale_pdata *) + msm_bus_cl_get_pdata(pdev); + if (!podev->platform_support.bus_scale_table) { + pr_err("bus_scale_table is NULL\n"); + return -ENODATA; + } + podev->bus_scale_handle = msm_bus_scale_register_client( + (struct msm_bus_scale_pdata *) + podev->platform_support.bus_scale_table); + if (!podev->bus_scale_handle) { + pr_err("%s not able to get bus scale\n", __func__); + return -ENOMEM; + } + + rc = msm_bus_scale_client_update_request(podev->bus_scale_handle, 1); + if (rc) { + pr_err("%s Unable to set to high bandwidth\n", __func__); + goto exit_unregister_bus_scale; + } handle = qce_open(pdev, &rc); if (handle == NULL) { - platform_set_drvdata(pdev, NULL); - return rc; + rc = -ENODEV; + goto exit_scale_busbandwidth; + } + rc = msm_bus_scale_client_update_request(podev->bus_scale_handle, 0); + if (rc) { + pr_err("%s Unable to set to low bandwidth\n", __func__); + goto exit_qce_close; } podev->qce = handle; podev->pdev = pdev; platform_set_drvdata(pdev, podev); - rc = misc_register(&podev->miscdevice); qce_hw_support(podev->qce, &podev->ce_support); if (podev->ce_support.bam) { podev->platform_support.ce_shared = 0; podev->platform_support.shared_ce_resource = 0; podev->platform_support.hw_key_support = podev->ce_support.hw_key; - podev->platform_support.bus_scale_table = NULL; podev->platform_support.sha_hmac = 1; - - podev->platform_support.bus_scale_table = - (struct msm_bus_scale_pdata *) - msm_bus_cl_get_pdata(pdev); - if (!podev->platform_support.bus_scale_table) - pr_err("bus_scale_table is NULL\n"); } else { platform_support = (struct msm_ce_hw_support *)pdev->dev.platform_data; @@ -1801,35 +1930,27 @@ static int qcedev_probe(struct platform_device *pdev) platform_support->shared_ce_resource; podev->platform_support.hw_key_support = platform_support->hw_key_support; - podev->platform_support.bus_scale_table = - platform_support->bus_scale_table; podev->platform_support.sha_hmac = platform_support->sha_hmac; } - if (podev->platform_support.bus_scale_table != NULL) { - podev->bus_scale_handle = - msm_bus_scale_register_client( - (struct msm_bus_scale_pdata *) - podev->platform_support.bus_scale_table); - if (!podev->bus_scale_handle) { - pr_err("%s not able to get bus scale\n", - __func__); - rc = -ENOMEM; - goto err; - } - } + rc = misc_register(&podev->miscdevice); if (rc >= 0) return 0; - if (podev->platform_support.bus_scale_table != NULL) - msm_bus_scale_unregister_client(podev->bus_scale_handle); -err: + misc_deregister(&podev->miscdevice); +exit_qce_close: if (handle) qce_close(handle); +exit_scale_busbandwidth: + msm_bus_scale_client_update_request(podev->bus_scale_handle, 0); +exit_unregister_bus_scale: + if (podev->platform_support.bus_scale_table != NULL) + msm_bus_scale_unregister_client(podev->bus_scale_handle); platform_set_drvdata(pdev, NULL); - podev->qce = NULL; podev->pdev = NULL; + podev->qce = NULL; + return rc; }; @@ -1864,23 +1985,9 @@ static int qcedev_suspend(struct platform_device *pdev, pm_message_t state) mutex_lock(&qcedev_sent_bw_req); if (podev->high_bw_req_count) { - ret = msm_bus_scale_client_update_request( - podev->bus_scale_handle, 0); - if (ret) { - pr_err("%s Unable to set to low bandwidth\n", - __func__); - goto suspend_exit; - } - ret = qce_disable_clk(podev->qce); - if (ret) { - pr_err("%s Unable disable clk\n", __func__); - ret = msm_bus_scale_client_update_request( - podev->bus_scale_handle, 1); - if (ret) - pr_err("%s Unable to set to high bandwidth\n", - __func__); + ret = qcedev_control_clocks(podev, false); + if (ret) goto suspend_exit; - } } suspend_exit: @@ -1900,22 +2007,9 @@ static int qcedev_resume(struct platform_device *pdev) mutex_lock(&qcedev_sent_bw_req); if (podev->high_bw_req_count) { - ret = qce_enable_clk(podev->qce); - if (ret) { - pr_err("%s Unable enable clk\n", __func__); + ret = qcedev_control_clocks(podev, true); + if (ret) goto resume_exit; - } - ret = msm_bus_scale_client_update_request( - podev->bus_scale_handle, 1); - if (ret) { - pr_err("%s Unable to set to high bandwidth\n", - __func__); - ret = qce_disable_clk(podev->qce); - if (ret) - pr_err("%s Unable enable clk\n", - __func__); - goto resume_exit; - } } resume_exit: diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c index f184ee11154835e2e5d1381e339e9f1cfe47177c..fd4257567d392fc36238376835bd6ff1c9df3e7d 100644 --- a/drivers/crypto/msm/qcrypto.c +++ b/drivers/crypto/msm/qcrypto.c @@ -265,7 +265,7 @@ static void qcrypto_free_req_control(struct crypto_engine *pce, preq->arsp = NULL; /* free req */ if (xchg(&preq->in_use, false) == false) - pr_warn("request info %p free already\n", preq); + pr_warn("request info %pK free already\n", preq); else atomic_dec(&pce->req_count); } @@ -439,6 +439,7 @@ struct qcrypto_cipher_req_ctx { u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH]; unsigned int ivsize; int aead; + int ccmtype; /* default: 0, rfc4309: 1 */ struct scatterlist asg; /* Formatted associated data sg */ unsigned char *adata; /* Pointer to formatted assoc data */ enum qce_cipher_alg_enum alg; @@ -583,44 +584,92 @@ static void _words_to_byte_stream(uint32_t *iv, unsigned char *b, static void qcrypto_ce_set_bus(struct crypto_engine *pengine, bool high_bw_req) { + struct crypto_priv *cp = pengine->pcp; + unsigned int control_flag; int ret = 0; - if (high_bw_req) { + if (cp->ce_support.req_bw_before_clk) { + if (high_bw_req) + control_flag = QCE_BW_REQUEST_FIRST; + else + control_flag = QCE_CLK_DISABLE_FIRST; + } else { + if (high_bw_req) + control_flag = QCE_CLK_ENABLE_FIRST; + else + control_flag = QCE_BW_REQUEST_RESET_FIRST; + } + + switch (control_flag) { + case QCE_CLK_ENABLE_FIRST: ret = qce_enable_clk(pengine->qce); if (ret) { pr_err("%s Unable enable clk\n", __func__); - goto clk_err; + return; } ret = msm_bus_scale_client_update_request( pengine->bus_scale_handle, 1); if (ret) { - pr_err("%s Unable to set to high bandwidth\n", - __func__); - qce_disable_clk(pengine->qce); - goto clk_err; + pr_err("%s Unable to set high bw\n", __func__); + ret = qce_disable_clk(pengine->qce); + if (ret) + pr_err("%s Unable disable clk\n", __func__); + return; } - } else { + break; + case QCE_BW_REQUEST_FIRST: ret = msm_bus_scale_client_update_request( + pengine->bus_scale_handle, 1); + if (ret) { + pr_err("%s Unable to set high bw\n", __func__); + return; + } + ret = qce_enable_clk(pengine->qce); + if (ret) { + pr_err("%s Unable enable clk\n", __func__); + ret = msm_bus_scale_client_update_request( pengine->bus_scale_handle, 0); + if (ret) + pr_err("%s Unable to set low bw\n", __func__); + return; + } + break; + case QCE_CLK_DISABLE_FIRST: + ret = qce_disable_clk(pengine->qce); if (ret) { - pr_err("%s Unable to set to low bandwidth\n", - __func__); - goto clk_err; + pr_err("%s Unable to disable clk\n", __func__); + return; + } + ret = msm_bus_scale_client_update_request( + pengine->bus_scale_handle, 0); + if (ret) { + pr_err("%s Unable to set low bw\n", __func__); + ret = qce_enable_clk(pengine->qce); + if (ret) + pr_err("%s Unable enable clk\n", __func__); + return; + } + break; + case QCE_BW_REQUEST_RESET_FIRST: + ret = msm_bus_scale_client_update_request( + pengine->bus_scale_handle, 0); + if (ret) { + pr_err("%s Unable to set low bw\n", __func__); + return; } ret = qce_disable_clk(pengine->qce); if (ret) { - pr_err("%s Unable disable clk\n", __func__); + pr_err("%s Unable to disable clk\n", __func__); ret = msm_bus_scale_client_update_request( pengine->bus_scale_handle, 1); if (ret) - pr_err("%s Unable to set to high bandwidth\n", - __func__); - goto clk_err; + pr_err("%s Unable to set high bw\n", __func__); + return; } + break; + default: + return; } -clk_err: - return; - } static void qcrypto_bw_reaper_timer_callback(unsigned long data) @@ -1710,7 +1759,7 @@ static void _qce_ahash_complete(void *cookie, unsigned char *digest, } #ifdef QCRYPTO_DEBUG - dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %p ret %d\n", + dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %pK ret %d\n", areq, ret); #endif if (digest) { @@ -1769,7 +1818,7 @@ static void _qce_ablk_cipher_complete(void *cookie, unsigned char *icb, } #ifdef QCRYPTO_DEBUG - dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n", + dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %pK ret %d\n", areq, ret); #endif if (iv) @@ -1888,9 +1937,8 @@ static int aead_ccm_set_msg_len(u8 *block, unsigned int msglen, int csize) return 0; } -static int qccrypto_set_aead_ccm_nonce(struct qce_req *qreq) +static int qccrypto_set_aead_ccm_nonce(struct qce_req *qreq, uint32_t assoclen) { - struct aead_request *areq = (struct aead_request *) qreq->areq; unsigned int i = ((unsigned int)qreq->iv[0]) + 1; memcpy(&qreq->nonce[0], qreq->iv, qreq->ivsize); @@ -1899,7 +1947,7 @@ static int qccrypto_set_aead_ccm_nonce(struct qce_req *qreq) * NIST Special Publication 800-38C */ qreq->nonce[0] |= (8 * ((qreq->authsize - 2) / 2)); - if (areq->assoclen) + if (assoclen) qreq->nonce[0] |= 64; if (i > MAX_NONCE) @@ -2105,24 +2153,31 @@ static int _qcrypto_process_aead(struct crypto_engine *pengine, qreq.flags = cipher_ctx->flags; if (qreq.mode == QCE_MODE_CCM) { + uint32_t assoclen; + if (qreq.dir == QCE_ENCRYPT) qreq.cryptlen = req->cryptlen; else qreq.cryptlen = req->cryptlen - qreq.authsize; + + /* if rfc4309 ccm, adjust assoclen */ + assoclen = req->assoclen; + if (rctx->ccmtype) + assoclen -= 8; /* Get NONCE */ - ret = qccrypto_set_aead_ccm_nonce(&qreq); + ret = qccrypto_set_aead_ccm_nonce(&qreq, assoclen); if (ret) return ret; - if (req->assoclen) { - rctx->adata = kzalloc((req->assoclen + 0x64), + if (assoclen) { + rctx->adata = kzalloc((assoclen + 0x64), GFP_ATOMIC); if (!rctx->adata) return -ENOMEM; /* Format Associated data */ ret = qcrypto_aead_ccm_format_adata(&qreq, - req->assoclen, + assoclen, req->src, rctx->adata); } else { @@ -2465,7 +2520,7 @@ static int _qcrypto_enc_aes_ecb(struct ablkcipher_request *req) WARN_ON(crypto_tfm_alg_type(req->base.tfm) != CRYPTO_ALG_TYPE_ABLKCIPHER); #ifdef QCRYPTO_DEBUG - dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %p\n", req); + dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %pK\n", req); #endif if ((ctx->enc_key_len == AES_KEYSIZE_192) && @@ -2495,7 +2550,7 @@ static int _qcrypto_enc_aes_cbc(struct ablkcipher_request *req) WARN_ON(crypto_tfm_alg_type(req->base.tfm) != CRYPTO_ALG_TYPE_ABLKCIPHER); #ifdef QCRYPTO_DEBUG - dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %p\n", req); + dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %pK\n", req); #endif if ((ctx->enc_key_len == AES_KEYSIZE_192) && @@ -2525,7 +2580,7 @@ static int _qcrypto_enc_aes_ctr(struct ablkcipher_request *req) WARN_ON(crypto_tfm_alg_type(req->base.tfm) != CRYPTO_ALG_TYPE_ABLKCIPHER); #ifdef QCRYPTO_DEBUG - dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %p\n", req); + dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %pK\n", req); #endif if ((ctx->enc_key_len == AES_KEYSIZE_192) && @@ -2585,6 +2640,7 @@ static int _qcrypto_aead_encrypt_aes_ccm(struct aead_request *req) rctx->dir = QCE_ENCRYPT; rctx->mode = QCE_MODE_CCM; rctx->iv = req->iv; + rctx->ccmtype = 0; pstat->aead_ccm_aes_enc++; return _qcrypto_queue_req(cp, ctx->pengine, &req->base); @@ -2599,6 +2655,8 @@ static int _qcrypto_aead_rfc4309_enc_aes_ccm(struct aead_request *req) pstat = &_qcrypto_stat; + if (req->assoclen != 16 && req->assoclen != 20) + return -EINVAL; rctx = aead_request_ctx(req); rctx->aead = 1; rctx->alg = CIPHER_ALG_AES; @@ -2608,6 +2666,7 @@ static int _qcrypto_aead_rfc4309_enc_aes_ccm(struct aead_request *req) rctx->rfc4309_iv[0] = 3; /* L -1 */ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3); memcpy(&rctx->rfc4309_iv[4], req->iv, 8); + rctx->ccmtype = 1; rctx->iv = rctx->rfc4309_iv; pstat->aead_rfc4309_ccm_aes_enc++; return _qcrypto_queue_req(cp, ctx->pengine, &req->base); @@ -2709,7 +2768,7 @@ static int _qcrypto_dec_aes_ecb(struct ablkcipher_request *req) WARN_ON(crypto_tfm_alg_type(req->base.tfm) != CRYPTO_ALG_TYPE_ABLKCIPHER); #ifdef QCRYPTO_DEBUG - dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %p\n", req); + dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %pK\n", req); #endif if ((ctx->enc_key_len == AES_KEYSIZE_192) && @@ -2739,7 +2798,7 @@ static int _qcrypto_dec_aes_cbc(struct ablkcipher_request *req) WARN_ON(crypto_tfm_alg_type(req->base.tfm) != CRYPTO_ALG_TYPE_ABLKCIPHER); #ifdef QCRYPTO_DEBUG - dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %p\n", req); + dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %pK\n", req); #endif if ((ctx->enc_key_len == AES_KEYSIZE_192) && @@ -2769,7 +2828,7 @@ static int _qcrypto_dec_aes_ctr(struct ablkcipher_request *req) WARN_ON(crypto_tfm_alg_type(req->base.tfm) != CRYPTO_ALG_TYPE_ABLKCIPHER); #ifdef QCRYPTO_DEBUG - dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %p\n", req); + dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %pK\n", req); #endif if ((ctx->enc_key_len == AES_KEYSIZE_192) && @@ -2915,6 +2974,7 @@ static int _qcrypto_aead_decrypt_aes_ccm(struct aead_request *req) rctx->dir = QCE_DECRYPT; rctx->mode = QCE_MODE_CCM; rctx->iv = req->iv; + rctx->ccmtype = 0; pstat->aead_ccm_aes_dec++; return _qcrypto_queue_req(cp, ctx->pengine, &req->base); @@ -2928,6 +2988,8 @@ static int _qcrypto_aead_rfc4309_dec_aes_ccm(struct aead_request *req) struct crypto_stat *pstat; pstat = &_qcrypto_stat; + if (req->assoclen != 16 && req->assoclen != 20) + return -EINVAL; rctx = aead_request_ctx(req); rctx->aead = 1; rctx->alg = CIPHER_ALG_AES; @@ -2937,6 +2999,7 @@ static int _qcrypto_aead_rfc4309_dec_aes_ccm(struct aead_request *req) rctx->rfc4309_iv[0] = 3; /* L -1 */ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3); memcpy(&rctx->rfc4309_iv[4], req->iv, 8); + rctx->ccmtype = 1; rctx->iv = rctx->rfc4309_iv; pstat->aead_rfc4309_ccm_aes_dec++; return _qcrypto_queue_req(cp, ctx->pengine, &req->base); @@ -3331,7 +3394,7 @@ static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req) #ifdef QCRYPTO_DEBUG dev_info(&ctx->pengine->pdev->dev, - "_qcrypto_aead_encrypt_aes_cbc: %p\n", req); + "_qcrypto_aead_encrypt_aes_cbc: %pK\n", req); #endif rctx = aead_request_ctx(req); @@ -3362,7 +3425,7 @@ static int _qcrypto_aead_decrypt_aes_cbc(struct aead_request *req) #ifdef QCRYPTO_DEBUG dev_info(&ctx->pengine->pdev->dev, - "_qcrypto_aead_decrypt_aes_cbc: %p\n", req); + "_qcrypto_aead_decrypt_aes_cbc: %pK\n", req); #endif rctx = aead_request_ctx(req); rctx->aead = 1; @@ -3901,7 +3964,7 @@ static int _sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base); uint8_t *in_buf; int ret = 0; - struct scatterlist sg; + struct scatterlist sg = {0}; struct ahash_request *ahash_req; struct completion ahash_req_complete; @@ -3948,7 +4011,7 @@ static int _sha1_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int len) { struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base); - + int ret = 0; memset(&sha_ctx->authkey[0], 0, SHA1_BLOCK_SIZE); if (len <= SHA1_BLOCK_SIZE) { memcpy(&sha_ctx->authkey[0], key, len); @@ -3956,16 +4019,19 @@ static int _sha1_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, } else { sha_ctx->alg = QCE_HASH_SHA1; sha_ctx->diglen = SHA1_DIGEST_SIZE; - _sha_hmac_setkey(tfm, key, len); + ret = _sha_hmac_setkey(tfm, key, len); + if (ret) + pr_err("SHA1 hmac setkey failed\n"); sha_ctx->authkey_in_len = SHA1_BLOCK_SIZE; } - return 0; + return ret; } static int _sha256_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int len) { struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base); + int ret = 0; memset(&sha_ctx->authkey[0], 0, SHA256_BLOCK_SIZE); if (len <= SHA256_BLOCK_SIZE) { @@ -3974,11 +4040,13 @@ static int _sha256_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, } else { sha_ctx->alg = QCE_HASH_SHA256; sha_ctx->diglen = SHA256_DIGEST_SIZE; - _sha_hmac_setkey(tfm, key, len); + ret = _sha_hmac_setkey(tfm, key, len); + if (ret) + pr_err("SHA256 hmac setkey failed\n"); sha_ctx->authkey_in_len = SHA256_BLOCK_SIZE; } - return 0; + return ret; } static int _sha_hmac_init_ihash(struct ahash_request *req, @@ -4226,7 +4294,7 @@ int qcrypto_cipher_set_device(struct ablkcipher_request *req, unsigned int dev) }; EXPORT_SYMBOL(qcrypto_cipher_set_device); -int qcrypto_cipher_set_device_hw(struct ablkcipher_request *req, u32 dev, +int qcrypto_cipher_set_device_hw(struct skcipher_request *req, u32 dev, u32 hw_inst) { struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); @@ -4272,7 +4340,7 @@ int qcrypto_ahash_set_device(struct ahash_request *req, unsigned int dev) }; EXPORT_SYMBOL(qcrypto_ahash_set_device); -int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags) +int qcrypto_cipher_set_flag(struct skcipher_request *req, unsigned int flags) { struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); struct crypto_priv *cp = ctx->cp; @@ -4856,12 +4924,36 @@ static int _qcrypto_probe(struct platform_device *pdev) if (!pengine) return -ENOMEM; - /* open qce */ + cp->platform_support.bus_scale_table = (struct msm_bus_scale_pdata *) + msm_bus_cl_get_pdata(pdev); + if (!cp->platform_support.bus_scale_table) { + dev_err(&pdev->dev, "bus_scale_table is NULL\n"); + pengine->bw_state = BUS_HAS_BANDWIDTH; + } else { + pengine->bus_scale_handle = msm_bus_scale_register_client( + (struct msm_bus_scale_pdata *) + cp->platform_support.bus_scale_table); + if (!pengine->bus_scale_handle) { + dev_err(&pdev->dev, "failed to get bus scale handle\n"); + rc = -ENOMEM; + goto exit_kzfree; + } + pengine->bw_state = BUS_NO_BANDWIDTH; + } + rc = msm_bus_scale_client_update_request(pengine->bus_scale_handle, 1); + if (rc) { + dev_err(&pdev->dev, "failed to set high bandwidth\n"); + goto exit_kzfree; + } handle = qce_open(pdev, &rc); if (handle == NULL) { - kzfree(pengine); - platform_set_drvdata(pdev, NULL); - return rc; + rc = -ENODEV; + goto exit_free_pdata; + } + rc = msm_bus_scale_client_update_request(pengine->bus_scale_handle, 0); + if (rc) { + dev_err(&pdev->dev, "failed to set low bandwidth\n"); + goto exit_qce_close; } platform_set_drvdata(pdev, pengine); @@ -4903,7 +4995,7 @@ static int _qcrypto_probe(struct platform_device *pdev) pengine->max_req, GFP_KERNEL); if (pqcrypto_req_control == NULL) { rc = -ENOMEM; - goto err; + goto exit_unlock_mutex; } qcrypto_init_req_control(pengine, pqcrypto_req_control); if (cp->ce_support.bam) { @@ -4911,15 +5003,7 @@ static int _qcrypto_probe(struct platform_device *pdev) cp->platform_support.shared_ce_resource = 0; cp->platform_support.hw_key_support = cp->ce_support.hw_key; cp->platform_support.sha_hmac = 1; - - cp->platform_support.bus_scale_table = - (struct msm_bus_scale_pdata *) - msm_bus_cl_get_pdata(pdev); - if (!cp->platform_support.bus_scale_table) - pr_warn("bus_scale_table is NULL\n"); - pengine->ce_device = cp->ce_support.ce_device; - } else { platform_support = (struct msm_ce_hw_support *)pdev->dev.platform_data; @@ -4928,33 +5012,11 @@ static int _qcrypto_probe(struct platform_device *pdev) platform_support->shared_ce_resource; cp->platform_support.hw_key_support = platform_support->hw_key_support; - cp->platform_support.bus_scale_table = - platform_support->bus_scale_table; cp->platform_support.sha_hmac = platform_support->sha_hmac; } - pengine->bus_scale_handle = 0; - - if (cp->platform_support.bus_scale_table != NULL) { - pengine->bus_scale_handle = - msm_bus_scale_register_client( - (struct msm_bus_scale_pdata *) - cp->platform_support.bus_scale_table); - if (!pengine->bus_scale_handle) { - pr_err("%s not able to get bus scale\n", - __func__); - rc = -ENOMEM; - goto err; - } - pengine->bw_state = BUS_NO_BANDWIDTH; - } else { - pengine->bw_state = BUS_HAS_BANDWIDTH; - } - - if (cp->total_units != 1) { - mutex_unlock(&cp->engine_lock); - return 0; - } + if (cp->total_units != 1) + goto exit_unlock_mutex; /* register crypto cipher algorithms the device supports */ for (i = 0; i < ARRAY_SIZE(_qcrypto_ablk_cipher_algos); i++) { @@ -5243,13 +5305,19 @@ static int _qcrypto_probe(struct platform_device *pdev) } mutex_unlock(&cp->engine_lock); - return 0; err: _qcrypto_remove_engine(pengine); + kzfree(pqcrypto_req_control); +exit_unlock_mutex: mutex_unlock(&cp->engine_lock); +exit_qce_close: if (pengine->qce) qce_close(pengine->qce); +exit_free_pdata: + msm_bus_scale_client_update_request(pengine->bus_scale_handle, 0); + platform_set_drvdata(pdev, NULL); +exit_kzfree: kzfree(pengine); return rc; }; @@ -5323,8 +5391,11 @@ static int _qcrypto_suspend(struct platform_device *pdev, pm_message_t state) spin_unlock_irqrestore(&cp->lock, flags); if (ret) return ret; - if (qce_pm_table.suspend) + if (qce_pm_table.suspend) { + qcrypto_ce_set_bus(pengine, true); qce_pm_table.suspend(pengine->qce); + qcrypto_ce_set_bus(pengine, false); + } return 0; } @@ -5345,9 +5416,11 @@ static int _qcrypto_resume(struct platform_device *pdev) spin_lock_irqsave(&cp->lock, flags); if (pengine->bw_state == BUS_SUSPENDED) { spin_unlock_irqrestore(&cp->lock, flags); - if (qce_pm_table.resume) + if (qce_pm_table.resume) { + qcrypto_ce_set_bus(pengine, true); qce_pm_table.resume(pengine->qce); - + qcrypto_ce_set_bus(pengine, false); + } spin_lock_irqsave(&cp->lock, flags); pengine->bw_state = BUS_NO_BANDWIDTH; pengine->active_seq++; diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index c5aac25a57380ba8e6976538cb76ee5b72e6429c..b365ad78ac27accff12e0ad9099cf92cb75bc84a 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1620,6 +1620,7 @@ static int queue_cache_init(void) CWQ_ENTRY_SIZE, 0, NULL); if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) { kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); + queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; return -ENOMEM; } return 0; @@ -1629,6 +1630,8 @@ static void queue_cache_destroy(void) { kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]); + queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; + queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL; } static int spu_queue_register(struct spu_queue *p, unsigned long q_type) diff --git a/drivers/crypto/qce/Makefile b/drivers/crypto/qce/Makefile index 348dc3173afa5b9cb130a36a7b57669cc3abbe67..7f584eed039558b49f8fc7dc7f1cb5174d2889fa 100644 --- a/drivers/crypto/qce/Makefile +++ b/drivers/crypto/qce/Makefile @@ -1,5 +1,5 @@ -obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypto.o -qcrypto-objs := core.o \ +obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypt.o +qcrypt-objs := core.o \ common.o \ dma.o \ sha.o \ diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index dce1af0ce85ce8ec6dbd7184f02776cb173c41f0..a668286d62cb17aca693c525c1703594ae688aac 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -805,8 +805,9 @@ static int s5p_aes_probe(struct platform_device *pdev) dev_warn(dev, "feed control interrupt is not available.\n"); goto err_irq; } - err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt, - IRQF_SHARED, pdev->name, pdev); + err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL, + s5p_aes_interrupt, IRQF_ONESHOT, + pdev->name, pdev); if (err < 0) { dev_warn(dev, "feed control interrupt is not available.\n"); goto err_irq; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 0418a2f41dc0839d8a6d0dbcb1617ce1b770d148..1c8d79d93098fbec5272ff210597a75be6a13d10 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -816,7 +816,7 @@ static void talitos_unregister_rng(struct device *dev) * HMAC_SNOOP_NO_AFEA (HSNA) instead of type IPSEC_ESP */ #define TALITOS_CRA_PRIORITY_AEAD_HSNA (TALITOS_CRA_PRIORITY - 1) -#define TALITOS_MAX_KEY_SIZE 96 +#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE) #define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ struct talitos_ctx { @@ -1232,12 +1232,11 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, sg_link_tbl_len += authsize; } - sg_count = talitos_sg_map(dev, areq->src, cryptlen, edesc, - &desc->ptr[4], sg_count, areq->assoclen, - tbl_off); + ret = talitos_sg_map(dev, areq->src, sg_link_tbl_len, edesc, + &desc->ptr[4], sg_count, areq->assoclen, tbl_off); - if (sg_count > 1) { - tbl_off += sg_count; + if (ret > 1) { + tbl_off += ret; sync_needed = true; } @@ -1248,14 +1247,15 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, dma_map_sg(dev, areq->dst, sg_count, DMA_FROM_DEVICE); } - sg_count = talitos_sg_map(dev, areq->dst, cryptlen, edesc, - &desc->ptr[5], sg_count, areq->assoclen, - tbl_off); + ret = talitos_sg_map(dev, areq->dst, cryptlen, edesc, &desc->ptr[5], + sg_count, areq->assoclen, tbl_off); if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) to_talitos_ptr_ext_or(&desc->ptr[5], authsize, is_sec1); - if (sg_count > 1) { + /* ICV data */ + if (ret > 1) { + tbl_off += ret; edesc->icv_ool = true; sync_needed = true; @@ -1265,9 +1265,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, sizeof(struct talitos_ptr) + authsize; /* Add an entry to the link table for ICV data */ - tbl_ptr += sg_count - 1; - to_talitos_ptr_ext_set(tbl_ptr, 0, is_sec1); - tbl_ptr++; + to_talitos_ptr_ext_set(tbl_ptr - 1, 0, is_sec1); to_talitos_ptr_ext_set(tbl_ptr, DESC_PTR_LNKTBL_RETURN, is_sec1); to_talitos_ptr_len(tbl_ptr, authsize, is_sec1); @@ -1275,18 +1273,33 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, /* icv data follows link tables */ to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + offset, is_sec1); + } else { + dma_addr_t addr = edesc->dma_link_tbl; + + if (is_sec1) + addr += areq->assoclen + cryptlen; + else + addr += sizeof(struct talitos_ptr) * tbl_off; + + to_talitos_ptr(&desc->ptr[6], addr, is_sec1); + to_talitos_ptr_len(&desc->ptr[6], authsize, is_sec1); + } + } else if (!(desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)) { + ret = talitos_sg_map(dev, areq->dst, authsize, edesc, + &desc->ptr[6], sg_count, areq->assoclen + + cryptlen, + tbl_off); + if (ret > 1) { + tbl_off += ret; + edesc->icv_ool = true; + sync_needed = true; + } else { + edesc->icv_ool = false; } } else { edesc->icv_ool = false; } - /* ICV data */ - if (!(desc->hdr & DESC_HDR_TYPE_IPSEC_ESP)) { - to_talitos_ptr_len(&desc->ptr[6], authsize, is_sec1); - to_talitos_ptr(&desc->ptr[6], edesc->dma_link_tbl + - areq->assoclen + cryptlen, is_sec1); - } - /* iv out */ if (desc->hdr & DESC_HDR_TYPE_IPSEC_ESP) map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, @@ -1494,6 +1507,19 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, const u8 *key, unsigned int keylen) { struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + u32 tmp[DES_EXPKEY_WORDS]; + + if (keylen > TALITOS_MAX_KEY_SIZE) { + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + if (unlikely(crypto_ablkcipher_get_flags(cipher) & + CRYPTO_TFM_REQ_WEAK_KEY) && + !des_ekey(tmp, key)) { + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_WEAK_KEY); + return -EINVAL; + } memcpy(&ctx->key, key, keylen); ctx->keylen = keylen; @@ -1751,9 +1777,9 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, req_ctx->swinit = 0; } else { desc->ptr[1] = zero_entry; - /* Indicate next op is not the first. */ - req_ctx->first = 0; } + /* Indicate next op is not the first. */ + req_ctx->first = 0; /* HMAC key */ if (ctx->keylen) @@ -1764,7 +1790,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, sg_count = edesc->src_nents ?: 1; if (is_sec1 && sg_count > 1) - sg_copy_to_buffer(areq->src, sg_count, edesc->buf, length); + sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length); else sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count, DMA_TO_DEVICE); @@ -2609,7 +2635,7 @@ static struct talitos_alg_template driver_algs[] = { .ivsize = AES_BLOCK_SIZE, } }, - .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + .desc_hdr_template = DESC_HDR_TYPE_AESU_CTR_NONSNOOP | DESC_HDR_SEL0_AESU | DESC_HDR_MODE0_AESU_CTR, }, @@ -3042,6 +3068,11 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, t_alg->algt.alg.aead.setkey = aead_setkey; t_alg->algt.alg.aead.encrypt = aead_encrypt; t_alg->algt.alg.aead.decrypt = aead_decrypt; + if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) && + !strncmp(alg->cra_name, "authenc(hmac(sha224)", 20)) { + kfree(t_alg); + return ERR_PTR(-ENOTSUPP); + } break; case CRYPTO_ALG_TYPE_AHASH: alg = &t_alg->algt.alg.hash.halg.base; @@ -3052,7 +3083,8 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, t_alg->algt.alg.hash.final = ahash_final; t_alg->algt.alg.hash.finup = ahash_finup; t_alg->algt.alg.hash.digest = ahash_digest; - t_alg->algt.alg.hash.setkey = ahash_setkey; + if (!strncmp(alg->cra_name, "hmac", 4)) + t_alg->algt.alg.hash.setkey = ahash_setkey; t_alg->algt.alg.hash.import = ahash_import; t_alg->algt.alg.hash.export = ahash_export; diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 38ed10d761d006eb2f9e24e1c318f98a09a4a323..7cf6d31c1123a117d55dc3de87ed543a3c6279a6 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -80,11 +80,13 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, int ret; struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); + preempt_disable(); pagefault_disable(); enable_kernel_vsx(); ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); disable_kernel_vsx(); pagefault_enable(); + preempt_enable(); ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen); return ret; @@ -99,11 +101,13 @@ static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx, u8 *dst = walk->dst.virt.addr; unsigned int nbytes = walk->nbytes; + preempt_disable(); pagefault_disable(); enable_kernel_vsx(); aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key); disable_kernel_vsx(); pagefault_enable(); + preempt_enable(); crypto_xor(keystream, src, nbytes); memcpy(dst, keystream, nbytes); @@ -132,6 +136,7 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { + preempt_disable(); pagefault_disable(); enable_kernel_vsx(); aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, @@ -143,6 +148,7 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, walk.iv); disable_kernel_vsx(); pagefault_enable(); + preempt_enable(); /* We need to update IV mostly for last bytes/round */ inc = (nbytes & AES_BLOCK_MASK) / AES_BLOCK_SIZE; diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 193224889e41c9e17f1607c3b9122b0a425d8da6..40be3747724d9e86bbbc2271ed24acde1888cfed 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -546,20 +546,18 @@ static void dax_dev_release(struct device *dev) struct dax_dev *dax_dev = to_dax_dev(dev); struct dax_region *dax_region = dax_dev->region; - ida_simple_remove(&dax_region->ida, dax_dev->id); + if (dax_dev->id >= 0) + ida_simple_remove(&dax_region->ida, dax_dev->id); ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); dax_region_put(dax_region); iput(dax_dev->inode); kfree(dax_dev); } -static void unregister_dax_dev(void *dev) +static void kill_dax_dev(struct dax_dev *dax_dev) { - struct dax_dev *dax_dev = to_dax_dev(dev); struct cdev *cdev = &dax_dev->cdev; - dev_dbg(dev, "%s\n", __func__); - /* * Note, rcu is not protecting the liveness of dax_dev, rcu is * ensuring that any fault handlers that might have seen @@ -571,11 +569,20 @@ static void unregister_dax_dev(void *dev) synchronize_srcu(&dax_srcu); unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); cdev_del(cdev); +} + +static void unregister_dax_dev(void *dev) +{ + struct dax_dev *dax_dev = to_dax_dev(dev); + + dev_dbg(dev, "%s\n", __func__); + + kill_dax_dev(dax_dev); device_unregister(dev); } struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, - struct resource *res, int count) + int id, struct resource *res, int count) { struct device *parent = dax_region->dev; struct dax_dev *dax_dev; @@ -602,10 +609,16 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, if (i < count) goto err_id; - dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); - if (dax_dev->id < 0) { - rc = dax_dev->id; - goto err_id; + if (id < 0) { + id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); + dax_dev->id = id; + if (id < 0) { + rc = id; + goto err_id; + } + } else { + /* region provider owns @id lifetime */ + dax_dev->id = -1; } minor = ida_simple_get(&dax_minor_ida, 0, 0, GFP_KERNEL); @@ -644,9 +657,10 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, dev->parent = parent; dev->groups = dax_attribute_groups; dev->release = dax_dev_release; - dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); + dev_set_name(dev, "dax%d.%d", dax_region->id, id); rc = device_add(dev); if (rc) { + kill_dax_dev(dax_dev); put_device(dev); return ERR_PTR(rc); } @@ -662,7 +676,8 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, err_inode: ida_simple_remove(&dax_minor_ida, minor); err_minor: - ida_simple_remove(&dax_region->ida, dax_dev->id); + if (dax_dev->id >= 0) + ida_simple_remove(&dax_region->ida, dax_dev->id); err_id: kfree(dax_dev); diff --git a/drivers/dax/dax.h b/drivers/dax/dax.h index ddd829ab58c05884ffea85bfab8e198ce6303b72..b5ed85036b2a0bef88c231f2bae23b0dece8d8bb 100644 --- a/drivers/dax/dax.h +++ b/drivers/dax/dax.h @@ -21,5 +21,5 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, void *addr, unsigned long flags); struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, - struct resource *res, int count); + int id, struct resource *res, int count); #endif /* __DAX_H__ */ diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 73c6ce93a0d9204227818465a707db9f7d5806fb..eebb35720398bf6280b0b61a1a85d43de41bfcac 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -58,13 +58,12 @@ static void dax_pmem_percpu_kill(void *data) static int dax_pmem_probe(struct device *dev) { - int rc; void *addr; struct resource res; struct dax_dev *dax_dev; + int rc, id, region_id; struct nd_pfn_sb *pfn_sb; struct dax_pmem *dax_pmem; - struct nd_region *nd_region; struct nd_namespace_io *nsio; struct dax_region *dax_region; struct nd_namespace_common *ndns; @@ -122,14 +121,17 @@ static int dax_pmem_probe(struct device *dev) /* adjust the dax_region resource to the start of data */ res.start += le64_to_cpu(pfn_sb->dataoff); - nd_region = to_nd_region(dev->parent); - dax_region = alloc_dax_region(dev, nd_region->id, &res, + rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); + if (rc != 2) + return -EINVAL; + + dax_region = alloc_dax_region(dev, region_id, &res, le32_to_cpu(pfn_sb->align), addr, PFN_DEV|PFN_MAP); if (!dax_region) return -ENOMEM; /* TODO: support for subdividing a dax region... */ - dax_dev = devm_create_dax_dev(dax_region, &res, 1); + dax_dev = devm_create_dax_dev(dax_region, id, &res, 1); /* child dax_dev instances now own the lifetime of the dax_region */ dax_region_put(dax_region); diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index b8effac0f114b98cd4b62f5f63a77c8f8158864d..3a2239ccf9f78ce38cf5816251de33584af9092f 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -135,6 +135,15 @@ config DEVFREQ_GOV_QCOM_CACHE_HWMON it can conflict with existing profiling tools. This governor is unlikely to be useful for other devices. +config DEVFREQ_GOV_SPDM_HYP + bool "QTI SPDM Hypervisor Governor" + depends on ARCH_QCOM + help + Hypervisor based governor for CPU bandwidth voting + for QTI chipsets. + Sets the frequency using a "on-demand" algorithm. + This governor is unlikely to be useful for other devices. + config DEVFREQ_GOV_MEMLAT tristate "HW monitor based governor for device BW" depends on ARM_MEMLAT_MON @@ -227,6 +236,24 @@ config QCOM_DEVFREQ_DEVBW agnostic interface to so that some of the devfreq governors can be shared across SoCs. +config SPDM_SCM + bool "QTI SPDM SCM based call support" + depends on DEVFREQ_SPDM + help + SPDM driver support the dcvs algorithm logic being accessed via + scm or hvc calls. This adds the support for SPDM interaction to + tz via SCM based call. If not selected then Hypervior interaction + will be activated. + +config DEVFREQ_SPDM + bool "QTI SPDM based bandwidth voting" + depends on ARCH_QCOM + select DEVFREQ_GOV_SPDM_HYP + help + This adds the support for SPDM based bandwidth voting on QTI chipsets. + This driver allows any SPDM based client to vote for bandwidth. + Used with the QTI SPDM Hypervisor Governor. + source "drivers/devfreq/event/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index f248e02e613e24844d7bf9dcafa248f3bca04c38..0202f664f3db1ad857437bc6e2bdc186e1ca88bd 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_QCOMCCI_HWMON) += msmcci-hwmon.o obj-$(CONFIG_QCOM_M4M_HWMON) += m4m-hwmon.o obj-$(CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON) += governor_bw_hwmon.o obj-$(CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON) += governor_cache_hwmon.o +obj-$(CONFIG_DEVFREQ_GOV_SPDM_HYP) += governor_spdm_bw_hyp.o obj-$(CONFIG_DEVFREQ_GOV_MEMLAT) += governor_memlat.o # DEVFREQ Drivers @@ -23,6 +24,7 @@ obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o obj-$(CONFIG_QCOM_DEVFREQ_DEVBW) += devfreq_devbw.o obj-$(CONFIG_DEVFREQ_SIMPLE_DEV) += devfreq_simple_dev.o +obj-$(CONFIG_DEVFREQ_SPDM) += devfreq_spdm.o devfreq_spdm_debugfs.o # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index ed83185444017c2ce92f4ec294c9a69926d8a04f..1dca479fd8ba9802ae4ff4c6394047ea182536d4 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -31,11 +31,13 @@ #include "governor.h" #include "governor_memlat.h" #include +#include enum ev_index { INST_IDX, CM_IDX, CYC_IDX, + STALL_CYC_IDX, NUM_EVENTS }; #define INST_EV 0x08 @@ -47,22 +49,35 @@ struct event_data { unsigned long prev_count; }; -struct memlat_hwmon_data { +struct cpu_pmu_stats { struct event_data events[NUM_EVENTS]; ktime_t prev_ts; - bool init_pending; - unsigned long cache_miss_event; - unsigned long inst_event; }; -static DEFINE_PER_CPU(struct memlat_hwmon_data, pm_data); struct cpu_grp_info { cpumask_t cpus; + cpumask_t inited_cpus; + unsigned int event_ids[NUM_EVENTS]; + struct cpu_pmu_stats *cpustats; struct memlat_hwmon hw; struct notifier_block arm_memlat_cpu_notif; + struct list_head mon_list; }; -static unsigned long compute_freq(struct memlat_hwmon_data *hw_data, +struct memlat_mon_spec { + bool is_compute; +}; + +#define to_cpustats(cpu_grp, cpu) \ + (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) +#define to_devstats(cpu_grp, cpu) \ + (&cpu_grp->hw.core_stats[cpu - cpumask_first(&cpu_grp->cpus)]) +#define to_cpu_grp(hwmon) container_of(hwmon, struct cpu_grp_info, hw) + +static LIST_HEAD(memlat_mon_list); +static DEFINE_MUTEX(list_lock); + +static unsigned long compute_freq(struct cpu_pmu_stats *cpustats, unsigned long cyc_cnt) { ktime_t ts; @@ -70,10 +85,10 @@ static unsigned long compute_freq(struct memlat_hwmon_data *hw_data, unsigned long freq = 0; ts = ktime_get(); - diff = ktime_to_us(ktime_sub(ts, hw_data->prev_ts)); + diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts)); if (!diff) diff = 1; - hw_data->prev_ts = ts; + cpustats->prev_ts = ts; freq = cyc_cnt; do_div(freq, diff); @@ -86,82 +101,81 @@ static inline unsigned long read_event(struct event_data *event) unsigned long ev_count; u64 total, enabled, running; - total = perf_event_read_value(event->pevent, &enabled, &running); - if (total >= event->prev_count) - ev_count = total - event->prev_count; - else - ev_count = (MAX_COUNT_LIM - event->prev_count) + total; + if (!event->pevent) + return 0; + total = perf_event_read_value(event->pevent, &enabled, &running); + ev_count = total - event->prev_count; event->prev_count = total; - return ev_count; } static void read_perf_counters(int cpu, struct cpu_grp_info *cpu_grp) { - int cpu_idx; - struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu); - struct memlat_hwmon *hw = &cpu_grp->hw; - unsigned long cyc_cnt; - - if (hw_data->init_pending) - return; - - cpu_idx = cpu - cpumask_first(&cpu_grp->cpus); - - hw->core_stats[cpu_idx].inst_count = - read_event(&hw_data->events[INST_IDX]); - - hw->core_stats[cpu_idx].mem_count = - read_event(&hw_data->events[CM_IDX]); - - cyc_cnt = read_event(&hw_data->events[CYC_IDX]); - hw->core_stats[cpu_idx].freq = compute_freq(hw_data, cyc_cnt); + struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); + struct dev_stats *devstats = to_devstats(cpu_grp, cpu); + unsigned long cyc_cnt, stall_cnt; + + devstats->inst_count = read_event(&cpustats->events[INST_IDX]); + devstats->mem_count = read_event(&cpustats->events[CM_IDX]); + cyc_cnt = read_event(&cpustats->events[CYC_IDX]); + devstats->freq = compute_freq(cpustats, cyc_cnt); + if (cpustats->events[STALL_CYC_IDX].pevent) { + stall_cnt = read_event(&cpustats->events[STALL_CYC_IDX]); + stall_cnt = min(stall_cnt, cyc_cnt); + devstats->stall_pct = mult_frac(100, stall_cnt, cyc_cnt); + } else { + devstats->stall_pct = 100; + } } static unsigned long get_cnt(struct memlat_hwmon *hw) { int cpu; - struct cpu_grp_info *cpu_grp = container_of(hw, - struct cpu_grp_info, hw); + struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); - for_each_cpu(cpu, &cpu_grp->cpus) + for_each_cpu(cpu, &cpu_grp->inited_cpus) read_perf_counters(cpu, cpu_grp); return 0; } -static void delete_events(struct memlat_hwmon_data *hw_data) +static void delete_events(struct cpu_pmu_stats *cpustats) { int i; - for (i = 0; i < NUM_EVENTS; i++) { - hw_data->events[i].prev_count = 0; - perf_event_release_kernel(hw_data->events[i].pevent); + for (i = 0; i < ARRAY_SIZE(cpustats->events); i++) { + cpustats->events[i].prev_count = 0; + if (cpustats->events[i].pevent) { + perf_event_release_kernel(cpustats->events[i].pevent); + cpustats->events[i].pevent = NULL; + } } } static void stop_hwmon(struct memlat_hwmon *hw) { - int cpu, idx; - struct memlat_hwmon_data *hw_data; - struct cpu_grp_info *cpu_grp = container_of(hw, - struct cpu_grp_info, hw); + int cpu; + struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); + struct dev_stats *devstats; get_online_cpus(); - for_each_cpu(cpu, &cpu_grp->cpus) { - hw_data = &per_cpu(pm_data, cpu); - if (hw_data->init_pending) - hw_data->init_pending = false; - else - delete_events(hw_data); + for_each_cpu(cpu, &cpu_grp->inited_cpus) { + delete_events(to_cpustats(cpu_grp, cpu)); /* Clear governor data */ - idx = cpu - cpumask_first(&cpu_grp->cpus); - hw->core_stats[idx].inst_count = 0; - hw->core_stats[idx].mem_count = 0; - hw->core_stats[idx].freq = 0; + devstats = to_devstats(cpu_grp, cpu); + devstats->inst_count = 0; + devstats->mem_count = 0; + devstats->freq = 0; + devstats->stall_pct = 0; } + mutex_lock(&list_lock); + if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) + list_del(&cpu_grp->mon_list); + mutex_unlock(&list_lock); + cpumask_clear(&cpu_grp->inited_cpus); + put_online_cpus(); unregister_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif); @@ -173,7 +187,7 @@ static struct perf_event_attr *alloc_attr(void) attr = kzalloc(sizeof(struct perf_event_attr), GFP_KERNEL); if (!attr) - return ERR_PTR(-ENOMEM); + return attr; attr->type = PERF_TYPE_RAW; attr->size = sizeof(struct perf_event_attr); @@ -183,37 +197,32 @@ static struct perf_event_attr *alloc_attr(void) return attr; } -static int set_events(struct memlat_hwmon_data *hw_data, int cpu) +static int set_events(struct cpu_grp_info *cpu_grp, int cpu) { struct perf_event *pevent; struct perf_event_attr *attr; - int err; + int err, i; + unsigned int event_id; + struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); /* Allocate an attribute for event initialization */ attr = alloc_attr(); - if (IS_ERR(attr)) - return PTR_ERR(attr); - - attr->config = hw_data->inst_event; - pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); - if (IS_ERR(pevent)) - goto err_out; - hw_data->events[INST_IDX].pevent = pevent; - perf_event_enable(hw_data->events[INST_IDX].pevent); - - attr->config = hw_data->cache_miss_event; - pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); - if (IS_ERR(pevent)) - goto err_out; - hw_data->events[CM_IDX].pevent = pevent; - perf_event_enable(hw_data->events[CM_IDX].pevent); - - attr->config = CYC_EV; - pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); - if (IS_ERR(pevent)) - goto err_out; - hw_data->events[CYC_IDX].pevent = pevent; - perf_event_enable(hw_data->events[CYC_IDX].pevent); + if (!attr) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(cpustats->events); i++) { + event_id = cpu_grp->event_ids[i]; + if (!event_id) + continue; + + attr->config = event_id; + pevent = perf_event_create_kernel_counter(attr, cpu, NULL, + NULL, NULL); + if (IS_ERR(pevent)) + goto err_out; + cpustats->events[i].pevent = pevent; + perf_event_enable(pevent); + } kfree(attr); return 0; @@ -228,15 +237,24 @@ static int arm_memlat_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) { unsigned long cpu = (unsigned long)hcpu; - struct memlat_hwmon_data *hw_data = &per_cpu(pm_data, cpu); + struct cpu_grp_info *cpu_grp, *tmp; - if ((action != CPU_ONLINE) || !hw_data->init_pending) + if (action != CPU_ONLINE) return NOTIFY_OK; - if (set_events(hw_data, cpu)) - pr_warn("Failed to create perf event for CPU%lu\n", cpu); - - hw_data->init_pending = false; + mutex_lock(&list_lock); + list_for_each_entry_safe(cpu_grp, tmp, &memlat_mon_list, mon_list) { + if (!cpumask_test_cpu(cpu, &cpu_grp->cpus) || + cpumask_test_cpu(cpu, &cpu_grp->inited_cpus)) + continue; + if (set_events(cpu_grp, cpu)) + pr_warn("Failed to create perf ev for CPU%lu\n", cpu); + else + cpumask_set_cpu(cpu, &cpu_grp->inited_cpus); + if (cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) + list_del(&cpu_grp->mon_list); + } + mutex_unlock(&list_lock); return NOTIFY_OK; } @@ -244,29 +262,32 @@ static int arm_memlat_cpu_callback(struct notifier_block *nb, static int start_hwmon(struct memlat_hwmon *hw) { int cpu, ret = 0; - struct memlat_hwmon_data *hw_data; - struct cpu_grp_info *cpu_grp = container_of(hw, - struct cpu_grp_info, hw); + struct cpu_grp_info *cpu_grp = to_cpu_grp(hw); register_cpu_notifier(&cpu_grp->arm_memlat_cpu_notif); get_online_cpus(); for_each_cpu(cpu, &cpu_grp->cpus) { - hw_data = &per_cpu(pm_data, cpu); - ret = set_events(hw_data, cpu); + ret = set_events(cpu_grp, cpu); if (ret) { if (!cpu_online(cpu)) { - hw_data->init_pending = true; ret = 0; } else { pr_warn("Perf event init failed on CPU%d\n", cpu); break; } + } else { + cpumask_set_cpu(cpu, &cpu_grp->inited_cpus); } } + mutex_lock(&list_lock); + if (!cpumask_equal(&cpu_grp->cpus, &cpu_grp->inited_cpus)) + list_add_tail(&cpu_grp->mon_list, &memlat_mon_list); + mutex_unlock(&list_lock); put_online_cpus(); + return ret; } @@ -301,8 +322,9 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct memlat_hwmon *hw; struct cpu_grp_info *cpu_grp; + const struct memlat_mon_spec *spec; int cpu, ret; - u32 cachemiss_ev, inst_ev; + u32 event_id; cpu_grp = devm_kzalloc(dev, sizeof(*cpu_grp), GFP_KERNEL); if (!cpu_grp) @@ -328,42 +350,68 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) if (!hw->core_stats) return -ENOMEM; + cpu_grp->cpustats = devm_kzalloc(dev, hw->num_cores * + sizeof(*(cpu_grp->cpustats)), GFP_KERNEL); + if (!cpu_grp->cpustats) + return -ENOMEM; + + cpu_grp->event_ids[CYC_IDX] = CYC_EV; + + for_each_cpu(cpu, &cpu_grp->cpus) + to_devstats(cpu_grp, cpu)->id = cpu; + + hw->start_hwmon = &start_hwmon; + hw->stop_hwmon = &stop_hwmon; + hw->get_cnt = &get_cnt; + + spec = of_device_get_match_data(dev); + if (spec && spec->is_compute) { + ret = register_compute(dev, hw); + if (ret) + pr_err("Compute Gov registration failed\n"); + + return ret; + } + ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev", - &cachemiss_ev); + &event_id); if (ret) { dev_dbg(dev, "Cache Miss event not specified. Using def:0x%x\n", - L2DM_EV); - cachemiss_ev = L2DM_EV; + L2DM_EV); + event_id = L2DM_EV; } + cpu_grp->event_ids[CM_IDX] = event_id; - ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &inst_ev); + ret = of_property_read_u32(dev->of_node, "qcom,inst-ev", &event_id); if (ret) { dev_dbg(dev, "Inst event not specified. Using def:0x%x\n", - INST_EV); - inst_ev = INST_EV; + INST_EV); + event_id = INST_EV; } + cpu_grp->event_ids[INST_IDX] = event_id; - for_each_cpu(cpu, &cpu_grp->cpus) { - hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu; - (&per_cpu(pm_data, cpu))->cache_miss_event = cachemiss_ev; - (&per_cpu(pm_data, cpu))->inst_event = inst_ev; - } - - hw->start_hwmon = &start_hwmon; - hw->stop_hwmon = &stop_hwmon; - hw->get_cnt = &get_cnt; + ret = of_property_read_u32(dev->of_node, "qcom,stall-cycle-ev", + &event_id); + if (ret) + dev_dbg(dev, "Stall cycle event not specified. Event ignored.\n"); + else + cpu_grp->event_ids[STALL_CYC_IDX] = event_id; ret = register_memlat(dev, hw); - if (ret) { + if (ret) pr_err("Mem Latency Gov registration failed\n"); - return ret; - } - return 0; + return ret; } +static const struct memlat_mon_spec spec[] = { + [0] = { false }, + [1] = { true }, +}; + static const struct of_device_id memlat_match_table[] = { - { .compatible = "qcom,arm-memlat-mon" }, + { .compatible = "qcom,arm-memlat-mon", .data = &spec[0] }, + { .compatible = "qcom,arm-cpu-mon", .data = &spec[1] }, {} }; diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c index d70104d2428999dea5ba051188de730181197c31..33e16261983cabe48a8fc0ce2df9770319a5357e 100644 --- a/drivers/devfreq/bimc-bwmon.c +++ b/drivers/devfreq/bimc-bwmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,14 +26,21 @@ #include #include #include +#include +#include #include "governor_bw_hwmon.h" #define GLB_INT_STATUS(m) ((m)->global_base + 0x100) #define GLB_INT_CLR(m) ((m)->global_base + 0x108) #define GLB_INT_EN(m) ((m)->global_base + 0x10C) #define MON_INT_STATUS(m) ((m)->base + 0x100) +#define MON_INT_STATUS_MASK 0x03 +#define MON2_INT_STATUS_MASK 0xA0 +#define MON2_INT_DISABLE_MASK 0xF0 +#define MON2_INT_STATUS_SHIFT 4 #define MON_INT_CLR(m) ((m)->base + 0x108) #define MON_INT_EN(m) ((m)->base + 0x10C) +#define MON_INT_ENABLE 0x1 #define MON_EN(m) ((m)->base + 0x280) #define MON_CLEAR(m) ((m)->base + 0x284) #define MON_CNT(m) ((m)->base + 0x288) @@ -54,9 +61,30 @@ #define MON2_ZONE_CNT(m) ((m)->base + 0x2D8) #define MON2_ZONE_MAX(m, zone) ((m)->base + 0x2E0 + 0x4 * zone) -enum bwmon_type { - BWMON_1, - BWMON_2, +#define MON3_INT_STATUS(m) ((m)->base + 0x00) +#define MON3_INT_CLR(m) ((m)->base + 0x08) +#define MON3_INT_EN(m) ((m)->base + 0x0C) +#define MON3_INT_STATUS_MASK 0x0A +#define MON3_INT_DISABLE_MASK 0x0F +#define MON3_EN(m) ((m)->base + 0x10) +#define MON3_CLEAR(m) ((m)->base + 0x14) +#define MON3_MASK(m) ((m)->base + 0x18) +#define MON3_MATCH(m) ((m)->base + 0x1C) +#define MON3_SW(m) ((m)->base + 0x20) +#define MON3_THRES_HI(m) ((m)->base + 0x24) +#define MON3_THRES_MED(m) ((m)->base + 0x28) +#define MON3_THRES_LO(m) ((m)->base + 0x2C) +#define MON3_ZONE_ACTIONS(m) ((m)->base + 0x30) +#define MON3_ZONE_CNT_THRES(m) ((m)->base + 0x34) +#define MON3_BYTE_CNT(m) ((m)->base + 0x38) +#define MON3_WIN_TIMER(m) ((m)->base + 0x3C) +#define MON3_ZONE_CNT(m) ((m)->base + 0x40) +#define MON3_ZONE_MAX(m, zone) ((m)->base + 0x44 + 0x4 * zone) + +enum mon_reg_type { + MON1, + MON2, + MON3, }; struct bwmon_spec { @@ -64,6 +92,8 @@ struct bwmon_spec { bool overflow; bool throt_adj; bool hw_sampling; + bool has_global_base; + enum mon_reg_type reg_type; }; struct bwmon { @@ -78,6 +108,10 @@ struct bwmon { u32 throttle_adj; u32 sample_size_ms; u32 intr_status; + u8 count_shift; + u32 thres_lim; + u32 byte_mask; + u32 byte_match; }; #define to_bwmon(ptr) container_of(ptr, struct bwmon, hw) @@ -85,33 +119,36 @@ struct bwmon { #define ENABLE_MASK BIT(0) #define THROTTLE_MASK 0x1F #define THROTTLE_SHIFT 16 -#define INT_ENABLE_V1 0x1 -#define INT_STATUS_MASK 0x03 -#define INT_STATUS_MASK_HWS 0xF0 static DEFINE_SPINLOCK(glb_lock); -static __always_inline void mon_enable(struct bwmon *m, enum bwmon_type type) +static __always_inline void mon_enable(struct bwmon *m, enum mon_reg_type type) { switch (type) { - case BWMON_1: + case MON1: writel_relaxed(ENABLE_MASK | m->throttle_adj, MON_EN(m)); break; - case BWMON_2: + case MON2: writel_relaxed(ENABLE_MASK | m->throttle_adj, MON2_EN(m)); break; + case MON3: + writel_relaxed(ENABLE_MASK | m->throttle_adj, MON3_EN(m)); + break; } } -static __always_inline void mon_disable(struct bwmon *m, enum bwmon_type type) +static __always_inline void mon_disable(struct bwmon *m, enum mon_reg_type type) { switch (type) { - case BWMON_1: + case MON1: writel_relaxed(m->throttle_adj, MON_EN(m)); break; - case BWMON_2: + case MON2: writel_relaxed(m->throttle_adj, MON2_EN(m)); break; + case MON3: + writel_relaxed(m->throttle_adj, MON3_EN(m)); + break; } /* * mon_disable() and mon_irq_clear(), @@ -124,18 +161,24 @@ static __always_inline void mon_disable(struct bwmon *m, enum bwmon_type type) #define MON_CLEAR_BIT 0x1 #define MON_CLEAR_ALL_BIT 0x2 static __always_inline -void mon_clear(struct bwmon *m, bool clear_all, enum bwmon_type type) +void mon_clear(struct bwmon *m, bool clear_all, enum mon_reg_type type) { switch (type) { - case BWMON_1: + case MON1: writel_relaxed(MON_CLEAR_BIT, MON_CLEAR(m)); break; - case BWMON_2: + case MON2: if (clear_all) writel_relaxed(MON_CLEAR_ALL_BIT, MON2_CLEAR(m)); else writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m)); break; + case MON3: + if (clear_all) + writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m)); + else + writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m)); + break; } /* * The counter clear and IRQ clear bits are not in the same 4KB @@ -146,7 +189,9 @@ void mon_clear(struct bwmon *m, bool clear_all, enum bwmon_type type) } #define SAMPLE_WIN_LIM 0xFFFFF -static void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms) +static __always_inline +void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms, + enum mon_reg_type type) { u32 rate; @@ -158,7 +203,17 @@ static void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms) pr_warn("Sample window %u larger than hw limit: %u\n", rate, SAMPLE_WIN_LIM); } - writel_relaxed(rate, MON2_SW(m)); + switch (type) { + case MON1: + WARN(1, "Invalid\n"); + return; + case MON2: + writel_relaxed(rate, MON2_SW(m)); + break; + case MON3: + writel_relaxed(rate, MON3_SW(m)); + break; + } } } @@ -172,24 +227,29 @@ static void mon_glb_irq_enable(struct bwmon *m) } static __always_inline -void mon_irq_enable(struct bwmon *m, enum bwmon_type type) +void mon_irq_enable(struct bwmon *m, enum mon_reg_type type) { u32 val; spin_lock(&glb_lock); switch (type) { - case BWMON_1: + case MON1: mon_glb_irq_enable(m); val = readl_relaxed(MON_INT_EN(m)); - val |= INT_ENABLE_V1; + val |= MON_INT_ENABLE; writel_relaxed(val, MON_INT_EN(m)); break; - case BWMON_2: + case MON2: mon_glb_irq_enable(m); val = readl_relaxed(MON_INT_EN(m)); - val |= INT_STATUS_MASK_HWS; + val |= MON2_INT_STATUS_MASK; writel_relaxed(val, MON_INT_EN(m)); break; + case MON3: + val = readl_relaxed(MON3_INT_EN(m)); + val |= MON3_INT_STATUS_MASK; + writel_relaxed(val, MON3_INT_EN(m)); + break; } spin_unlock(&glb_lock); /* @@ -209,25 +269,30 @@ static void mon_glb_irq_disable(struct bwmon *m) } static __always_inline -void mon_irq_disable(struct bwmon *m, enum bwmon_type type) +void mon_irq_disable(struct bwmon *m, enum mon_reg_type type) { u32 val; spin_lock(&glb_lock); switch (type) { - case BWMON_1: + case MON1: mon_glb_irq_disable(m); val = readl_relaxed(MON_INT_EN(m)); - val &= ~INT_ENABLE_V1; + val &= ~MON_INT_ENABLE; writel_relaxed(val, MON_INT_EN(m)); break; - case BWMON_2: + case MON2: mon_glb_irq_disable(m); val = readl_relaxed(MON_INT_EN(m)); - val &= ~INT_STATUS_MASK_HWS; + val &= ~MON2_INT_DISABLE_MASK; writel_relaxed(val, MON_INT_EN(m)); break; + case MON3: + val = readl_relaxed(MON3_INT_EN(m)); + val &= ~MON3_INT_DISABLE_MASK; + writel_relaxed(val, MON3_INT_EN(m)); + break; } spin_unlock(&glb_lock); /* @@ -238,22 +303,28 @@ void mon_irq_disable(struct bwmon *m, enum bwmon_type type) } static __always_inline -unsigned int mon_irq_status(struct bwmon *m, enum bwmon_type type) +unsigned int mon_irq_status(struct bwmon *m, enum mon_reg_type type) { u32 mval; switch (type) { - case BWMON_1: + case MON1: mval = readl_relaxed(MON_INT_STATUS(m)); dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval, readl_relaxed(GLB_INT_STATUS(m))); - mval &= INT_STATUS_MASK; + mval &= MON_INT_STATUS_MASK; break; - case BWMON_2: + case MON2: mval = readl_relaxed(MON_INT_STATUS(m)); dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval, readl_relaxed(GLB_INT_STATUS(m))); - mval &= INT_STATUS_MASK_HWS; + mval &= MON2_INT_STATUS_MASK; + mval >>= MON2_INT_STATUS_SHIFT; + break; + case MON3: + mval = readl_relaxed(MON3_INT_STATUS(m)); + dev_dbg(m->dev, "IRQ status p:%x\n", mval); + mval &= MON3_INT_STATUS_MASK; break; } @@ -283,17 +354,20 @@ static void mon_glb_irq_clear(struct bwmon *m) } static __always_inline -void mon_irq_clear(struct bwmon *m, enum bwmon_type type) +void mon_irq_clear(struct bwmon *m, enum mon_reg_type type) { switch (type) { - case BWMON_1: - writel_relaxed(INT_STATUS_MASK, MON_INT_CLR(m)); + case MON1: + writel_relaxed(MON_INT_STATUS_MASK, MON_INT_CLR(m)); mon_glb_irq_clear(m); break; - case BWMON_2: - writel_relaxed(INT_STATUS_MASK_HWS, MON_INT_CLR(m)); + case MON2: + writel_relaxed(MON2_INT_STATUS_MASK, MON_INT_CLR(m)); mon_glb_irq_clear(m); break; + case MON3: + writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m)); + break; } } @@ -350,11 +424,18 @@ static u32 calc_zone_counts(struct bw_hwmon *hw) return zone_counts; } -static unsigned int mbps_to_mb(unsigned long mbps, unsigned int ms) +#define MB_SHIFT 20 + +static u32 mbps_to_count(unsigned long mbps, unsigned int ms, u8 shift) { mbps *= ms; - mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC); - return mbps; + + if (shift > MB_SHIFT) + mbps >>= shift - MB_SHIFT; + else + mbps <<= MB_SHIFT - shift; + + return DIV_ROUND_UP(mbps, MSEC_PER_SEC); } /* @@ -362,43 +443,60 @@ static unsigned int mbps_to_mb(unsigned long mbps, unsigned int ms) * Zone 0: byte count < THRES_LO * Zone 1: THRES_LO < byte count < THRES_MED * Zone 2: THRES_MED < byte count < THRES_HI - * Zone 3: byte count > THRES_HI + * Zone 3: THRES_LIM > byte count > THRES_HI */ -#define THRES_LIM 0x7FFU -static void set_zone_thres(struct bwmon *m, unsigned int sample_ms) +#define THRES_LIM(shift) (0xFFFFFFFF >> shift) + +static __always_inline +void set_zone_thres(struct bwmon *m, unsigned int sample_ms, + enum mon_reg_type type) { - struct bw_hwmon *hw = &(m->hw); + struct bw_hwmon *hw = &m->hw; u32 hi, med, lo; + u32 zone_cnt_thres = calc_zone_counts(hw); - hi = mbps_to_mb(hw->up_wake_mbps, sample_ms); - med = mbps_to_mb(hw->down_wake_mbps, sample_ms); + hi = mbps_to_count(hw->up_wake_mbps, sample_ms, m->count_shift); + med = mbps_to_count(hw->down_wake_mbps, sample_ms, m->count_shift); lo = 0; - if (unlikely((hi > THRES_LIM) || (med > hi) || (lo > med))) { + if (unlikely((hi > m->thres_lim) || (med > hi) || (lo > med))) { pr_warn("Zone thres larger than hw limit: hi:%u med:%u lo:%u\n", hi, med, lo); - hi = min(hi, THRES_LIM); + hi = min(hi, m->thres_lim); med = min(med, hi - 1); lo = min(lo, med-1); } - writel_relaxed(hi, MON2_THRES_HI(m)); - writel_relaxed(med, MON2_THRES_MED(m)); - writel_relaxed(lo, MON2_THRES_LO(m)); + switch (type) { + case MON1: + WARN(1, "Invalid\n"); + return; + case MON2: + writel_relaxed(hi, MON2_THRES_HI(m)); + writel_relaxed(med, MON2_THRES_MED(m)); + writel_relaxed(lo, MON2_THRES_LO(m)); + /* Set the zone count thresholds for interrupts */ + writel_relaxed(zone_cnt_thres, MON2_ZONE_CNT_THRES(m)); + break; + case MON3: + writel_relaxed(hi, MON3_THRES_HI(m)); + writel_relaxed(med, MON3_THRES_MED(m)); + writel_relaxed(lo, MON3_THRES_LO(m)); + /* Set the zone count thresholds for interrupts */ + writel_relaxed(zone_cnt_thres, MON3_ZONE_CNT_THRES(m)); + break; + } + dev_dbg(m->dev, "Thres: hi:%u med:%u lo:%u\n", hi, med, lo); + dev_dbg(m->dev, "Zone Count Thres: %0x\n", zone_cnt_thres); } -static void mon_set_zones(struct bwmon *m, unsigned int sample_ms) +static __always_inline +void mon_set_zones(struct bwmon *m, unsigned int sample_ms, + enum mon_reg_type type) { - struct bw_hwmon *hw = &(m->hw); - u32 zone_cnt_thres = calc_zone_counts(hw); - - mon_set_hw_sampling_window(m, sample_ms); - set_zone_thres(m, sample_ms); - /* Set the zone count thresholds for interrupts */ - writel_relaxed(zone_cnt_thres, MON2_ZONE_CNT_THRES(m)); - - dev_dbg(m->dev, "Zone Count Thres: %0x\n", zone_cnt_thres); + mon_set_hw_sampling_window(m, sample_ms, type); + set_zone_thres(m, sample_ms, type); } static void mon_set_limit(struct bwmon *m, u32 count) @@ -419,7 +517,7 @@ static unsigned long mon_get_count1(struct bwmon *m) unsigned long count, status; count = readl_relaxed(MON_CNT(m)); - status = mon_irq_status(m, BWMON_1); + status = mon_irq_status(m, MON1); dev_dbg(m->dev, "Counter: %08lx\n", count); @@ -433,16 +531,28 @@ static unsigned long mon_get_count1(struct bwmon *m) return count; } -static unsigned int get_zone(struct bwmon *m) +static __always_inline +unsigned int get_zone(struct bwmon *m, enum mon_reg_type type) { u32 zone_counts; u32 zone; - zone = get_bitmask_order((m->intr_status & INT_STATUS_MASK_HWS) >> 4); + zone = get_bitmask_order(m->intr_status); if (zone) { zone--; } else { - zone_counts = readl_relaxed(MON2_ZONE_CNT(m)); + switch (type) { + case MON1: + WARN(1, "Invalid\n"); + return 0; + case MON2: + zone_counts = readl_relaxed(MON2_ZONE_CNT(m)); + break; + case MON3: + zone_counts = readl_relaxed(MON3_ZONE_CNT(m)); + break; + } + if (zone_counts) { zone = get_bitmask_order(zone_counts) - 1; zone /= 8; @@ -453,15 +563,38 @@ static unsigned int get_zone(struct bwmon *m) return zone; } -static unsigned long mon_get_zone_stats(struct bwmon *m) +static __always_inline +unsigned long get_zone_count(struct bwmon *m, unsigned int zone, + enum mon_reg_type type) +{ + unsigned long count; + + switch (type) { + case MON1: + WARN(1, "Invalid\n"); + return 0; + case MON2: + count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1; + break; + case MON3: + count = readl_relaxed(MON3_ZONE_MAX(m, zone)); + if (count) + count++; + break; + } + + return count; +} + +static __always_inline +unsigned long mon_get_zone_stats(struct bwmon *m, enum mon_reg_type type) { unsigned int zone; unsigned long count = 0; - zone = get_zone(m); - - count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1; - count *= SZ_1M; + zone = get_zone(m, type); + count = get_zone_count(m, zone, type); + count <<= m->count_shift; dev_dbg(m->dev, "Zone%d Max byte count: %08lx\n", zone, count); @@ -469,16 +602,17 @@ static unsigned long mon_get_zone_stats(struct bwmon *m) } static __always_inline -unsigned long mon_get_count(struct bwmon *m, enum bwmon_type type) +unsigned long mon_get_count(struct bwmon *m, enum mon_reg_type type) { unsigned long count; switch (type) { - case BWMON_1: + case MON1: count = mon_get_count1(m); break; - case BWMON_2: - count = mon_get_zone_stats(m); + case MON2: + case MON3: + count = mon_get_zone_stats(m, type); break; } @@ -499,7 +633,7 @@ static unsigned int mbps_to_bytes(unsigned long mbps, unsigned int ms, } static __always_inline -unsigned long __get_bytes_and_clear(struct bw_hwmon *hw, enum bwmon_type type) +unsigned long __get_bytes_and_clear(struct bw_hwmon *hw, enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); unsigned long count; @@ -515,12 +649,17 @@ unsigned long __get_bytes_and_clear(struct bw_hwmon *hw, enum bwmon_type type) static unsigned long get_bytes_and_clear(struct bw_hwmon *hw) { - return __get_bytes_and_clear(hw, BWMON_1); + return __get_bytes_and_clear(hw, MON1); } static unsigned long get_bytes_and_clear2(struct bw_hwmon *hw) { - return __get_bytes_and_clear(hw, BWMON_2); + return __get_bytes_and_clear(hw, MON2); +} + +static unsigned long get_bytes_and_clear3(struct bw_hwmon *hw) +{ + return __get_bytes_and_clear(hw, MON3); } static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes) @@ -529,10 +668,10 @@ static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes) u32 limit; struct bwmon *m = to_bwmon(hw); - mon_disable(m, BWMON_1); + mon_disable(m, MON1); count = mon_get_count1(m); - mon_clear(m, false, BWMON_1); - mon_irq_clear(m, BWMON_1); + mon_clear(m, false, MON1); + mon_irq_clear(m, MON1); if (likely(!m->spec->wrap_on_thres)) limit = bytes; @@ -540,27 +679,40 @@ static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes) limit = max(bytes, 500000UL); mon_set_limit(m, limit); - mon_enable(m, BWMON_1); + mon_enable(m, MON1); return count; } -static unsigned long set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms) +static unsigned long +__set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms, + enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); - mon_disable(m, BWMON_2); - mon_clear(m, false, BWMON_2); - mon_irq_clear(m, BWMON_2); + mon_disable(m, type); + mon_clear(m, false, type); + mon_irq_clear(m, type); - mon_set_zones(m, sample_ms); - mon_enable(m, BWMON_2); + mon_set_zones(m, sample_ms, type); + mon_enable(m, type); return 0; } +static unsigned long set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms) +{ + return __set_hw_events(hw, sample_ms, MON2); +} + +static unsigned long +set_hw_events3(struct bw_hwmon *hw, unsigned int sample_ms) +{ + return __set_hw_events(hw, sample_ms, MON3); +} + static irqreturn_t -__bwmon_intr_handler(int irq, void *dev, enum bwmon_type type) +__bwmon_intr_handler(int irq, void *dev, enum mon_reg_type type) { struct bwmon *m = dev; @@ -576,12 +728,17 @@ __bwmon_intr_handler(int irq, void *dev, enum bwmon_type type) static irqreturn_t bwmon_intr_handler(int irq, void *dev) { - return __bwmon_intr_handler(irq, dev, BWMON_1); + return __bwmon_intr_handler(irq, dev, MON1); } static irqreturn_t bwmon_intr_handler2(int irq, void *dev) { - return __bwmon_intr_handler(irq, dev, BWMON_2); + return __bwmon_intr_handler(irq, dev, MON2); +} + +static irqreturn_t bwmon_intr_handler3(int irq, void *dev) +{ + return __bwmon_intr_handler(irq, dev, MON3); } static irqreturn_t bwmon_intr_thread(int irq, void *dev) @@ -592,8 +749,27 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev) return IRQ_HANDLED; } -static __always_inline int -__start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum bwmon_type type) +static __always_inline +void mon_set_byte_count_filter(struct bwmon *m, enum mon_reg_type type) +{ + if (!m->byte_mask) + return; + + switch (type) { + case MON1: + case MON2: + writel_relaxed(m->byte_mask, MON_MASK(m)); + writel_relaxed(m->byte_match, MON_MATCH(m)); + break; + case MON3: + writel_relaxed(m->byte_mask, MON3_MASK(m)); + writel_relaxed(m->byte_match, MON3_MATCH(m)); + break; + } +} + +static __always_inline int __start_bw_hwmon(struct bw_hwmon *hw, + unsigned long mbps, enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); u32 limit, zone_actions; @@ -601,14 +777,18 @@ __start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum bwmon_type type) irq_handler_t handler; switch (type) { - case BWMON_1: + case MON1: handler = bwmon_intr_handler; limit = mbps_to_bytes(mbps, hw->df->profile->polling_ms, 0); break; - case BWMON_2: + case MON2: zone_actions = calc_zone_actions(); handler = bwmon_intr_handler2; break; + case MON3: + zone_actions = calc_zone_actions(); + handler = bwmon_intr_handler3; + break; } ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread, @@ -625,17 +805,22 @@ __start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum bwmon_type type) mon_clear(m, false, type); switch (type) { - case BWMON_1: + case MON1: handler = bwmon_intr_handler; mon_set_limit(m, limit); break; - case BWMON_2: - mon_set_zones(m, hw->df->profile->polling_ms); + case MON2: + mon_set_zones(m, hw->df->profile->polling_ms, type); /* Set the zone actions to increment appropriate counters */ writel_relaxed(zone_actions, MON2_ZONE_ACTIONS(m)); break; + case MON3: + mon_set_zones(m, hw->df->profile->polling_ms, type); + /* Set the zone actions to increment appropriate counters */ + writel_relaxed(zone_actions, MON3_ZONE_ACTIONS(m)); } + mon_set_byte_count_filter(m, type); mon_irq_clear(m, type); mon_irq_enable(m, type); mon_enable(m, type); @@ -645,16 +830,21 @@ __start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum bwmon_type type) static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps) { - return __start_bw_hwmon(hw, mbps, BWMON_1); + return __start_bw_hwmon(hw, mbps, MON1); } static int start_bw_hwmon2(struct bw_hwmon *hw, unsigned long mbps) { - return __start_bw_hwmon(hw, mbps, BWMON_2); + return __start_bw_hwmon(hw, mbps, MON2); +} + +static int start_bw_hwmon3(struct bw_hwmon *hw, unsigned long mbps) +{ + return __start_bw_hwmon(hw, mbps, MON3); } static __always_inline -void __stop_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type) +void __stop_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); @@ -667,16 +857,21 @@ void __stop_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type) static void stop_bw_hwmon(struct bw_hwmon *hw) { - return __stop_bw_hwmon(hw, BWMON_1); + return __stop_bw_hwmon(hw, MON1); } static void stop_bw_hwmon2(struct bw_hwmon *hw) { - return __stop_bw_hwmon(hw, BWMON_2); + return __stop_bw_hwmon(hw, MON2); +} + +static void stop_bw_hwmon3(struct bw_hwmon *hw) +{ + return __stop_bw_hwmon(hw, MON3); } static __always_inline -int __suspend_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type) +int __suspend_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); @@ -690,27 +885,36 @@ int __suspend_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type) static int suspend_bw_hwmon(struct bw_hwmon *hw) { - return __suspend_bw_hwmon(hw, BWMON_1); + return __suspend_bw_hwmon(hw, MON1); } static int suspend_bw_hwmon2(struct bw_hwmon *hw) { - return __suspend_bw_hwmon(hw, BWMON_2); + return __suspend_bw_hwmon(hw, MON2); +} + +static int suspend_bw_hwmon3(struct bw_hwmon *hw) +{ + return __suspend_bw_hwmon(hw, MON3); } -static int __resume_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type) +static __always_inline +int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); int ret; irq_handler_t handler; switch (type) { - case BWMON_1: + case MON1: handler = bwmon_intr_handler; break; - case BWMON_2: + case MON2: handler = bwmon_intr_handler2; break; + case MON3: + handler = bwmon_intr_handler3; + break; } mon_clear(m, false, type); @@ -731,12 +935,17 @@ static int __resume_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type) static int resume_bw_hwmon(struct bw_hwmon *hw) { - return __resume_bw_hwmon(hw, BWMON_1); + return __resume_bw_hwmon(hw, MON1); } static int resume_bw_hwmon2(struct bw_hwmon *hw) { - return __resume_bw_hwmon(hw, BWMON_2); + return __resume_bw_hwmon(hw, MON2); +} + +static int resume_bw_hwmon3(struct bw_hwmon *hw) +{ + return __resume_bw_hwmon(hw, MON3); } /*************************************************************************/ @@ -746,25 +955,40 @@ static const struct bwmon_spec spec[] = { .wrap_on_thres = true, .overflow = false, .throt_adj = false, - .hw_sampling = false + .hw_sampling = false, + .has_global_base = true, + .reg_type = MON1, }, [1] = { .wrap_on_thres = false, .overflow = true, .throt_adj = false, - .hw_sampling = false + .hw_sampling = false, + .has_global_base = true, + .reg_type = MON1, }, [2] = { .wrap_on_thres = false, .overflow = true, .throt_adj = true, - .hw_sampling = false + .hw_sampling = false, + .has_global_base = true, + .reg_type = MON1, }, [3] = { .wrap_on_thres = false, .overflow = true, .throt_adj = true, - .hw_sampling = true + .hw_sampling = true, + .has_global_base = true, + .reg_type = MON2, + }, + [4] = { + .wrap_on_thres = false, + .overflow = true, + .throt_adj = false, + .hw_sampling = true, + .reg_type = MON3, }, }; @@ -773,6 +997,7 @@ static const struct of_device_id bimc_bwmon_match_table[] = { { .compatible = "qcom,bimc-bwmon2", .data = &spec[1] }, { .compatible = "qcom,bimc-bwmon3", .data = &spec[2] }, { .compatible = "qcom,bimc-bwmon4", .data = &spec[3] }, + { .compatible = "qcom,bimc-bwmon5", .data = &spec[4] }, {} }; @@ -782,20 +1007,13 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) struct resource *res; struct bwmon *m; int ret; - u32 data; + u32 data, count_unit; m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL); if (!m) return -ENOMEM; m->dev = dev; - ret = of_property_read_u32(dev->of_node, "qcom,mport", &data); - if (ret) { - dev_err(dev, "mport not found!\n"); - return ret; - } - m->mport = data; - m->spec = of_device_get_match_data(dev); if (!m->spec) { dev_err(dev, "Unknown device type!\n"); @@ -813,15 +1031,26 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) return -ENOMEM; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "global_base"); - if (!res) { - dev_err(dev, "global_base not found!\n"); - return -EINVAL; - } - m->global_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!m->global_base) { - dev_err(dev, "Unable map global_base!\n"); - return -ENOMEM; + if (m->spec->has_global_base) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "global_base"); + if (!res) { + dev_err(dev, "global_base not found!\n"); + return -EINVAL; + } + m->global_base = devm_ioremap(dev, res->start, + resource_size(res)); + if (!m->global_base) { + dev_err(dev, "Unable map global_base!\n"); + return -ENOMEM; + } + + ret = of_property_read_u32(dev->of_node, "qcom,mport", &data); + if (ret) { + dev_err(dev, "mport not found!\n"); + return ret; + } + m->mport = data; } m->irq = platform_get_irq(pdev, 0); @@ -841,22 +1070,45 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev) dev_err(dev, "HW sampling rate not specified!\n"); return ret; } + } + if (of_property_read_u32(dev->of_node, "qcom,count-unit", &count_unit)) + count_unit = SZ_1M; + m->count_shift = order_base_2(count_unit); + m->thres_lim = THRES_LIM(m->count_shift); + + switch (m->spec->reg_type) { + case MON3: + m->hw.start_hwmon = start_bw_hwmon3; + m->hw.stop_hwmon = stop_bw_hwmon3; + m->hw.suspend_hwmon = suspend_bw_hwmon3; + m->hw.resume_hwmon = resume_bw_hwmon3; + m->hw.get_bytes_and_clear = get_bytes_and_clear3; + m->hw.set_hw_events = set_hw_events3; + break; + case MON2: m->hw.start_hwmon = start_bw_hwmon2; m->hw.stop_hwmon = stop_bw_hwmon2; m->hw.suspend_hwmon = suspend_bw_hwmon2; m->hw.resume_hwmon = resume_bw_hwmon2; m->hw.get_bytes_and_clear = get_bytes_and_clear2; m->hw.set_hw_events = set_hw_events; - } else { + break; + case MON1: m->hw.start_hwmon = start_bw_hwmon; m->hw.stop_hwmon = stop_bw_hwmon; m->hw.suspend_hwmon = suspend_bw_hwmon; m->hw.resume_hwmon = resume_bw_hwmon; m->hw.get_bytes_and_clear = get_bytes_and_clear; m->hw.set_thres = set_thres; + break; } + of_property_read_u32(dev->of_node, "qcom,byte-mid-match", + &m->byte_match); + of_property_read_u32(dev->of_node, "qcom,byte-mid-mask", + &m->byte_mask); + if (m->spec->throt_adj) { m->hw.set_throttle_adj = mon_set_throttle_adj; m->hw.get_throttle_adj = mon_get_throttle_adj; diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 8f582f621a096f4d6588c44d4d3b7782250405e2..b2636967ddddf501b7bd320a46955dac3997f1f1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -598,7 +598,7 @@ struct devfreq *devfreq_add_device(struct device *dev, err = device_register(&devfreq->dev); if (err) { mutex_unlock(&devfreq->lock); - goto err_out; + goto err_dev; } devfreq->trans_table = devm_kzalloc(&devfreq->dev, sizeof(unsigned int) * @@ -642,6 +642,9 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_unlock(&devfreq_list_lock); device_unregister(&devfreq->dev); +err_dev: + if (devfreq) + kfree(devfreq); err_out: return ERR_PTR(err); } diff --git a/drivers/devfreq/devfreq_simple_dev.c b/drivers/devfreq/devfreq_simple_dev.c index 9c99fcf43ff848db7a0398cc513fb057cddf01f2..b0757b647f5b5dbe0f3d1605f05b695e78245423 100644 --- a/drivers/devfreq/devfreq_simple_dev.c +++ b/drivers/devfreq/devfreq_simple_dev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, 2017, 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 @@ -34,6 +34,7 @@ struct dev_data { struct clk *clk; struct devfreq *df; struct devfreq_dev_profile profile; + bool freq_in_khz; }; static void find_freq(struct devfreq_dev_profile *p, unsigned long *freq, @@ -65,7 +66,7 @@ static int dev_target(struct device *dev, unsigned long *freq, u32 flags) find_freq(&d->profile, freq, flags); - rfreq = clk_round_rate(d->clk, *freq * 1000); + rfreq = clk_round_rate(d->clk, d->freq_in_khz ? *freq * 1000 : *freq); if (IS_ERR_VALUE(rfreq)) { dev_err(dev, "devfreq: Cannot find matching frequency for %lu\n", *freq); @@ -83,39 +84,30 @@ static int dev_get_cur_freq(struct device *dev, unsigned long *freq) f = clk_get_rate(d->clk); if (IS_ERR_VALUE(f)) return f; - *freq = f / 1000; + *freq = d->freq_in_khz ? f / 1000 : f; return 0; } #define PROP_TBL "freq-tbl-khz" -static int devfreq_clock_probe(struct platform_device *pdev) +static int parse_freq_table(struct device *dev, struct dev_data *d) { - struct device *dev = &pdev->dev; - struct dev_data *d; - struct devfreq_dev_profile *p; - u32 *data, poll; - const char *gov_name; + struct devfreq_dev_profile *p = &d->profile; int ret, len, i, j; + u32 *data; unsigned long f; - d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; - platform_set_drvdata(pdev, d); - - d->clk = devm_clk_get(dev, "devfreq_clk"); - if (IS_ERR(d->clk)) - return PTR_ERR(d->clk); - - if (!of_find_property(dev->of_node, PROP_TBL, &len)) - return -EINVAL; + if (!of_find_property(dev->of_node, PROP_TBL, &len)) { + if (dev_pm_opp_get_opp_count(dev) <= 0) + return -EPROBE_DEFER; + return 0; + } + d->freq_in_khz = true; len /= sizeof(*data); data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - p = &d->profile; p->freq_table = devm_kzalloc(dev, len * sizeof(*p->freq_table), GFP_KERNEL); if (!p->freq_table) @@ -142,6 +134,32 @@ static int devfreq_clock_probe(struct platform_device *pdev) return -EINVAL; } + return 0; +} + +static int devfreq_clock_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dev_data *d; + struct devfreq_dev_profile *p; + u32 poll; + const char *gov_name; + int ret; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + platform_set_drvdata(pdev, d); + + d->clk = devm_clk_get(dev, "devfreq_clk"); + if (IS_ERR(d->clk)) + return PTR_ERR(d->clk); + + ret = parse_freq_table(dev, d); + if (ret) + return ret; + + p = &d->profile; p->target = dev_target; p->get_cur_freq = dev_get_cur_freq; ret = dev_get_cur_freq(dev, &p->initial_freq); diff --git a/drivers/devfreq/devfreq_spdm.c b/drivers/devfreq/devfreq_spdm.c new file mode 100644 index 0000000000000000000000000000000000000000..3290a2a9929fec73244eab3e37f3ee0658b0c30f --- /dev/null +++ b/drivers/devfreq/devfreq_spdm.c @@ -0,0 +1,444 @@ +/* + *Copyright (c) 2014-2015, 2017, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "governor.h" +#include "devfreq_spdm.h" + +static void *spdm_ipc_log_ctxt; +#define DEVFREQ_SPDM_DEFAULT_WINDOW_MS 100 +#define SPDM_IPC_LOG_PAGES 5 + +#define SPDM_IPC_LOG(x...) do { \ + pr_debug(x); \ + if (spdm_ipc_log_ctxt) \ + ipc_log_string(spdm_ipc_log_ctxt, x); \ +} while (0) + +#define COPY_SIZE(x, y) ((x) <= (y) ? (x) : (y)) + +static int change_bw(struct device *dev, unsigned long *freq, u32 flags) +{ + struct spdm_data *data = 0; + int i; + int next_idx; + int ret = 0; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (!dev || !freq) + return -EINVAL; + + data = dev_get_drvdata(dev); + if (!data) + return -EINVAL; + + if (data->devfreq->previous_freq == *freq) + goto update_thresholds; + + next_idx = data->cur_idx + 1; + next_idx = next_idx % 2; + + for (i = 0; i < data->pdata->usecase[next_idx].num_paths; i++) + data->pdata->usecase[next_idx].vectors[i].ab = (*freq) << 6; + + data->cur_idx = next_idx; + ret = msm_bus_scale_client_update_request(data->bus_scale_client_id, + data->cur_idx); + +update_thresholds: + desc.arg[0] = SPDM_CMD_ENABLE; + desc.arg[1] = data->spdm_client; + desc.arg[2] = (clk_get_rate(data->cci_clk)) / 1000; + ext_status = spdm_ext_call(&desc, 3); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + return ret; +} + +static int get_cur_bw(struct device *dev, unsigned long *freq) +{ + struct spdm_data *data = 0; + + if (!dev || !freq) + return -EINVAL; + + data = dev_get_drvdata(dev); + if (!data) + return -EINVAL; + + *freq = data->pdata->usecase[data->cur_idx].vectors[0].ab >> 6; + + return 0; +} + +static int get_dev_status(struct device *dev, struct devfreq_dev_status *status) +{ + struct spdm_data *data = 0; + int ret; + + if (!dev || !status) + return -EINVAL; + + data = dev_get_drvdata(dev); + if (!data) + return -EINVAL; + + /* + * determine if we want to go up or down based on the notification. + */ + if (data->action == SPDM_UP) + status->busy_time = 255; + else + status->busy_time = 0; + status->total_time = 255; + ret = get_cur_bw(dev, &status->current_frequency); + if (ret) + return ret; + + return 0; + +} + +static int populate_config_data(struct spdm_data *data, + struct platform_device *pdev) +{ + int ret = -EINVAL; + struct device_node *node = pdev->dev.of_node; + struct property *prop = 0; + + ret = of_property_read_u32(node, "qcom,max-vote", + &data->config_data.max_vote); + if (ret) + return ret; + + ret = of_property_read_u32(node, "qcom,bw-upstep", + &data->config_data.upstep); + if (ret) + return ret; + + ret = of_property_read_u32(node, "qcom,bw-dwnstep", + &data->config_data.downstep); + if (ret) + return ret; + + ret = of_property_read_u32(node, "qcom,alpha-up", + &data->config_data.aup); + if (ret) + return ret; + + ret = of_property_read_u32(node, "qcom,alpha-down", + &data->config_data.adown); + if (ret) + return ret; + + ret = of_property_read_u32(node, "qcom,bucket-size", + &data->config_data.bucket_size); + if (ret) + return ret; + + ret = of_property_read_u32_array(node, "qcom,pl-freqs", + data->config_data.pl_freqs, + SPDM_PL_COUNT - 1); + if (ret) + return ret; + + ret = of_property_read_u32_array(node, "qcom,reject-rate", + data->config_data.reject_rate, + SPDM_PL_COUNT * 2); + if (ret) + return ret; + + ret = of_property_read_u32_array(node, "qcom,response-time-us", + data->config_data.response_time_us, + SPDM_PL_COUNT * 2); + if (ret) + return ret; + + ret = of_property_read_u32_array(node, "qcom,cci-response-time-us", + data->config_data.cci_response_time_us, + SPDM_PL_COUNT * 2); + if (ret) + return ret; + + ret = of_property_read_u32(node, "qcom,max-cci-freq", + &data->config_data.max_cci_freq); + if (ret) + return ret; + ret = of_property_read_u32(node, "qcom,up-step-multp", + &data->config_data.up_step_multp); + if (ret) + return ret; + + prop = of_find_property(node, "qcom,ports", 0); + if (!prop) + return -EINVAL; + data->config_data.num_ports = prop->length / sizeof(u32); + data->config_data.ports = + devm_kzalloc(&pdev->dev, prop->length, GFP_KERNEL); + if (!data->config_data.ports) + return -ENOMEM; + ret = of_property_read_u32_array(node, "qcom,ports", + data->config_data.ports, + data->config_data.num_ports); + if (ret) { + devm_kfree(&pdev->dev, data->config_data.ports); + data->config_data.ports = NULL; + return ret; + } + + return 0; +} + +static int populate_spdm_data(struct spdm_data *data, + struct platform_device *pdev) +{ + int ret = -EINVAL; + struct device_node *node = pdev->dev.of_node; + + ret = populate_config_data(data, pdev); + if (ret) + return ret; + + ret = + of_property_read_u32(node, "qcom,spdm-client", &data->spdm_client); + if (ret) + goto no_client; + + ret = of_property_read_u32(node, "qcom,spdm-interval", &data->window); + if (ret) + data->window = DEVFREQ_SPDM_DEFAULT_WINDOW_MS; + + data->pdata = msm_bus_cl_get_pdata(pdev); + if (!data->pdata) { + ret = -EINVAL; + goto no_pdata; + } + + return 0; + +no_client: +no_pdata: + devm_kfree(&pdev->dev, data->config_data.ports); + data->config_data.ports = NULL; + return ret; +} + +#ifdef CONFIG_MSM_HVC +int __spdm_hyp_call(struct spdm_args *args, int num_args) +{ + struct hvc_desc desc = { { 0 } }; + int status; + + memcpy(desc.arg, args->arg, + COPY_SIZE(sizeof(desc.arg), sizeof(args->arg))); + SPDM_IPC_LOG("hvc call fn:0x%x, cmd:%llu, num_args:%d\n", + HVC_FN_SIP(SPDM_HYP_FNID), desc.arg[0], num_args); + + status = hvc(HVC_FN_SIP(SPDM_HYP_FNID), &desc); + + memcpy(args->ret, desc.ret, + COPY_SIZE(sizeof(args->ret), sizeof(desc.ret))); + SPDM_IPC_LOG("hvc return fn:0x%x cmd:%llu Ret[0]:%llu Ret[1]:%llu\n", + HVC_FN_SIP(SPDM_HYP_FNID), desc.arg[0], + desc.ret[0], desc.ret[1]); + return status; +} +#endif + +int __spdm_scm_call(struct spdm_args *args, int num_args) +{ + int status = 0; + + SPDM_IPC_LOG("%s:svc_id:%d,cmd_id:%d,cmd:%llu,num_args:%d\n", + __func__, SPDM_SCM_SVC_ID, SPDM_SCM_CMD_ID, + args->arg[0], num_args); + + if (!is_scm_armv8()) { + status = scm_call(SPDM_SCM_SVC_ID, SPDM_SCM_CMD_ID, args->arg, + sizeof(args->arg), args->ret, + sizeof(args->ret)); + } else { + struct scm_desc desc = {0}; + /* + * Need to hard code this, this is a requirement from TZ syscall + * interface. + */ + desc.arginfo = SCM_ARGS(6); + memcpy(desc.args, args->arg, + COPY_SIZE(sizeof(desc.args), sizeof(args->arg))); + + status = scm_call2(SCM_SIP_FNID(SPDM_SCM_SVC_ID, + SPDM_SCM_CMD_ID), &desc); + + memcpy(args->ret, desc.ret, + COPY_SIZE(sizeof(args->ret), sizeof(desc.ret))); + } + SPDM_IPC_LOG("%s:svc_id:%d,cmd_id:%d,cmd:%llu,Ret[0]:%llu,Ret[1]:%llu\n" + , __func__, SPDM_SCM_SVC_ID, SPDM_SCM_CMD_ID, args->arg[0], + args->ret[0], args->ret[1]); + return status; +} + +static int probe(struct platform_device *pdev) +{ + struct spdm_data *data = 0; + int ret = -EINVAL; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->action = SPDM_DOWN; + + platform_set_drvdata(pdev, data); + + ret = populate_spdm_data(data, pdev); + if (ret) + goto bad_of; + + desc.arg[0] = SPDM_CMD_GET_VERSION; + ext_status = spdm_ext_call(&desc, 1); + if (ext_status) { + pr_err("%s:External command %u failed with error %u\n", + __func__, (int)desc.arg[0], ext_status); + goto bad_of; + } + + if (desc.ret[0] < SPDM_TZ_VERSION) { + pr_err("%s: Version mismatch expected 0x%x got 0x%x", __func__, + SPDM_TZ_VERSION, (int)desc.arg[0]); + goto bad_of; + } + + data->bus_scale_client_id = msm_bus_scale_register_client(data->pdata); + if (!data->bus_scale_client_id) { + ret = -EINVAL; + goto no_bus_scaling; + } + + data->cci_clk = clk_get(&pdev->dev, "cci_clk"); + if (IS_ERR(data->cci_clk)) { + ret = PTR_ERR(data->cci_clk); + goto no_clock; + } + + data->profile = + devm_kzalloc(&pdev->dev, sizeof(*(data->profile)), GFP_KERNEL); + if (!data->profile) { + ret = -ENOMEM; + goto no_profile; + } + data->profile->target = change_bw; + data->profile->get_dev_status = get_dev_status; + data->profile->get_cur_freq = get_cur_bw; + data->profile->polling_ms = data->window; + + data->devfreq = + devfreq_add_device(&pdev->dev, data->profile, "spdm_bw_hyp", data); + if (IS_ERR(data->devfreq)) { + ret = PTR_ERR(data->devfreq); + goto no_spdm_device; + } + + spdm_init_debugfs(&pdev->dev); + spdm_ipc_log_ctxt = ipc_log_context_create(SPDM_IPC_LOG_PAGES, + "devfreq_spdm", 0); + + if (IS_ERR_OR_NULL(spdm_ipc_log_ctxt)) { + pr_err("%s: Failed to create IPC log context\n", __func__); + spdm_ipc_log_ctxt = NULL; + } + + + return 0; + +no_spdm_device: + devm_kfree(&pdev->dev, data->profile); +no_profile: +no_clock: + msm_bus_scale_unregister_client(data->bus_scale_client_id); +no_bus_scaling: + devm_kfree(&pdev->dev, data->config_data.ports); +bad_of: + devm_kfree(&pdev->dev, data); + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int remove(struct platform_device *pdev) +{ + struct spdm_data *data = 0; + + data = platform_get_drvdata(pdev); + + spdm_remove_debugfs(data); + + if (data->devfreq) + devfreq_remove_device(data->devfreq); + + if (data->profile) + devm_kfree(&pdev->dev, data->profile); + + if (data->bus_scale_client_id) + msm_bus_scale_unregister_client(data->bus_scale_client_id); + + if (data->config_data.ports) + devm_kfree(&pdev->dev, data->config_data.ports); + + devm_kfree(&pdev->dev, data); + platform_set_drvdata(pdev, NULL); + + if (spdm_ipc_log_ctxt) + ipc_log_context_destroy(spdm_ipc_log_ctxt); + + return 0; +} + +static const struct of_device_id devfreq_spdm_match[] = { + {.compatible = "qcom,devfreq_spdm"}, + {} +}; + +static struct platform_driver devfreq_spdm_drvr = { + .driver = { + .name = "devfreq_spdm", + .owner = THIS_MODULE, + .of_match_table = devfreq_spdm_match, + }, + .probe = probe, + .remove = remove, +}; + +static int __init devfreq_spdm_init(void) +{ + return platform_driver_register(&devfreq_spdm_drvr); +} + +module_init(devfreq_spdm_init); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/devfreq/devfreq_spdm.h b/drivers/devfreq/devfreq_spdm.h new file mode 100644 index 0000000000000000000000000000000000000000..1e5ab0359be69444d5b4c59a897d255a2cd0f925 --- /dev/null +++ b/drivers/devfreq/devfreq_spdm.h @@ -0,0 +1,131 @@ +/* + *Copyright (c) 2014-2015, 2017, 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 DEVFREQ_SPDM_H +#define DEVFREQ_SPDM_H + +#include +#ifdef CONFIG_MSM_HVC +#include +#endif +#include + +enum pl_levels { SPDM_PL1, SPDM_PL2, SPDM_PL3, SPDM_PL_COUNT }; +enum actions { SPDM_UP, SPDM_DOWN }; +enum spdm_client { SPDM_CLIENT_CPU, SPDM_CLIENT_GPU, SPDM_CLIENT_COUNT }; + +struct spdm_config_data { + /* in MB/s */ + u32 upstep; + u32 downstep; + u32 up_step_multp; + + u32 num_ports; + u32 *ports; + u32 aup; + u32 adown; + u32 bucket_size; + + /* + * If We define n PL levels we need n-1 frequencies to tell + * where to change from one pl to another + */ + /* hz */ + u32 pl_freqs[SPDM_PL_COUNT - 1]; + /* + * We have a low threshold and a high threhold for each pl to support + * the two port solution so we need twice as many entries as + * performance levels + */ + /* in 100th's of a percent */ + u32 reject_rate[SPDM_PL_COUNT * 2]; + u32 response_time_us[SPDM_PL_COUNT * 2]; + u32 cci_response_time_us[SPDM_PL_COUNT * 2]; + /* hz */ + u32 max_cci_freq; + /* in MB/s */ + u32 max_vote; + +}; + +struct spdm_data { + /* bus scaling data */ + int cur_idx; + struct msm_bus_scale_pdata *pdata; + u32 bus_scale_client_id; + /* in mb/s */ + u32 new_bw; + + /* devfreq data */ + struct devfreq *devfreq; + struct devfreq_dev_profile *profile; + unsigned long action; + int window; + struct clk *cci_clk; + + /* spdm hw/gov data */ + struct spdm_config_data config_data; + + enum spdm_client spdm_client; + /* list used by governor to keep track of spdm devices */ + struct list_head list; + + struct dentry *debugfs_dir; + + bool enabled; +}; + +extern void spdm_init_debugfs(struct device *dev); +extern void spdm_remove_debugfs(struct spdm_data *data); + +#define SPDM_HYP_FNID 5 +#define SPDM_SCM_SVC_ID 0x9 +#define SPDM_SCM_CMD_ID 0x4 +#define SPDM_TZ_VERSION 0x20000 /* TZ SPDM driver version */ +/* SPDM CMD ID's for hypervisor/SCM */ +#define SPDM_CMD_GET_VERSION 0 +#define SPDM_CMD_GET_BW_ALL 1 +#define SPDM_CMD_GET_BW_SPECIFIC 2 +#define SPDM_CMD_ENABLE 3 +#define SPDM_CMD_DISABLE 4 +#define SPDM_CMD_CFG_PORTS 5 +#define SPDM_CMD_CFG_FLTR 6 +#define SPDM_CMD_CFG_PL 7 +#define SPDM_CMD_CFG_REJRATE_LOW 8 +#define SPDM_CMD_CFG_REJRATE_MED 9 +#define SPDM_CMD_CFG_REJRATE_HIGH 10 +#define SPDM_CMD_CFG_RESPTIME_LOW 11 +#define SPDM_CMD_CFG_RESPTIME_MED 12 +#define SPDM_CMD_CFG_RESPTIME_HIGH 13 +#define SPDM_CMD_CFG_CCIRESPTIME_LOW 14 +#define SPDM_CMD_CFG_CCIRESPTIME_MED 15 +#define SPDM_CMD_CFG_CCIRESPTIME_HIGH 16 +#define SPDM_CMD_CFG_MAXCCI 17 +#define SPDM_CMD_CFG_VOTES 18 + +#define SPDM_MAX_ARGS 6 +#define SPDM_MAX_RETS 3 + +struct spdm_args { + u64 arg[SPDM_MAX_ARGS]; + u64 ret[SPDM_MAX_RETS]; +}; + +#ifdef CONFIG_SPDM_SCM +extern int __spdm_scm_call(struct spdm_args *args, int num_args); +#define spdm_ext_call __spdm_scm_call +#else +extern int __spdm_hyp_call(struct spdm_args *args, int num_args); +#define spdm_ext_call __spdm_hyp_call +#endif +#endif diff --git a/drivers/devfreq/devfreq_spdm_debugfs.c b/drivers/devfreq/devfreq_spdm_debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..4e49d5b7aae73a6eb583b44f60d6802e5507b994 --- /dev/null +++ b/drivers/devfreq/devfreq_spdm_debugfs.c @@ -0,0 +1,848 @@ +/* + *Copyright (c) 2014-2015, 2017, 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 +#include +#include +#include +#include +#include +#include "devfreq_spdm.h" +#include "governor.h" + +static int spdm_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static char buf[PAGE_SIZE]; + +static ssize_t enable_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i; + int next_idx; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + goto err; + size = -EINVAL; + } + + if (sscanf(buf, "%u\n", &i) != 1) { + size = -EINVAL; + goto err; + } + i = !!i; + + if (i == spdm_data->enabled) + goto out; + + spdm_data->devfreq->governor->event_handler(spdm_data->devfreq, + i ? DEVFREQ_GOV_START : + DEVFREQ_GOV_STOP, NULL); + + if (!i) { + next_idx = spdm_data->cur_idx + 1; + next_idx = next_idx % 2; + + for (i = 0; i < spdm_data->pdata->usecase[next_idx].num_paths; + i++) + spdm_data->pdata->usecase[next_idx].vectors[i].ab = 0; + + spdm_data->cur_idx = next_idx; + msm_bus_scale_client_update_request + (spdm_data->bus_scale_client_id, spdm_data->cur_idx); + } + +out: + *offset += size; +err: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t enable_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int len = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + len = scnprintf(buf, size, "%u\n", spdm_data->enabled); + len = simple_read_from_buffer(data, size, offset, buf, len); + + memset(buf, 0, sizeof(buf)); + return len; +} + +static const struct file_operations enable_fops = { + .open = spdm_open, + .write = enable_write, + .read = enable_read, +}; + +static ssize_t pl_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + int i; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.pl_freqs[0], + &spdm_data->config_data.pl_freqs[1]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_PL; + desc.arg[1] = spdm_data->spdm_client; + for (i = 0; i < SPDM_PL_COUNT - 1; i++) + desc.arg[i+2] = spdm_data->config_data.pl_freqs[i]; + ext_status = spdm_ext_call(&desc, SPDM_PL_COUNT + 1); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; + +} + +static ssize_t pl_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", spdm_data->config_data.pl_freqs[0], + spdm_data->config_data.pl_freqs[1]); + i = simple_read_from_buffer(data, size, offset, buf, i); + + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations pl_fops = { + .open = spdm_open, + .write = pl_write, + .read = pl_read, +}; + +static ssize_t rejrate_low_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[0], + &spdm_data->config_data.reject_rate[1]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[0]; + desc.arg[3] = spdm_data->config_data.reject_rate[1]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t rejrate_low_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.reject_rate[0], + spdm_data->config_data.reject_rate[1]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations rrl_fops = { + .open = spdm_open, + .write = rejrate_low_write, + .read = rejrate_low_read, +}; + +static ssize_t rejrate_med_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[2], + &spdm_data->config_data.reject_rate[3]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[2]; + desc.arg[3] = spdm_data->config_data.reject_rate[3]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t rejrate_med_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.reject_rate[2], + spdm_data->config_data.reject_rate[3]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations rrm_fops = { + .open = spdm_open, + .write = rejrate_med_write, + .read = rejrate_med_read, +}; + +static ssize_t rejrate_high_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.reject_rate[4], + &spdm_data->config_data.reject_rate[5]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[4]; + desc.arg[3] = spdm_data->config_data.reject_rate[5]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t rejrate_high_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.reject_rate[4], + spdm_data->config_data.reject_rate[5]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations rrh_fops = { + .open = spdm_open, + .write = rejrate_high_write, + .read = rejrate_high_read, +}; + +static ssize_t resptime_low_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[0], + &spdm_data->config_data.response_time_us[1]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[0]; + desc.arg[3] = spdm_data->config_data.response_time_us[1]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t resptime_low_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.response_time_us[0], + spdm_data->config_data.response_time_us[1]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations rtl_fops = { + .open = spdm_open, + .write = resptime_low_write, + .read = resptime_low_read, +}; + +static ssize_t resptime_med_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[2], + &spdm_data->config_data.response_time_us[3]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[2]; + desc.arg[3] = spdm_data->config_data.response_time_us[3]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t resptime_med_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.response_time_us[2], + spdm_data->config_data.response_time_us[3]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations rtm_fops = { + .open = spdm_open, + .write = resptime_med_write, + .read = resptime_med_read, +}; + +static ssize_t resptime_high_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", &spdm_data->config_data.response_time_us[4], + &spdm_data->config_data.response_time_us[5]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[4]; + desc.arg[3] = spdm_data->config_data.response_time_us[5]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t resptime_high_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.response_time_us[4], + spdm_data->config_data.response_time_us[5]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations rth_fops = { + .open = spdm_open, + .write = resptime_high_write, + .read = resptime_high_read, +}; + +static ssize_t cciresptime_low_write(struct file *file, + const char __user *data, size_t size, + loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", + &spdm_data->config_data.cci_response_time_us[0], + &spdm_data->config_data.cci_response_time_us[1]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[0]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[1]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t cciresptime_low_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.cci_response_time_us[0], + spdm_data->config_data.cci_response_time_us[1]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations ccil_fops = { + .open = spdm_open, + .write = cciresptime_low_write, + .read = cciresptime_low_read, +}; + +static ssize_t cciresptime_med_write(struct file *file, + const char __user *data, size_t size, + loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", + &spdm_data->config_data.cci_response_time_us[2], + &spdm_data->config_data.cci_response_time_us[3]) != 2) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[2]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[3]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t cciresptime_med_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.cci_response_time_us[2], + spdm_data->config_data.cci_response_time_us[3]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations ccim_fops = { + .open = spdm_open, + .write = cciresptime_med_write, + .read = cciresptime_med_read, +}; + +static ssize_t cciresptime_high_write(struct file *file, + const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u\n", + &spdm_data->config_data.cci_response_time_us[4], + &spdm_data->config_data.cci_response_time_us[5]) != 2){ + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[4]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[5]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t cciresptime_high_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u\n", + spdm_data->config_data.cci_response_time_us[4], + spdm_data->config_data.cci_response_time_us[5]); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations ccih_fops = { + .open = spdm_open, + .write = cciresptime_high_write, + .read = cciresptime_high_read, +}; + +static ssize_t cci_max_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u\n", &spdm_data->config_data.max_cci_freq) != 1) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_MAXCCI; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.max_cci_freq; + ext_status = spdm_ext_call(&desc, 3); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t cci_max_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u\n", spdm_data->config_data.max_cci_freq); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations ccimax_fops = { + .open = spdm_open, + .write = cci_max_write, + .read = cci_max_read, +}; + +static ssize_t vote_cfg_write(struct file *file, const char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + if (size > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, data, size)) { + size = -EINVAL; + goto out; + } + if (sscanf(buf, "%u %u %u %u\n", &spdm_data->config_data.upstep, + &spdm_data->config_data.downstep, + &spdm_data->config_data.max_vote, + &spdm_data->config_data.up_step_multp) != 4) { + size = -EINVAL; + goto out; + } + + desc.arg[0] = SPDM_CMD_CFG_VOTES; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.upstep; + desc.arg[3] = spdm_data->config_data.downstep; + desc.arg[4] = spdm_data->config_data.max_vote; + desc.arg[5] = spdm_data->config_data.up_step_multp; + ext_status = spdm_ext_call(&desc, 6); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + *offset += size; +out: + memset(buf, 0, sizeof(buf)); + return size; +} + +static ssize_t vote_cfg_read(struct file *file, char __user *data, + size_t size, loff_t *offset) +{ + struct spdm_data *spdm_data = file->private_data; + int i = 32; + + if (size > sizeof(buf)) + return -EINVAL; + + i = scnprintf(buf, size, "%u %u %u %u\n", + spdm_data->config_data.upstep, + spdm_data->config_data.downstep, + spdm_data->config_data.max_vote, + spdm_data->config_data.up_step_multp); + + i = simple_read_from_buffer(data, size, offset, buf, i); + memset(buf, 0, sizeof(buf)); + return i; +} + +static const struct file_operations vote_fops = { + .open = spdm_open, + .write = vote_cfg_write, + .read = vote_cfg_read, +}; + +void spdm_init_debugfs(struct device *dev) +{ + struct spdm_data *data = 0; + + data = dev_get_drvdata(dev); + data->debugfs_dir = debugfs_create_dir(dev_name(dev), NULL); + + debugfs_create_file("enable", 0600, data->debugfs_dir, data, + &enable_fops); + debugfs_create_file("pl_freqs", 0600, data->debugfs_dir, data, + &pl_fops); + debugfs_create_file("rej_rate_low", 0600, data->debugfs_dir, data, + &rrl_fops); + debugfs_create_file("rej_rate_med", 0600, data->debugfs_dir, data, + &rrm_fops); + debugfs_create_file("rej_rate_high", 0600, data->debugfs_dir, data, + &rrh_fops); + debugfs_create_file("resp_time_low", 0600, data->debugfs_dir, data, + &rtl_fops); + debugfs_create_file("resp_time_med", 0600, data->debugfs_dir, data, + &rtm_fops); + debugfs_create_file("resp_time_high", 0600, data->debugfs_dir, data, + &rth_fops); + debugfs_create_file("cci_resp_time_low", 0600, data->debugfs_dir, data, + &ccil_fops); + debugfs_create_file("cci_resp_time_med", 0600, data->debugfs_dir, data, + &ccim_fops); + debugfs_create_file("cci_resp_time_high", 0600, data->debugfs_dir, + data, &ccih_fops); + debugfs_create_file("cci_max", 0600, data->debugfs_dir, data, + &ccimax_fops); + debugfs_create_file("vote_cfg", 0600, data->debugfs_dir, data, + &vote_fops); +} + +void spdm_remove_debugfs(struct spdm_data *data) +{ + debugfs_remove_recursive(data->debugfs_dir); +} + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c index 53c0f8aee687197890c75eb075f304eed2127118..3026bc22b374ad63ec98dd00cee43a475a4e0fb7 100644 --- a/drivers/devfreq/governor_bw_hwmon.c +++ b/drivers/devfreq/governor_bw_hwmon.c @@ -48,9 +48,6 @@ struct hwmon_node { unsigned int hyst_trigger_count; unsigned int hyst_length; unsigned int idle_mbps; - unsigned int low_power_ceil_mbps; - unsigned int low_power_io_percent; - unsigned int low_power_delay; unsigned int mbps_zones[NUM_MBPS_ZONES]; unsigned long prev_ab; @@ -65,7 +62,6 @@ struct hwmon_node { unsigned long hyst_mbps; unsigned long hyst_trig_win; unsigned long hyst_en; - unsigned long above_low_power; unsigned long prev_req; unsigned int wake; unsigned int down_cnt; @@ -317,7 +313,7 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, unsigned long meas_mbps_zone; unsigned long hist_lo_tol, hyst_lo_tol; struct bw_hwmon *hw = node->hw; - unsigned int new_bw, io_percent; + unsigned int new_bw, io_percent = node->io_percent; ktime_t ts; unsigned int ms = 0; @@ -353,17 +349,6 @@ static unsigned long get_bw_and_set_irq(struct hwmon_node *node, node->hist_mem--; } - /* Keep track of whether we are in low power mode consistently. */ - if (meas_mbps > node->low_power_ceil_mbps) - node->above_low_power = node->low_power_delay; - if (node->above_low_power) - node->above_low_power--; - - if (node->above_low_power) - io_percent = node->io_percent; - else - io_percent = node->low_power_io_percent; - /* * The AB value that corresponds to the lowest mbps zone greater than * or equal to the "frequency" the current measurement will pick. @@ -785,9 +770,6 @@ gov_attr(hist_memory, 0U, 90U); gov_attr(hyst_trigger_count, 0U, 90U); gov_attr(hyst_length, 0U, 90U); gov_attr(idle_mbps, 0U, 2000U); -gov_attr(low_power_ceil_mbps, 0U, 2500U); -gov_attr(low_power_io_percent, 1U, 100U); -gov_attr(low_power_delay, 1U, 60U); gov_list_attr(mbps_zones, NUM_MBPS_ZONES, 0U, UINT_MAX); static struct attribute *dev_attr[] = { @@ -804,9 +786,6 @@ static struct attribute *dev_attr[] = { &dev_attr_hyst_trigger_count.attr, &dev_attr_hyst_length.attr, &dev_attr_idle_mbps.attr, - &dev_attr_low_power_ceil_mbps.attr, - &dev_attr_low_power_io_percent.attr, - &dev_attr_low_power_delay.attr, &dev_attr_mbps_zones.attr, &dev_attr_throttle_adj.attr, NULL, @@ -820,11 +799,13 @@ static struct attribute_group dev_attr_group = { static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, unsigned int event, void *data) { - int ret; + int ret = 0; unsigned int sample_ms; struct hwmon_node *node; struct bw_hwmon *hw; + mutex_lock(&state_lock); + switch (event) { case DEVFREQ_GOV_START: sample_ms = df->profile->polling_ms; @@ -834,7 +815,7 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, ret = gov_start(df); if (ret) - return ret; + goto out; dev_dbg(df->dev.parent, "Enabled dev BW HW monitor governor\n"); @@ -864,7 +845,7 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, if (ret) { dev_err(df->dev.parent, "Unable to resume HW monitor (%d)\n", ret); - return ret; + goto out; } break; @@ -874,7 +855,7 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, dev_err(df->dev.parent, "Unable to suspend BW HW mon governor (%d)\n", ret); - return ret; + goto out; } dev_dbg(df->dev.parent, "Suspended BW HW mon governor\n"); @@ -886,14 +867,17 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df, dev_err(df->dev.parent, "Unable to resume BW HW mon governor (%d)\n", ret); - return ret; + goto out; } dev_dbg(df->dev.parent, "Resumed BW HW mon governor\n"); break; } - return 0; +out: + mutex_unlock(&state_lock); + + return ret; } static struct devfreq_governor devfreq_gov_bw_hwmon = { @@ -935,9 +919,6 @@ int register_bw_hwmon(struct device *dev, struct bw_hwmon *hwmon) node->guard_band_mbps = 100; node->decay_rate = 90; node->io_percent = 16; - node->low_power_ceil_mbps = 0; - node->low_power_io_percent = 16; - node->low_power_delay = 60; node->bw_step = 190; node->sample_ms = 50; node->up_scale = 0; diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c index e1afa60ec442c42a2472a0495d3b1076e76b57bf..12a90d41bc37d0a01f3c9eb2799bb26fce15611a 100644 --- a/drivers/devfreq/governor_memlat.c +++ b/drivers/devfreq/governor_memlat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,7 +35,9 @@ struct memlat_node { unsigned int ratio_ceil; + unsigned int stall_floor; bool mon_started; + bool already_zero; struct list_head list; void *orig_data; struct memlat_hwmon *hw; @@ -46,7 +48,8 @@ struct memlat_node { static LIST_HEAD(memlat_list); static DEFINE_MUTEX(list_lock); -static int use_cnt; +static int memlat_use_cnt; +static int compute_use_cnt; static DEFINE_MUTEX(state_lock); #define show_attr(name) \ @@ -224,7 +227,7 @@ static void gov_stop(struct devfreq *df) static int devfreq_memlat_get_freq(struct devfreq *df, unsigned long *freq) { - int i, lat_dev; + int i, lat_dev = 0; struct memlat_node *node = df->data; struct memlat_hwmon *hw = node->hw; unsigned long max_freq = 0; @@ -238,21 +241,28 @@ static int devfreq_memlat_get_freq(struct devfreq *df, if (hw->core_stats[i].mem_count) ratio /= hw->core_stats[i].mem_count; + if (!hw->core_stats[i].freq) + continue; + trace_memlat_dev_meas(dev_name(df->dev.parent), hw->core_stats[i].id, hw->core_stats[i].inst_count, hw->core_stats[i].mem_count, - hw->core_stats[i].freq, ratio); + hw->core_stats[i].freq, + hw->core_stats[i].stall_pct, ratio); - if (ratio && ratio <= node->ratio_ceil + if (ratio <= node->ratio_ceil + && hw->core_stats[i].stall_pct >= node->stall_floor && hw->core_stats[i].freq > max_freq) { lat_dev = i; max_freq = hw->core_stats[i].freq; } } - if (max_freq) { + if (max_freq) max_freq = core_to_dev_freq(node, max_freq); + + if (max_freq || !node->already_zero) { trace_memlat_dev_update(dev_name(df->dev.parent), hw->core_stats[lat_dev].id, hw->core_stats[lat_dev].inst_count, @@ -261,21 +271,35 @@ static int devfreq_memlat_get_freq(struct devfreq *df, max_freq); } + node->already_zero = !max_freq; + *freq = max_freq; return 0; } gov_attr(ratio_ceil, 1U, 10000U); +gov_attr(stall_floor, 0U, 100U); -static struct attribute *dev_attr[] = { +static struct attribute *memlat_dev_attr[] = { &dev_attr_ratio_ceil.attr, + &dev_attr_stall_floor.attr, + &dev_attr_freq_map.attr, + NULL, +}; + +static struct attribute *compute_dev_attr[] = { &dev_attr_freq_map.attr, NULL, }; -static struct attribute_group dev_attr_group = { +static struct attribute_group memlat_dev_attr_group = { .name = "mem_latency", - .attrs = dev_attr, + .attrs = memlat_dev_attr, +}; + +static struct attribute_group compute_dev_attr_group = { + .name = "compute", + .attrs = compute_dev_attr, }; #define MIN_MS 10U @@ -324,6 +348,12 @@ static struct devfreq_governor devfreq_gov_memlat = { .event_handler = devfreq_memlat_ev_handler, }; +static struct devfreq_governor devfreq_gov_compute = { + .name = "compute", + .get_target_freq = devfreq_memlat_get_freq, + .event_handler = devfreq_memlat_ev_handler, +}; + #define NUM_COLS 2 static struct core_dev_map *init_core_dev_map(struct device *dev, char *prop_name) @@ -366,20 +396,17 @@ static struct core_dev_map *init_core_dev_map(struct device *dev, return tbl; } -int register_memlat(struct device *dev, struct memlat_hwmon *hw) +static struct memlat_node *register_common(struct device *dev, + struct memlat_hwmon *hw) { - int ret = 0; struct memlat_node *node; if (!hw->dev && !hw->of_node) - return -EINVAL; + return ERR_PTR(-EINVAL); node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); if (!node) - return -ENOMEM; - - node->gov = &devfreq_gov_memlat; - node->attr_grp = &dev_attr_group; + return ERR_PTR(-ENOMEM); node->ratio_ceil = 10; node->hw = hw; @@ -387,20 +414,68 @@ int register_memlat(struct device *dev, struct memlat_hwmon *hw) hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table"); if (!hw->freq_map) { dev_err(dev, "Couldn't find the core-dev freq table!\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } mutex_lock(&list_lock); list_add_tail(&node->list, &memlat_list); mutex_unlock(&list_lock); + return node; +} + +int register_compute(struct device *dev, struct memlat_hwmon *hw) +{ + struct memlat_node *node; + int ret = 0; + + node = register_common(dev, hw); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto out; + } + + mutex_lock(&state_lock); + node->gov = &devfreq_gov_compute; + node->attr_grp = &compute_dev_attr_group; + + if (!compute_use_cnt) + ret = devfreq_add_governor(&devfreq_gov_compute); + if (!ret) + compute_use_cnt++; + mutex_unlock(&state_lock); + +out: + if (!ret) + dev_info(dev, "Compute governor registered.\n"); + else + dev_err(dev, "Compute governor registration failed!\n"); + + return ret; +} + +int register_memlat(struct device *dev, struct memlat_hwmon *hw) +{ + struct memlat_node *node; + int ret = 0; + + node = register_common(dev, hw); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto out; + } + mutex_lock(&state_lock); - if (!use_cnt) + node->gov = &devfreq_gov_memlat; + node->attr_grp = &memlat_dev_attr_group; + + if (!memlat_use_cnt) ret = devfreq_add_governor(&devfreq_gov_memlat); if (!ret) - use_cnt++; + memlat_use_cnt++; mutex_unlock(&state_lock); +out: if (!ret) dev_info(dev, "Memory Latency governor registered.\n"); else diff --git a/drivers/devfreq/governor_memlat.h b/drivers/devfreq/governor_memlat.h index a0e52a0997adf5a0aff23d1198529e7051ebde4c..6491c6ceccd64d7c435fc9fbbcff3cb6ea1b2294 100644 --- a/drivers/devfreq/governor_memlat.h +++ b/drivers/devfreq/governor_memlat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _GOVERNOR_BW_HWMON_H -#define _GOVERNOR_BW_HWMON_H +#ifndef _GOVERNOR_MEMLAT_H +#define _GOVERNOR_MEMLAT_H #include #include @@ -29,6 +29,7 @@ struct dev_stats { unsigned long inst_count; unsigned long mem_count; unsigned long freq; + unsigned long stall_pct; }; struct core_dev_map { @@ -73,10 +74,16 @@ struct memlat_hwmon { #ifdef CONFIG_DEVFREQ_GOV_MEMLAT int register_memlat(struct device *dev, struct memlat_hwmon *hw); +int register_compute(struct device *dev, struct memlat_hwmon *hw); int update_memlat(struct memlat_hwmon *hw); #else static inline int register_memlat(struct device *dev, - struct memlat_hwmon *hw) + struct memlat_hwmon *hw) +{ + return 0; +} +static inline int register_compute(struct device *dev, + struct memlat_hwmon *hw) { return 0; } diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index 43d8fefc87cb21111310aa862bf0d72b12dda83b..3c50c4e26c0e1fd19b038ed99995ee129418e0fc 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -236,7 +236,7 @@ static int tz_init_ca(struct devfreq_msm_adreno_tz_data *priv) { unsigned int tz_ca_data[2]; struct scm_desc desc = {0}; - unsigned int *tz_buf; + u8 *tz_buf; int ret; /* Set data for TZ */ @@ -281,7 +281,7 @@ static int tz_init(struct devfreq_msm_adreno_tz_data *priv, scm_is_call_available(SCM_SVC_DCVS, TZ_UPDATE_ID_64) && scm_is_call_available(SCM_SVC_DCVS, TZ_RESET_ID_64)) { struct scm_desc desc = {0}; - unsigned int *tz_buf; + u8 *tz_buf; if (!is_scm_armv8()) { ret = scm_call(SCM_SVC_DCVS, TZ_INIT_ID_64, @@ -548,10 +548,6 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data) (devfreq->profile), struct msm_adreno_extended_profile, profile); - if (devfreq == NULL) { - pr_err(TAG "NULL defvreq passed to tz_handler\n"); - return -EFAULT; - } switch (event) { case DEVFREQ_GOV_START: diff --git a/drivers/devfreq/governor_spdm_bw_hyp.c b/drivers/devfreq/governor_spdm_bw_hyp.c new file mode 100644 index 0000000000000000000000000000000000000000..7e7e0eee7f6daf9a06172228ec3c1e76d740213f --- /dev/null +++ b/drivers/devfreq/governor_spdm_bw_hyp.c @@ -0,0 +1,419 @@ +/* + *Copyright (c) 2014-2018, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "governor.h" +#include "devfreq_spdm.h" + +enum msm_spdm_rt_res { + SPDM_RES_ID = 1, + SPDM_RES_TYPE = 0x63707362, + SPDM_KEY = 0x00006e65, + SPDM_SIZE = 4, +}; + +static LIST_HEAD(devfreqs); +static DEFINE_MUTEX(devfreqs_lock); + +static int enable_clocks(void) +{ + struct msm_rpm_request *rpm_req; + int id; + const int one = 1; + + rpm_req = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET, SPDM_RES_TYPE, + SPDM_RES_ID, 1); + if (IS_ERR_OR_NULL(rpm_req)) + return -ENODEV; + msm_rpm_add_kvp_data(rpm_req, SPDM_KEY, (const uint8_t *)&one, + sizeof(int)); + id = msm_rpm_send_request(rpm_req); + msm_rpm_wait_for_ack(id); + msm_rpm_free_request(rpm_req); + + return 0; +} + +static int disable_clocks(void) +{ + struct msm_rpm_request *rpm_req; + int id; + const int zero = 0; + + rpm_req = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET, SPDM_RES_TYPE, + SPDM_RES_ID, 1); + if (IS_ERR_OR_NULL(rpm_req)) + return -ENODEV; + msm_rpm_add_kvp_data(rpm_req, SPDM_KEY, (const uint8_t *)&zero, + sizeof(int)); + id = msm_rpm_send_request(rpm_req); + msm_rpm_wait_for_ack(id); + msm_rpm_free_request(rpm_req); + + return 0; +} + +static irqreturn_t threaded_isr(int irq, void *dev_id) +{ + struct spdm_data *data; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + + /* call hyp to get bw_vote */ + desc.arg[0] = SPDM_CMD_GET_BW_ALL; + ext_status = spdm_ext_call(&desc, 1); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + mutex_lock(&devfreqs_lock); + list_for_each_entry(data, &devfreqs, list) { + if (data == NULL || data->devfreq == NULL) { + pr_err("Spurious interrupts\n"); + break; + } + if (data->spdm_client == desc.ret[0]) { + devfreq_monitor_suspend(data->devfreq); + mutex_lock(&data->devfreq->lock); + data->action = SPDM_UP; + data->new_bw = + (desc.ret[1] * 1000) >> 6; + update_devfreq(data->devfreq); + data->action = SPDM_DOWN; + mutex_unlock(&data->devfreq->lock); + devfreq_monitor_resume(data->devfreq); + break; + } + } + mutex_unlock(&devfreqs_lock); + return IRQ_HANDLED; +} + +static irqreturn_t isr(int irq, void *dev_id) +{ + return IRQ_WAKE_THREAD; +} + +static int gov_spdm_hyp_target_bw(struct devfreq *devfreq, unsigned long *freq) +{ + struct devfreq_dev_status status; + int ret = -EINVAL; + int usage; + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + u64 bw_ret; + + if (!devfreq || !devfreq->profile || !devfreq->profile->get_dev_status) + return ret; + + ret = devfreq->profile->get_dev_status(devfreq->dev.parent, &status); + if (ret) + return ret; + + usage = (status.busy_time * 100) / status.total_time; + + if (usage > 0) { + /* up was already called as part of hyp, so just use the + * already stored values. + */ + *freq = ((struct spdm_data *)devfreq->data)->new_bw; + } else { + desc.arg[0] = SPDM_CMD_GET_BW_SPECIFIC; + desc.arg[1] = ((struct spdm_data *)devfreq->data)->spdm_client; + ext_status = spdm_ext_call(&desc, 2); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + bw_ret = desc.ret[0] * 1000; + *freq = bw_ret >> 6; + } + + return 0; +} + +static int gov_spdm_hyp_eh(struct devfreq *devfreq, unsigned int event, + void *data) +{ + struct spdm_args desc = { { 0 } }; + int ext_status = 0; + struct spdm_data *spdm_data = (struct spdm_data *)devfreq->data; + int i; + + switch (event) { + case DEVFREQ_GOV_START: + mutex_lock(&devfreqs_lock); + list_add(&spdm_data->list, &devfreqs); + mutex_unlock(&devfreqs_lock); + /* call hyp with config data */ + desc.arg[0] = SPDM_CMD_CFG_PORTS; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.num_ports; + for (i = 0; i < spdm_data->config_data.num_ports; i++) + desc.arg[i+3] = spdm_data->config_data.ports[i]; + ext_status = spdm_ext_call(&desc, + spdm_data->config_data.num_ports + 3); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_FLTR; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.aup; + desc.arg[3] = spdm_data->config_data.adown; + desc.arg[4] = spdm_data->config_data.bucket_size; + ext_status = spdm_ext_call(&desc, 5); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_PL; + desc.arg[1] = spdm_data->spdm_client; + for (i = 0; i < SPDM_PL_COUNT - 1; i++) + desc.arg[i+2] = spdm_data->config_data.pl_freqs[i]; + ext_status = spdm_ext_call(&desc, SPDM_PL_COUNT + 1); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_REJRATE_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[0]; + desc.arg[3] = spdm_data->config_data.reject_rate[1]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + desc.arg[0] = SPDM_CMD_CFG_REJRATE_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[2]; + desc.arg[3] = spdm_data->config_data.reject_rate[3]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + desc.arg[0] = SPDM_CMD_CFG_REJRATE_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.reject_rate[4]; + desc.arg[3] = spdm_data->config_data.reject_rate[5]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[0]; + desc.arg[3] = spdm_data->config_data.response_time_us[1]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[2]; + desc.arg[3] = spdm_data->config_data.response_time_us[3]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + desc.arg[0] = SPDM_CMD_CFG_RESPTIME_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.response_time_us[4]; + desc.arg[3] = spdm_data->config_data.response_time_us[5]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_LOW; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[0]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[1]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_MED; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[2]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[3]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + desc.arg[0] = SPDM_CMD_CFG_CCIRESPTIME_HIGH; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.cci_response_time_us[4]; + desc.arg[3] = spdm_data->config_data.cci_response_time_us[5]; + ext_status = spdm_ext_call(&desc, 4); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_MAXCCI; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.max_cci_freq; + ext_status = spdm_ext_call(&desc, 3); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + desc.arg[0] = SPDM_CMD_CFG_VOTES; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = spdm_data->config_data.upstep; + desc.arg[3] = spdm_data->config_data.downstep; + desc.arg[4] = spdm_data->config_data.max_vote; + desc.arg[5] = spdm_data->config_data.up_step_multp; + ext_status = spdm_ext_call(&desc, 6); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + + /* call hyp enable/commit */ + desc.arg[0] = SPDM_CMD_ENABLE; + desc.arg[1] = spdm_data->spdm_client; + desc.arg[2] = 0; + ext_status = spdm_ext_call(&desc, 3); + if (ext_status) { + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + mutex_lock(&devfreqs_lock); + /* + * the spdm device probe will fail so remove it from + * the list to prevent accessing a deleted pointer in + * the future + */ + list_del(&spdm_data->list); + mutex_unlock(&devfreqs_lock); + return -EINVAL; + } + spdm_data->enabled = true; + devfreq_monitor_start(devfreq); + break; + + case DEVFREQ_GOV_STOP: + devfreq_monitor_stop(devfreq); + /* find devfreq in list and remove it */ + mutex_lock(&devfreqs_lock); + list_del(&spdm_data->list); + mutex_unlock(&devfreqs_lock); + + /* call hypvervisor to disable */ + desc.arg[0] = SPDM_CMD_DISABLE; + desc.arg[1] = spdm_data->spdm_client; + ext_status = spdm_ext_call(&desc, 2); + if (ext_status) + pr_err("External command %u failed with error %u", + (int)desc.arg[0], ext_status); + spdm_data->enabled = false; + break; + + case DEVFREQ_GOV_INTERVAL: + devfreq_interval_update(devfreq, (unsigned int *)data); + break; + + case DEVFREQ_GOV_SUSPEND: + devfreq_monitor_suspend(devfreq); + break; + + case DEVFREQ_GOV_RESUME: + devfreq_monitor_resume(devfreq); + break; + + default: + break; + } + + return 0; +} + +static struct devfreq_governor spdm_hyp_gov = { + .name = "spdm_bw_hyp", + .get_target_freq = gov_spdm_hyp_target_bw, + .event_handler = gov_spdm_hyp_eh, +}; + +static int probe(struct platform_device *pdev) +{ + int ret = -EINVAL; + int *irq = 0; + + irq = devm_kzalloc(&pdev->dev, sizeof(int), GFP_KERNEL); + if (!irq) + return -ENOMEM; + platform_set_drvdata(pdev, irq); + + ret = devfreq_add_governor(&spdm_hyp_gov); + if (ret) + goto nogov; + + *irq = platform_get_irq_byname(pdev, "spdm-irq"); + ret = request_threaded_irq(*irq, isr, threaded_isr, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + spdm_hyp_gov.name, pdev); + if (ret) + goto no_irq; + + enable_clocks(); + return 0; + +no_irq: + devfreq_remove_governor(&spdm_hyp_gov); +nogov: + devm_kfree(&pdev->dev, irq); + return ret; +} + +static int remove(struct platform_device *pdev) +{ + int *irq = 0; + + disable_clocks(); + irq = platform_get_drvdata(pdev); + free_irq(*irq, pdev); + devfreq_remove_governor(&spdm_hyp_gov); + devm_kfree(&pdev->dev, irq); + return 0; +} + +static const struct of_device_id gov_spdm_match[] = { + {.compatible = "qcom,gov_spdm_hyp"}, + {} +}; + +static struct platform_driver gov_spdm_hyp_drvr = { + .driver = { + .name = "gov_spdm_hyp", + .owner = THIS_MODULE, + .of_match_table = gov_spdm_match, + }, + .probe = probe, + .remove = remove, +}; + +static int __init governor_spdm_bw_hyp(void) +{ + return platform_driver_register(&gov_spdm_hyp_drvr); +} + +module_init(governor_spdm_bw_hyp); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma-buf/fence.c b/drivers/dma-buf/fence.c index 2453e076ee365ad1d16362f742ed4025765643ba..883b3bea143c1123e8559fb37eb943fd2d27a9cf 100644 --- a/drivers/dma-buf/fence.c +++ b/drivers/dma-buf/fence.c @@ -68,6 +68,8 @@ int fence_signal_locked(struct fence *fence) struct fence_cb *cur, *tmp; int ret = 0; + lockdep_assert_held(fence->lock); + if (WARN_ON(!fence)) return -EINVAL; @@ -159,9 +161,6 @@ fence_wait_timeout(struct fence *fence, bool intr, signed long timeout) if (WARN_ON(timeout < 0)) return -EINVAL; - if (timeout == 0) - return fence_is_signaled(fence); - trace_fence_wait_start(fence); ret = fence->ops->wait(fence, intr, timeout); trace_fence_wait_end(fence); @@ -280,6 +279,31 @@ int fence_add_callback(struct fence *fence, struct fence_cb *cb, } EXPORT_SYMBOL(fence_add_callback); +/** + * fence_get_status - returns the status upon completion + * @fence: [in] the fence to query + * + * This wraps fence_get_status_locked() to return the error status + * condition on a signaled fence. See fence_get_status_locked() for more + * details. + * + * Returns 0 if the fence has not yet been signaled, 1 if the fence has + * been signaled without an error condition, or a negative error code + * if the fence has been completed in err. + */ +int fence_get_status(struct fence *fence) +{ + unsigned long flags; + int status; + + spin_lock_irqsave(fence->lock, flags); + status = fence_get_status_locked(fence); + spin_unlock_irqrestore(fence->lock, flags); + + return status; +} +EXPORT_SYMBOL(fence_get_status); + /** * fence_remove_callback - remove a callback from the signaling list * @fence: [in] the fence to wait on @@ -530,6 +554,7 @@ fence_init(struct fence *fence, const struct fence_ops *ops, fence->context = context; fence->seqno = seqno; fence->flags = 0UL; + fence->error = 0; trace_fence_init(fence); } diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 723d8af988e5146ba247ce38658fe03f8b057923..82f35a4ab390a402821f44d6bf07b22366c5654f 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -280,18 +280,24 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, unsigned *pshared_count, struct fence ***pshared) { - unsigned shared_count = 0; - unsigned retry = 1; - struct fence **shared = NULL, *fence_excl = NULL; - int ret = 0; + struct fence **shared = NULL; + struct fence *fence_excl; + unsigned int shared_count; + int ret = 1; - while (retry) { + do { struct reservation_object_list *fobj; unsigned seq; + unsigned int i; - seq = read_seqcount_begin(&obj->seq); + shared_count = i = 0; rcu_read_lock(); + seq = read_seqcount_begin(&obj->seq); + + fence_excl = rcu_dereference(obj->fence_excl); + if (fence_excl && !fence_get_rcu(fence_excl)) + goto unlock; fobj = rcu_dereference(obj->fence); if (fobj) { @@ -309,52 +315,37 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, } ret = -ENOMEM; - shared_count = 0; break; } shared = nshared; - memcpy(shared, fobj->shared, sz); shared_count = fobj->shared_count; - } else - shared_count = 0; - fence_excl = rcu_dereference(obj->fence_excl); - - retry = read_seqcount_retry(&obj->seq, seq); - if (retry) - goto unlock; - - if (!fence_excl || fence_get_rcu(fence_excl)) { - unsigned i; for (i = 0; i < shared_count; ++i) { - if (fence_get_rcu(shared[i])) - continue; - - /* uh oh, refcount failed, abort and retry */ - while (i--) - fence_put(shared[i]); - - if (fence_excl) { - fence_put(fence_excl); - fence_excl = NULL; - } - - retry = 1; - break; + shared[i] = rcu_dereference(fobj->shared[i]); + if (!fence_get_rcu(shared[i])) + break; } - } else - retry = 1; + } + if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) { + while (i--) + fence_put(shared[i]); + fence_put(fence_excl); + goto unlock; + } + + ret = 0; unlock: rcu_read_unlock(); - } - *pshared_count = shared_count; - if (shared_count) - *pshared = shared; - else { - *pshared = NULL; + } while (ret); + + if (!shared_count) { kfree(shared); + shared = NULL; } + + *pshared_count = shared_count; + *pshared = shared; *pfence_excl = fence_excl; return ret; @@ -379,10 +370,7 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj, { struct fence *fence; unsigned seq, shared_count, i = 0; - long ret = timeout; - - if (!timeout) - return reservation_object_test_signaled_rcu(obj, wait_all); + long ret = timeout ? timeout : 1; retry: fence = NULL; @@ -397,9 +385,6 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj, if (fobj) shared_count = fobj->shared_count; - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - for (i = 0; i < shared_count; ++i) { struct fence *lfence = rcu_dereference(fobj->shared[i]); @@ -422,9 +407,6 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj, if (!shared_count) { struct fence *fence_excl = rcu_dereference(obj->fence_excl); - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - if (fence_excl && !test_bit(FENCE_FLAG_SIGNALED_BIT, &fence_excl->flags)) { if (!fence_get_rcu(fence_excl)) @@ -439,6 +421,11 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj, rcu_read_unlock(); if (fence) { + if (read_seqcount_retry(&obj->seq, seq)) { + fence_put(fence); + goto retry; + } + ret = fence_wait_timeout(fence, intr, ret); fence_put(fence); if (ret > 0 && wait_all && (i + 1 < shared_count)) @@ -484,12 +471,13 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj, bool test_all) { unsigned seq, shared_count; - int ret = true; + int ret; + rcu_read_lock(); retry: + ret = true; shared_count = 0; seq = read_seqcount_begin(&obj->seq); - rcu_read_lock(); if (test_all) { unsigned i; @@ -500,46 +488,35 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj, if (fobj) shared_count = fobj->shared_count; - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - for (i = 0; i < shared_count; ++i) { struct fence *fence = rcu_dereference(fobj->shared[i]); ret = reservation_object_test_signaled_single(fence); if (ret < 0) - goto unlock_retry; + goto retry; else if (!ret) break; } - /* - * There could be a read_seqcount_retry here, but nothing cares - * about whether it's the old or newer fence pointers that are - * signaled. That race could still have happened after checking - * read_seqcount_retry. If you care, use ww_mutex_lock. - */ + if (read_seqcount_retry(&obj->seq, seq)) + goto retry; } if (!shared_count) { struct fence *fence_excl = rcu_dereference(obj->fence_excl); - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - if (fence_excl) { ret = reservation_object_test_signaled_single( fence_excl); if (ret < 0) - goto unlock_retry; + goto retry; + + if (read_seqcount_retry(&obj->seq, seq)) + goto retry; } } rcu_read_unlock(); return ret; - -unlock_retry: - rcu_read_unlock(); - goto retry; } EXPORT_SYMBOL_GPL(reservation_object_test_signaled_rcu); diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 454d3b3df5129db41db26a21601a2d797ad71b2d..9dc86d3303aedf5ecf378fa6daed87831177546c 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -96,9 +96,9 @@ struct sync_timeline *sync_timeline_create(const char *name) obj->context = fence_context_alloc(1); strlcpy(obj->name, name, sizeof(obj->name)); - INIT_LIST_HEAD(&obj->child_list_head); - INIT_LIST_HEAD(&obj->active_list_head); - spin_lock_init(&obj->child_list_lock); + obj->pt_tree = RB_ROOT; + INIT_LIST_HEAD(&obj->pt_list); + spin_lock_init(&obj->lock); sync_timeline_debug_add(obj); @@ -125,68 +125,6 @@ static void sync_timeline_put(struct sync_timeline *obj) kref_put(&obj->kref, sync_timeline_free); } -/** - * sync_timeline_signal() - signal a status change on a sync_timeline - * @obj: sync_timeline to signal - * @inc: num to increment on timeline->value - * - * A sync implementation should call this any time one of it's fences - * has signaled or has an error condition. - */ -static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) -{ - unsigned long flags; - struct sync_pt *pt, *next; - - trace_sync_timeline(obj); - - spin_lock_irqsave(&obj->child_list_lock, flags); - - obj->value += inc; - - list_for_each_entry_safe(pt, next, &obj->active_list_head, - active_list) { - if (fence_is_signaled_locked(&pt->base)) - list_del_init(&pt->active_list); - } - - spin_unlock_irqrestore(&obj->child_list_lock, flags); -} - -/** - * sync_pt_create() - creates a sync pt - * @parent: fence's parent sync_timeline - * @size: size to allocate for this pt - * @inc: value of the fence - * - * Creates a new sync_pt as a child of @parent. @size bytes will be - * allocated allowing for implementation specific data to be kept after - * the generic sync_timeline struct. Returns the sync_pt object or - * NULL in case of error. - */ -static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, - unsigned int value) -{ - unsigned long flags; - struct sync_pt *pt; - - if (size < sizeof(*pt)) - return NULL; - - pt = kzalloc(size, GFP_KERNEL); - if (!pt) - return NULL; - - spin_lock_irqsave(&obj->child_list_lock, flags); - sync_timeline_get(obj); - fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, - obj->context, value); - list_add_tail(&pt->child_list, &obj->child_list_head); - INIT_LIST_HEAD(&pt->active_list); - spin_unlock_irqrestore(&obj->child_list_lock, flags); - return pt; -} - static const char *timeline_fence_get_driver_name(struct fence *fence) { return "sw_sync"; @@ -203,13 +141,17 @@ static void timeline_fence_release(struct fence *fence) { struct sync_pt *pt = fence_to_sync_pt(fence); struct sync_timeline *parent = fence_parent(fence); - unsigned long flags; - spin_lock_irqsave(fence->lock, flags); - list_del(&pt->child_list); - if (!list_empty(&pt->active_list)) - list_del(&pt->active_list); - spin_unlock_irqrestore(fence->lock, flags); + if (!list_empty(&pt->link)) { + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); + if (!list_empty(&pt->link)) { + list_del(&pt->link); + rb_erase(&pt->node, &parent->pt_tree); + } + spin_unlock_irqrestore(fence->lock, flags); + } sync_timeline_put(parent); fence_free(fence); @@ -219,18 +161,11 @@ static bool timeline_fence_signaled(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); - return (fence->seqno > parent->value) ? false : true; + return !__fence_is_later(fence->seqno, parent->value); } static bool timeline_fence_enable_signaling(struct fence *fence) { - struct sync_pt *pt = fence_to_sync_pt(fence); - struct sync_timeline *parent = fence_parent(fence); - - if (timeline_fence_signaled(fence)) - return false; - - list_add_tail(&pt->active_list, &parent->active_list_head); return true; } @@ -238,7 +173,7 @@ static void timeline_fence_disable_signaling(struct fence *fence) { struct sync_pt *pt = container_of(fence, struct sync_pt, base); - list_del_init(&pt->active_list); + list_del_init(&pt->link); } static void timeline_fence_value_str(struct fence *fence, @@ -267,6 +202,107 @@ static const struct fence_ops timeline_fence_ops = { .timeline_value_str = timeline_fence_timeline_value_str, }; +/** + * sync_timeline_signal() - signal a status change on a sync_timeline + * @obj: sync_timeline to signal + * @inc: num to increment on timeline->value + * + * A sync implementation should call this any time one of it's fences + * has signaled or has an error condition. + */ +static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) +{ + struct sync_pt *pt, *next; + + trace_sync_timeline(obj); + + spin_lock_irq(&obj->lock); + + obj->value += inc; + + list_for_each_entry_safe(pt, next, &obj->pt_list, link) { + if (!timeline_fence_signaled(&pt->base)) + break; + + list_del_init(&pt->link); + rb_erase(&pt->node, &obj->pt_tree); + + /* + * A signal callback may release the last reference to this + * fence, causing it to be freed. That operation has to be + * last to avoid a use after free inside this loop, and must + * be after we remove the fence from the timeline in order to + * prevent deadlocking on timeline->lock inside + * timeline_fence_release(). + */ + fence_signal_locked(&pt->base); + } + + spin_unlock_irq(&obj->lock); +} + +/** + * sync_pt_create() - creates a sync pt + * @parent: fence's parent sync_timeline + * @inc: value of the fence + * + * Creates a new sync_pt as a child of @parent. @size bytes will be + * allocated allowing for implementation specific data to be kept after + * the generic sync_timeline struct. Returns the sync_pt object or + * NULL in case of error. + */ +static struct sync_pt *sync_pt_create(struct sync_timeline *obj, + unsigned int value) +{ + struct sync_pt *pt; + + pt = kzalloc(sizeof(*pt), GFP_KERNEL); + if (!pt) + return NULL; + + sync_timeline_get(obj); + fence_init(&pt->base, &timeline_fence_ops, &obj->lock, + obj->context, value); + INIT_LIST_HEAD(&pt->link); + + spin_lock_irq(&obj->lock); + if (!fence_is_signaled_locked(&pt->base)) { + struct rb_node **p = &obj->pt_tree.rb_node; + struct rb_node *parent = NULL; + + while (*p) { + struct sync_pt *other; + int cmp; + + parent = *p; + other = rb_entry(parent, typeof(*pt), node); + cmp = value - other->base.seqno; + if (cmp > 0) { + p = &parent->rb_right; + } else if (cmp < 0) { + p = &parent->rb_left; + } else { + if (fence_get_rcu(&other->base)) { + fence_put(&pt->base); + pt = other; + goto unlock; + } + p = &parent->rb_left; + } + } + rb_link_node(&pt->node, parent, p); + rb_insert_color(&pt->node, &obj->pt_tree); + + parent = rb_next(&pt->node); + list_add_tail(&pt->link, + parent ? &rb_entry(parent, typeof(*pt), node)->link : &obj->pt_list); + } +unlock: + spin_unlock_irq(&obj->lock); + + return pt; +} + /* * *WARNING* * @@ -293,8 +329,16 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) static int sw_sync_debugfs_release(struct inode *inode, struct file *file) { struct sync_timeline *obj = file->private_data; + struct sync_pt *pt, *next; + + spin_lock_irq(&obj->lock); + + list_for_each_entry_safe(pt, next, &obj->pt_list, link) { + fence_set_error(&pt->base, -ENOENT); + fence_signal_locked(&pt->base); + } - smp_wmb(); + spin_unlock_irq(&obj->lock); sync_timeline_put(obj); return 0; @@ -317,15 +361,15 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, goto err; } - pt = sync_pt_create(obj, sizeof(*pt), data.value); + pt = sync_pt_create(obj, data.value); if (!pt) { err = -ENOMEM; goto err; } sync_file = sync_file_create(&pt->base); + fence_put(&pt->base); if (!sync_file) { - fence_put(&pt->base); err = -ENOMEM; goto err; } @@ -353,6 +397,11 @@ static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) if (copy_from_user(&value, (void __user *)arg, sizeof(value))) return -EFAULT; + while (value > INT_MAX) { + sync_timeline_signal(obj, INT_MAX); + value -= INT_MAX; + } + sync_timeline_signal(obj, value); return 0; diff --git a/drivers/dma-buf/sync_debug.c b/drivers/dma-buf/sync_debug.c index 2dd4c3db6caa83ceff101bb5405baea8c2ef4874..858263dbecd4c38091d29e709008dadbf79fd052 100644 --- a/drivers/dma-buf/sync_debug.c +++ b/drivers/dma-buf/sync_debug.c @@ -62,29 +62,29 @@ void sync_file_debug_remove(struct sync_file *sync_file) static const char *sync_status_str(int status) { - if (status == 0) - return "signaled"; + if (status < 0) + return "error"; if (status > 0) - return "active"; + return "signaled"; - return "error"; + return "active"; } -static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show) +static void sync_print_fence(struct seq_file *s, + struct fence *fence, bool show) { - int status = 1; struct sync_timeline *parent = fence_parent(fence); + int status; - if (fence_is_signaled_locked(fence)) - status = fence->status; + status = fence_get_status_locked(fence); seq_printf(s, " %s%sfence %s", show ? parent->name : "", show ? "_" : "", sync_status_str(status)); - if (status <= 0) { + if (status) { struct timespec64 ts64 = ktime_to_timespec64(fence->timestamp); @@ -116,17 +116,15 @@ static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show) static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) { struct list_head *pos; - unsigned long flags; seq_printf(s, "%s: %d\n", obj->name, obj->value); - spin_lock_irqsave(&obj->child_list_lock, flags); - list_for_each(pos, &obj->child_list_head) { - struct sync_pt *pt = - container_of(pos, struct sync_pt, child_list); + spin_lock_irq(&obj->lock); + list_for_each(pos, &obj->pt_list) { + struct sync_pt *pt = container_of(pos, struct sync_pt, link); sync_print_fence(s, &pt->base, false); } - spin_unlock_irqrestore(&obj->child_list_lock, flags); + spin_unlock_irq(&obj->lock); } static void sync_print_sync_file(struct seq_file *s, @@ -135,7 +133,7 @@ static void sync_print_sync_file(struct seq_file *s, int i; seq_printf(s, "[%p] %s: %s\n", sync_file, sync_file->name, - sync_status_str(!fence_is_signaled(sync_file->fence))); + sync_status_str(fence_get_status(sync_file->fence))); if (fence_is_array(sync_file->fence)) { struct fence_array *array = to_fence_array(sync_file->fence); @@ -149,12 +147,11 @@ static void sync_print_sync_file(struct seq_file *s, static int sync_debugfs_show(struct seq_file *s, void *unused) { - unsigned long flags; struct list_head *pos; seq_puts(s, "objs:\n--------------\n"); - spin_lock_irqsave(&sync_timeline_list_lock, flags); + spin_lock_irq(&sync_timeline_list_lock); list_for_each(pos, &sync_timeline_list_head) { struct sync_timeline *obj = container_of(pos, struct sync_timeline, @@ -163,11 +160,11 @@ static int sync_debugfs_show(struct seq_file *s, void *unused) sync_print_obj(s, obj); seq_puts(s, "\n"); } - spin_unlock_irqrestore(&sync_timeline_list_lock, flags); + spin_unlock_irq(&sync_timeline_list_lock); seq_puts(s, "fences:\n--------------\n"); - spin_lock_irqsave(&sync_file_list_lock, flags); + spin_lock_irq(&sync_file_list_lock); list_for_each(pos, &sync_file_list_head) { struct sync_file *sync_file = container_of(pos, struct sync_file, sync_file_list); @@ -175,7 +172,7 @@ static int sync_debugfs_show(struct seq_file *s, void *unused) sync_print_sync_file(s, sync_file); seq_puts(s, "\n"); } - spin_unlock_irqrestore(&sync_file_list_lock, flags); + spin_unlock_irq(&sync_file_list_lock); return 0; } diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h index d269aa6783aaa57c3137ee93b02c72c620a6fd0f..9615dc0385b5830e1afcea441b658a6dfc26dc11 100644 --- a/drivers/dma-buf/sync_debug.h +++ b/drivers/dma-buf/sync_debug.h @@ -14,6 +14,7 @@ #define _LINUX_SYNC_H #include +#include #include #include @@ -24,43 +25,41 @@ * struct sync_timeline - sync object * @kref: reference count on fence. * @name: name of the sync_timeline. Useful for debugging - * @child_list_head: list of children sync_pts for this sync_timeline - * @child_list_lock: lock protecting @child_list_head and fence.status - * @active_list_head: list of active (unsignaled/errored) sync_pts + * @lock: lock protecting @pt_list and @value + * @pt_tree: rbtree of active (unsignaled/errored) sync_pts + * @pt_list: list of active (unsignaled/errored) sync_pts * @sync_timeline_list: membership in global sync_timeline_list */ struct sync_timeline { struct kref kref; char name[32]; - /* protected by child_list_lock */ + /* protected by lock */ u64 context; int value; - struct list_head child_list_head; - spinlock_t child_list_lock; - - struct list_head active_list_head; + struct rb_root pt_tree; + struct list_head pt_list; + spinlock_t lock; struct list_head sync_timeline_list; }; static inline struct sync_timeline *fence_parent(struct fence *fence) { - return container_of(fence->lock, struct sync_timeline, - child_list_lock); + return container_of(fence->lock, struct sync_timeline, lock); } /** * struct sync_pt - sync_pt object * @base: base fence object - * @child_list: sync timeline child's list - * @active_list: sync timeline active child's list + * @link: link on the sync timeline's list + * @node: node in the sync timeline's tree */ struct sync_pt { struct fence base; - struct list_head child_list; - struct list_head active_list; + struct list_head link; + struct rb_node node; }; #ifdef CONFIG_SW_SYNC diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 8a9cf9272fc90a0c612911952327b8c068cd90cc..7053bb489b18d509ffc9eae0ce5204e7f194cd0d 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -67,9 +67,10 @@ static void fence_check_cb_func(struct fence *f, struct fence_cb *cb) * sync_file_create() - creates a sync file * @fence: fence to add to the sync_fence * - * Creates a sync_file containg @fence. Once this is called, the sync_file - * takes ownership of @fence. The sync_file can be released with - * fput(sync_file->file). Returns the sync_file or NULL in case of error. + * Creates a sync_file containg @fence. This function acquires and additional + * reference of @fence for the newly-created &sync_file, if it succeeds. The + * sync_file can be released with fput(sync_file->file). Returns the + * sync_file or NULL in case of error. */ struct sync_file *sync_file_create(struct fence *fence) { @@ -79,7 +80,7 @@ struct sync_file *sync_file_create(struct fence *fence) if (!sync_file) return NULL; - sync_file->fence = fence; + sync_file->fence = fence_get(fence); snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d", fence->ops->get_driver_name(fence), @@ -90,13 +91,6 @@ struct sync_file *sync_file_create(struct fence *fence) } EXPORT_SYMBOL(sync_file_create); -/** - * sync_file_fdget() - get a sync_file from an fd - * @fd: fd referencing a fence - * - * Ensures @fd references a valid sync_file, increments the refcount of the - * backing file. Returns the sync_file or NULL in case of error. - */ static struct sync_file *sync_file_fdget(int fd) { struct file *file = fget(fd); @@ -291,7 +285,7 @@ static void sync_file_free(struct kref *kref) struct sync_file *sync_file = container_of(kref, struct sync_file, kref); - if (test_bit(POLL_ENABLED, &sync_file->fence->flags)) + if (test_bit(POLL_ENABLED, &sync_file->flags)) fence_remove_callback(sync_file->fence, &sync_file->cb); fence_put(sync_file->fence); kfree(sync_file); @@ -311,10 +305,9 @@ static unsigned int sync_file_poll(struct file *file, poll_table *wait) poll_wait(file, &sync_file->wq, wait); - if (!poll_does_not_wait(wait) && - !test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) { + if (!test_and_set_bit(POLL_ENABLED, &sync_file->flags)) { if (fence_add_callback(sync_file->fence, &sync_file->cb, - fence_check_cb_func) < 0) + fence_check_cb_func) < 0) wake_up_all(&sync_file->wq); } @@ -383,10 +376,8 @@ static void sync_fill_fence_info(struct fence *fence, sizeof(info->obj_name)); strlcpy(info->driver_name, fence->ops->get_driver_name(fence), sizeof(info->driver_name)); - if (fence_is_signaled(fence)) - info->status = fence->status >= 0 ? 1 : fence->status; - else - info->status = 0; + + info->status = fence_get_status(fence); info->timestamp_ns = ktime_to_ns(fence->timestamp); } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 141aefbe37ec93d1f4f38d1be5e2cf8d93266725..4e2379b6c71b8d508732f125e0cf9c7b2fba32af 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -422,6 +422,16 @@ config PXA_DMA 16 to 32 channels for peripheral to memory or memory to memory transfers. +config QCOM_SPS_DMA + tristate "Qualcomm technologies inc DMA driver for sps-BAM" + depends on ARCH_QCOM + select DMA_ENGINE + help + Enable support for Qualcomm technologies inc, BAM DMA engine. + This DMA-engine-driver is a wrapper of the sps-BAM library. DMA + engine callbacks are implemented using the sps-BAM functionality + to access HW. + config SIRF_DMA tristate "CSR SiRFprimaII/SiRFmarco DMA support" depends on ARCH_SIRF diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index e4dc9cac7ee8427184f821896364c232634a444f..2c19be4aca7507bf33e6dce8e63838ce75961ec4 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ZX_DMA) += zx296702_dma.o +obj-$(CONFIG_QCOM_SPS_DMA) += qcom-sps-dma.o obj-y += qcom/ obj-y += xilinx/ diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index e18dc596cf2447fa9ef7e41b62d9396e29043426..6204cc32d09c5096df8aec304c3c37b3bcb6be44 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -251,8 +251,11 @@ static void bcm2835_dma_create_cb_set_length( */ /* have we filled in period_length yet? */ - if (*total_len + control_block->length < period_len) + if (*total_len + control_block->length < period_len) { + /* update number of bytes in this period so far */ + *total_len += control_block->length; return; + } /* calculate the length that remains to reach period_length */ control_block->length = period_len - *total_len; diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 6b535262ac5d76972bb525b49f3cf160fcf54aa0..3db94e81bc14a8aa5f3b37d66bd56eb04e7f8d54 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1107,12 +1107,14 @@ static struct dmaengine_unmap_pool *__get_unmap_pool(int nr) switch (order) { case 0 ... 1: return &unmap_pool[0]; +#if IS_ENABLED(CONFIG_DMA_ENGINE_RAID) case 2 ... 4: return &unmap_pool[1]; case 5 ... 7: return &unmap_pool[2]; case 8: return &unmap_pool[3]; +#endif default: BUG(); return NULL; diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index cf76fc6149e5f40407397adcd82ee9dadc0f798b..e0bd578a253afe624678499cc87ffa5d33741b77 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -158,6 +158,12 @@ MODULE_PARM_DESC(run, "Run the test (default: false)"); #define PATTERN_OVERWRITE 0x20 #define PATTERN_COUNT_MASK 0x1f +/* poor man's completion - we want to use wait_event_freezable() on it */ +struct dmatest_done { + bool done; + wait_queue_head_t *wait; +}; + struct dmatest_thread { struct list_head node; struct dmatest_info *info; @@ -166,6 +172,8 @@ struct dmatest_thread { u8 **srcs; u8 **dsts; enum dma_transaction_type type; + wait_queue_head_t done_wait; + struct dmatest_done test_done; bool done; }; @@ -326,18 +334,25 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start, return error_count; } -/* poor man's completion - we want to use wait_event_freezable() on it */ -struct dmatest_done { - bool done; - wait_queue_head_t *wait; -}; static void dmatest_callback(void *arg) { struct dmatest_done *done = arg; - - done->done = true; - wake_up_all(done->wait); + struct dmatest_thread *thread = + container_of(arg, struct dmatest_thread, done_wait); + if (!thread->done) { + done->done = true; + wake_up_all(done->wait); + } else { + /* + * If thread->done, it means that this callback occurred + * after the parent thread has cleaned up. This can + * happen in the case that driver doesn't implement + * the terminate_all() functionality and a dma operation + * did not occur within the timeout period + */ + WARN(1, "dmatest: Kernel memory may be corrupted!!\n"); + } } static unsigned int min_odd(unsigned int x, unsigned int y) @@ -408,9 +423,8 @@ static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len) */ static int dmatest_func(void *data) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait); struct dmatest_thread *thread = data; - struct dmatest_done done = { .wait = &done_wait }; + struct dmatest_done *done = &thread->test_done; struct dmatest_info *info; struct dmatest_params *params; struct dma_chan *chan; @@ -637,9 +651,9 @@ static int dmatest_func(void *data) continue; } - done.done = false; + done->done = false; tx->callback = dmatest_callback; - tx->callback_param = &done; + tx->callback_param = done; cookie = tx->tx_submit(tx); if (dma_submit_error(cookie)) { @@ -652,20 +666,12 @@ static int dmatest_func(void *data) } dma_async_issue_pending(chan); - wait_event_freezable_timeout(done_wait, done.done, + wait_event_freezable_timeout(thread->done_wait, done->done, msecs_to_jiffies(params->timeout)); status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); - if (!done.done) { - /* - * We're leaving the timed out dma operation with - * dangling pointer to done_wait. To make this - * correct, we'll need to allocate wait_done for - * each test iteration and perform "who's gonna - * free it this time?" dancing. For now, just - * leave it dangling. - */ + if (!done->done) { dmaengine_unmap_put(um); result("test timed out", total_tests, src_off, dst_off, len, 0); @@ -746,7 +752,7 @@ static int dmatest_func(void *data) dmatest_KBs(runtime, total_len), ret); /* terminate all transfers on specified channels */ - if (ret) + if (ret || failed_tests) dmaengine_terminate_all(chan); thread->done = true; @@ -806,6 +812,8 @@ static int dmatest_add_threads(struct dmatest_info *info, thread->info = info; thread->chan = dtc->chan; thread->type = type; + thread->test_done.wait = &thread->done_wait; + init_waitqueue_head(&thread->done_wait); smp_wmb(); thread->task = kthread_create(dmatest_func, thread, "%s-%s%u", dma_chan_name(chan), op, i); diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 77242b37ef87866acf4681c0934c906ecb75de77..57962bff75324c75ff96f38cd3f9ab9b0703e0ec 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -1143,11 +1143,24 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( struct edma_desc *edesc; struct device *dev = chan->device->dev; struct edma_chan *echan = to_edma_chan(chan); - unsigned int width, pset_len; + unsigned int width, pset_len, array_size; if (unlikely(!echan || !len)) return NULL; + /* Align the array size (acnt block) with the transfer properties */ + switch (__ffs((src | dest | len))) { + case 0: + array_size = SZ_32K - 1; + break; + case 1: + array_size = SZ_32K - 2; + break; + default: + array_size = SZ_32K - 4; + break; + } + if (len < SZ_64K) { /* * Transfer size less than 64K can be handled with one paRAM @@ -1169,7 +1182,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( * When the full_length is multibple of 32767 one slot can be * used to complete the transfer. */ - width = SZ_32K - 1; + width = array_size; pset_len = rounddown(len, width); /* One slot is enough for lengths multiple of (SZ_32K -1) */ if (unlikely(pset_len == len)) @@ -1217,7 +1230,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_memcpy( } dest += pset_len; src += pset_len; - pset_len = width = len % (SZ_32K - 1); + pset_len = width = len % array_size; ret = edma_config_pset(chan, &edesc->pset[1], src, dest, 1, width, pset_len, DMA_MEM_TO_MEM); diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index d37e8dda807900fe9725aa153c20c1c2bc927a52..ec240592f5c8e7a450e2c26c20feece9d12dafad 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -201,6 +201,7 @@ struct ep93xx_dma_engine { struct dma_device dma_dev; bool m2m; int (*hw_setup)(struct ep93xx_dma_chan *); + void (*hw_synchronize)(struct ep93xx_dma_chan *); void (*hw_shutdown)(struct ep93xx_dma_chan *); void (*hw_submit)(struct ep93xx_dma_chan *); int (*hw_interrupt)(struct ep93xx_dma_chan *); @@ -323,6 +324,8 @@ static int m2p_hw_setup(struct ep93xx_dma_chan *edmac) | M2P_CONTROL_ENABLE; m2p_set_control(edmac, control); + edmac->buffer = 0; + return 0; } @@ -331,21 +334,27 @@ static inline u32 m2p_channel_state(struct ep93xx_dma_chan *edmac) return (readl(edmac->regs + M2P_STATUS) >> 4) & 0x3; } -static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac) +static void m2p_hw_synchronize(struct ep93xx_dma_chan *edmac) { + unsigned long flags; u32 control; + spin_lock_irqsave(&edmac->lock, flags); control = readl(edmac->regs + M2P_CONTROL); control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT); m2p_set_control(edmac, control); + spin_unlock_irqrestore(&edmac->lock, flags); while (m2p_channel_state(edmac) >= M2P_STATE_ON) - cpu_relax(); + schedule(); +} +static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac) +{ m2p_set_control(edmac, 0); - while (m2p_channel_state(edmac) == M2P_STATE_STALL) - cpu_relax(); + while (m2p_channel_state(edmac) != M2P_STATE_IDLE) + dev_warn(chan2dev(edmac), "M2P: Not yet IDLE\n"); } static void m2p_fill_desc(struct ep93xx_dma_chan *edmac) @@ -1160,6 +1169,26 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, return NULL; } +/** + * ep93xx_dma_synchronize - Synchronizes the termination of transfers to the + * current context. + * @chan: channel + * + * Synchronizes the DMA channel termination to the current context. When this + * function returns it is guaranteed that all transfers for previously issued + * descriptors have stopped and and it is safe to free the memory associated + * with them. Furthermore it is guaranteed that all complete callback functions + * for a previously submitted descriptor have finished running and it is safe to + * free resources accessed from within the complete callbacks. + */ +static void ep93xx_dma_synchronize(struct dma_chan *chan) +{ + struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); + + if (edmac->edma->hw_synchronize) + edmac->edma->hw_synchronize(edmac); +} + /** * ep93xx_dma_terminate_all - terminate all transactions * @chan: channel @@ -1323,6 +1352,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev) dma_dev->device_prep_slave_sg = ep93xx_dma_prep_slave_sg; dma_dev->device_prep_dma_cyclic = ep93xx_dma_prep_dma_cyclic; dma_dev->device_config = ep93xx_dma_slave_config; + dma_dev->device_synchronize = ep93xx_dma_synchronize; dma_dev->device_terminate_all = ep93xx_dma_terminate_all; dma_dev->device_issue_pending = ep93xx_dma_issue_pending; dma_dev->device_tx_status = ep93xx_dma_tx_status; @@ -1340,6 +1370,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev) } else { dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask); + edma->hw_synchronize = m2p_hw_synchronize; edma->hw_setup = m2p_hw_setup; edma->hw_shutdown = m2p_hw_shutdown; edma->hw_submit = m2p_hw_submit; diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h index 8e67895bcca3a2db74e5b72e00374e2118ce95f7..abcc51b343cecd1629700233e8ca9d8882da2dff 100644 --- a/drivers/dma/ioat/hw.h +++ b/drivers/dma/ioat/hw.h @@ -64,6 +64,8 @@ #define PCI_DEVICE_ID_INTEL_IOAT_BDX8 0x6f2e #define PCI_DEVICE_ID_INTEL_IOAT_BDX9 0x6f2f +#define PCI_DEVICE_ID_INTEL_IOAT_SKX 0x2021 + #define IOAT_VER_1_2 0x12 /* Version 1.2 */ #define IOAT_VER_2_0 0x20 /* Version 2.0 */ #define IOAT_VER_3_0 0x30 /* Version 3.0 */ diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index d235fbe2564f2692631635871c13dd130429f6b7..0dea6d55f0ff59d8727827ab52925fb3be5577a8 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -106,6 +106,8 @@ static struct pci_device_id ioat_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SKX) }, + /* I/OAT v3.3 platforms */ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) }, @@ -243,10 +245,15 @@ static bool is_bdx_ioat(struct pci_dev *pdev) } } +static inline bool is_skx_ioat(struct pci_dev *pdev) +{ + return (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SKX) ? true : false; +} + static bool is_xeon_cb32(struct pci_dev *pdev) { return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) || - is_hsw_ioat(pdev) || is_bdx_ioat(pdev); + is_hsw_ioat(pdev) || is_bdx_ioat(pdev) || is_skx_ioat(pdev); } bool is_bwd_ioat(struct pci_dev *pdev) @@ -1350,6 +1357,8 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) device->version = readb(device->reg_base + IOAT_VER_OFFSET); if (device->version >= IOAT_VER_3_0) { + if (is_skx_ioat(pdev)) + device->version = IOAT_VER_3_2; err = ioat3_dma_probe(device, ioat_dca_enabled); if (device->version >= IOAT_VER_3_3) diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index a28a01fcba674dc569e4d49ca6fd50def5a58645..f3e211f8f6c58c00080703f11b25937bb36dab39 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -161,6 +161,7 @@ struct mv_xor_v2_device { struct mv_xor_v2_sw_desc *sw_desq; int desc_size; unsigned int npendings; + unsigned int hw_queue_idx; }; /** @@ -213,18 +214,6 @@ static void mv_xor_v2_set_data_buffers(struct mv_xor_v2_device *xor_dev, } } -/* - * Return the next available index in the DESQ. - */ -static int mv_xor_v2_get_desq_write_ptr(struct mv_xor_v2_device *xor_dev) -{ - /* read the index for the next available descriptor in the DESQ */ - u32 reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ALLOC_OFF); - - return ((reg >> MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT) - & MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK); -} - /* * notify the engine of new descriptors, and update the available index. */ @@ -257,22 +246,6 @@ static int mv_xor_v2_set_desc_size(struct mv_xor_v2_device *xor_dev) return MV_XOR_V2_EXT_DESC_SIZE; } -/* - * Set the IMSG threshold - */ -static inline -void mv_xor_v2_set_imsg_thrd(struct mv_xor_v2_device *xor_dev, int thrd_val) -{ - u32 reg; - - reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF); - - reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); - reg |= (thrd_val << MV_XOR_V2_DMA_IMSG_THRD_SHIFT); - - writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF); -} - static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data) { struct mv_xor_v2_device *xor_dev = data; @@ -288,12 +261,6 @@ static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data) if (!ndescs) return IRQ_NONE; - /* - * Update IMSG threshold, to disable new IMSG interrupts until - * end of the tasklet - */ - mv_xor_v2_set_imsg_thrd(xor_dev, MV_XOR_V2_DESC_NUM); - /* schedule a tasklet to handle descriptors callbacks */ tasklet_schedule(&xor_dev->irq_tasklet); @@ -306,7 +273,6 @@ static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data) static dma_cookie_t mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx) { - int desq_ptr; void *dest_hw_desc; dma_cookie_t cookie; struct mv_xor_v2_sw_desc *sw_desc = @@ -322,15 +288,15 @@ mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx) spin_lock_bh(&xor_dev->lock); cookie = dma_cookie_assign(tx); - /* get the next available slot in the DESQ */ - desq_ptr = mv_xor_v2_get_desq_write_ptr(xor_dev); - /* copy the HW descriptor from the SW descriptor to the DESQ */ - dest_hw_desc = xor_dev->hw_desq_virt + desq_ptr; + dest_hw_desc = xor_dev->hw_desq_virt + xor_dev->hw_queue_idx; memcpy(dest_hw_desc, &sw_desc->hw_desc, xor_dev->desc_size); xor_dev->npendings++; + xor_dev->hw_queue_idx++; + if (xor_dev->hw_queue_idx >= MV_XOR_V2_DESC_NUM) + xor_dev->hw_queue_idx = 0; spin_unlock_bh(&xor_dev->lock); @@ -344,6 +310,7 @@ static struct mv_xor_v2_sw_desc * mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev) { struct mv_xor_v2_sw_desc *sw_desc; + bool found = false; /* Lock the channel */ spin_lock_bh(&xor_dev->lock); @@ -355,19 +322,23 @@ mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev) return NULL; } - /* get a free SW descriptor from the SW DESQ */ - sw_desc = list_first_entry(&xor_dev->free_sw_desc, - struct mv_xor_v2_sw_desc, free_list); + list_for_each_entry(sw_desc, &xor_dev->free_sw_desc, free_list) { + if (async_tx_test_ack(&sw_desc->async_tx)) { + found = true; + break; + } + } + + if (!found) { + spin_unlock_bh(&xor_dev->lock); + return NULL; + } + list_del(&sw_desc->free_list); /* Release the channel */ spin_unlock_bh(&xor_dev->lock); - /* set the async tx descriptor */ - dma_async_tx_descriptor_init(&sw_desc->async_tx, &xor_dev->dmachan); - sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit; - async_tx_ack(&sw_desc->async_tx); - return sw_desc; } @@ -389,6 +360,8 @@ mv_xor_v2_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, __func__, len, &src, &dest, flags); sw_desc = mv_xor_v2_prep_sw_desc(xor_dev); + if (!sw_desc) + return NULL; sw_desc->async_tx.flags = flags; @@ -443,6 +416,8 @@ mv_xor_v2_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, __func__, src_cnt, len, &dest, flags); sw_desc = mv_xor_v2_prep_sw_desc(xor_dev); + if (!sw_desc) + return NULL; sw_desc->async_tx.flags = flags; @@ -491,6 +466,8 @@ mv_xor_v2_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags) container_of(chan, struct mv_xor_v2_device, dmachan); sw_desc = mv_xor_v2_prep_sw_desc(xor_dev); + if (!sw_desc) + return NULL; /* set the HW descriptor */ hw_descriptor = &sw_desc->hw_desc; @@ -554,7 +531,6 @@ static void mv_xor_v2_tasklet(unsigned long data) { struct mv_xor_v2_device *xor_dev = (struct mv_xor_v2_device *) data; int pending_ptr, num_of_pending, i; - struct mv_xor_v2_descriptor *next_pending_hw_desc = NULL; struct mv_xor_v2_sw_desc *next_pending_sw_desc = NULL; dev_dbg(xor_dev->dmadev.dev, "%s %d\n", __func__, __LINE__); @@ -562,17 +538,10 @@ static void mv_xor_v2_tasklet(unsigned long data) /* get the pending descriptors parameters */ num_of_pending = mv_xor_v2_get_pending_params(xor_dev, &pending_ptr); - /* next HW descriptor */ - next_pending_hw_desc = xor_dev->hw_desq_virt + pending_ptr; - /* loop over free descriptors */ for (i = 0; i < num_of_pending; i++) { - - if (pending_ptr > MV_XOR_V2_DESC_NUM) - pending_ptr = 0; - - if (next_pending_sw_desc != NULL) - next_pending_hw_desc++; + struct mv_xor_v2_descriptor *next_pending_hw_desc = + xor_dev->hw_desq_virt + pending_ptr; /* get the SW descriptor related to the HW descriptor */ next_pending_sw_desc = @@ -608,15 +577,14 @@ static void mv_xor_v2_tasklet(unsigned long data) /* increment the next descriptor */ pending_ptr++; + if (pending_ptr >= MV_XOR_V2_DESC_NUM) + pending_ptr = 0; } if (num_of_pending != 0) { /* free the descriptores */ mv_xor_v2_free_desc_from_desq(xor_dev, num_of_pending); } - - /* Update IMSG threshold, to enable new IMSG interrupts */ - mv_xor_v2_set_imsg_thrd(xor_dev, 0); } /* @@ -648,9 +616,6 @@ static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev) writel((xor_dev->hw_desq & 0xFFFF00000000) >> 32, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BAHR_OFF); - /* enable the DMA engine */ - writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF); - /* * This is a temporary solution, until we activate the * SMMU. Set the attributes for reading & writing data buffers @@ -694,6 +659,9 @@ static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev) reg |= MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL; writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE); + /* enable the DMA engine */ + writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF); + return 0; } @@ -725,6 +693,10 @@ static int mv_xor_v2_probe(struct platform_device *pdev) platform_set_drvdata(pdev, xor_dev); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (ret) + return ret; + xor_dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) return -EPROBE_DEFER; @@ -785,8 +757,15 @@ static int mv_xor_v2_probe(struct platform_device *pdev) /* add all SW descriptors to the free list */ for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) { - xor_dev->sw_desq[i].idx = i; - list_add(&xor_dev->sw_desq[i].free_list, + struct mv_xor_v2_sw_desc *sw_desc = + xor_dev->sw_desq + i; + sw_desc->idx = i; + dma_async_tx_descriptor_init(&sw_desc->async_tx, + &xor_dev->dmachan); + sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit; + async_tx_ack(&sw_desc->async_tx); + + list_add(&sw_desc->free_list, &xor_dev->free_sw_desc); } diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 9f3dbc8c63d27e733aadc975ca90a74328513333..fb2e7476d96b448d577d657940e32b1bd11e4282 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1694,7 +1694,6 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i) static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) { struct pl330_thread *thrd = NULL; - unsigned long flags; int chans, i; if (pl330->state == DYING) @@ -1702,8 +1701,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) chans = pl330->pcfg.num_chan; - spin_lock_irqsave(&pl330->lock, flags); - for (i = 0; i < chans; i++) { thrd = &pl330->channels[i]; if ((thrd->free) && (!_manager_ns(thrd) || @@ -1721,8 +1718,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) thrd = NULL; } - spin_unlock_irqrestore(&pl330->lock, flags); - return thrd; } @@ -1740,7 +1735,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev) static void pl330_release_channel(struct pl330_thread *thrd) { struct pl330_dmac *pl330; - unsigned long flags; if (!thrd || thrd->free) return; @@ -1752,10 +1746,8 @@ static void pl330_release_channel(struct pl330_thread *thrd) pl330 = thrd->dmac; - spin_lock_irqsave(&pl330->lock, flags); _free_event(thrd, thrd->ev); thrd->free = true; - spin_unlock_irqrestore(&pl330->lock, flags); } /* Initialize the structure for PL330 configuration, that can be used @@ -2120,20 +2112,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; - spin_lock_irqsave(&pch->lock, flags); + spin_lock_irqsave(&pl330->lock, flags); dma_cookie_init(chan); pch->cyclic = false; pch->thread = pl330_request_channel(pl330); if (!pch->thread) { - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pl330->lock, flags); return -ENOMEM; } tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch); - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pl330->lock, flags); return 1; } @@ -2236,12 +2228,13 @@ static int pl330_pause(struct dma_chan *chan) static void pl330_free_chan_resources(struct dma_chan *chan) { struct dma_pl330_chan *pch = to_pchan(chan); + struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; tasklet_kill(&pch->task); pm_runtime_get_sync(pch->dmac->ddma.dev); - spin_lock_irqsave(&pch->lock, flags); + spin_lock_irqsave(&pl330->lock, flags); pl330_release_channel(pch->thread); pch->thread = NULL; @@ -2249,7 +2242,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) if (pch->cyclic) list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pl330->lock, flags); pm_runtime_mark_last_busy(pch->dmac->ddma.dev); pm_runtime_put_autosuspend(pch->dmac->ddma.dev); } diff --git a/drivers/dma/qcom-sps-dma.c b/drivers/dma/qcom-sps-dma.c new file mode 100644 index 0000000000000000000000000000000000000000..d9fd653fd1ffc31600fd0221efc663c407f84611 --- /dev/null +++ b/drivers/dma/qcom-sps-dma.c @@ -0,0 +1,721 @@ +/* + * Copyright (c) 2014-2015,2017, 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. + * + */ + +/* + * Qualcomm technologies inc, DMA API for BAM (Bus Access Manager). + * This DMA driver uses sps-BAM API to access the HW, thus it is effectively a + * DMA engine wrapper of the sps-BAM API. + * + * Client channel configuration example: + * struct dma_slave_config config { + * .direction = DMA_MEM_TO_DEV; + * }; + * + * chan = dma_request_slave_channel(client_dev, "rx"); + * dmaengine_slave_config(chan, &config); + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dmaengine.h" + +#define QBAM_OF_SLAVE_N_ARGS (4) +#define QBAM_OF_MANAGE_LOCAL "qcom,managed-locally" +#define QBAM_OF_SUM_THRESHOLD "qcom,summing-threshold" +#define QBAM_MAX_DESCRIPTORS (0x100) +#define QBAM_MAX_CHANNELS (32) + +/* + * qbam_async_tx_descriptor - dma descriptor plus a list of xfer_bufs + * + * @sgl scatterlist of transfer buffers + * @sg_len size of that list + * @flags dma xfer flags + */ +struct qbam_async_tx_descriptor { + struct dma_async_tx_descriptor dma_desc; + struct scatterlist *sgl; + unsigned int sg_len; + unsigned long flags; +}; + +#define DMA_TO_QBAM_ASYNC_DESC(dma_async_desc) \ + container_of(dma_async_desc, struct qbam_async_tx_descriptor, dma_desc) + +struct qbam_channel; +/* + * qbam_device - top level device of current driver + * @handle bam sps handle. + * @regs bam register space virtual base address. + * @mem_resource bam register space resource. + * @deregister_required if bam is registered by this driver it need to be + * unregistered by this driver. + * @manage is bame managed locally or remotely, + * @summing_threshold event threshold. + * @irq bam interrupt line. + * @channels has the same channels as qbam_dev->dma_dev.channels but + * supports fast access by pipe index. + */ +struct qbam_device { + struct dma_device dma_dev; + void __iomem *regs; + struct resource *mem_resource; + ulong handle; + bool deregister_required; + u32 summing_threshold; + u32 manage; + int irq; + struct qbam_channel *channels[QBAM_MAX_CHANNELS]; +}; + +/* qbam_pipe: aggregate of bam pipe related entries of qbam_channel */ +struct qbam_pipe { + u32 index; + struct sps_pipe *handle; + struct sps_connect cfg; + u32 num_descriptors; + u32 sps_connect_flags; + u32 sps_register_event_flags; +}; + +/* + * qbam_channel - dma channel plus bam pipe info and current pending transfers + * + * @direction is a producer or consumer (MEM => DEV or DEV => MEM) + * @pending_desc next set of transfer to process + * @error last error that took place on the current pending_desc + */ +struct qbam_channel { + struct qbam_pipe bam_pipe; + + struct dma_chan chan; + enum dma_transfer_direction direction; + struct qbam_async_tx_descriptor pending_desc; + + struct qbam_device *qbam_dev; + struct mutex lock; + int error; +}; +#define DMA_TO_QBAM_CHAN(dma_chan) \ + container_of(dma_chan, struct qbam_channel, chan) +#define qbam_err(qbam_dev, fmt ...) dev_err(qbam_dev->dma_dev.dev, fmt) + +/* qbam_disconnect_chan - disconnect a channel */ +static int qbam_disconnect_chan(struct qbam_channel *qbam_chan) +{ + struct qbam_device *qbam_dev = qbam_chan->qbam_dev; + struct sps_pipe *pipe_handle = qbam_chan->bam_pipe.handle; + struct sps_connect pipe_config_no_irq = {.options = SPS_O_POLL}; + int ret; + + /* + * SW workaround: + * When disconnecting BAM pipe a spurious interrupt sometimes appears. + * To avoid that, we change the pipe setting from interrupt (default) + * to polling (SPS_O_POLL) before diconnecting the pipe. + */ + ret = sps_set_config(pipe_handle, &pipe_config_no_irq); + if (ret) + qbam_err(qbam_dev, + "error:%d sps_set_config(pipe:%d) before disconnect\n", + ret, qbam_chan->bam_pipe.index); + + ret = sps_disconnect(pipe_handle); + if (ret) + qbam_err(qbam_dev, "error:%d sps_disconnect(pipe:%d)\n", + ret, qbam_chan->bam_pipe.index); + + return ret; +} + +/* qbam_free_chan - disconnect channel and free its resources */ +static void qbam_free_chan(struct dma_chan *chan) +{ + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(chan); + struct qbam_device *qbam_dev = qbam_chan->qbam_dev; + + mutex_lock(&qbam_chan->lock); + if (qbam_disconnect_chan(qbam_chan)) + qbam_err(qbam_dev, + "error free_chan() failed to disconnect(pipe:%d)\n", + qbam_chan->bam_pipe.index); + qbam_chan->pending_desc.sgl = NULL; + qbam_chan->pending_desc.sg_len = 0; + mutex_unlock(&qbam_chan->lock); +} + +static struct dma_chan *qbam_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *of) +{ + struct qbam_device *qbam_dev = of->of_dma_data; + struct qbam_channel *qbam_chan; + u32 channel_index; + u32 num_descriptors; + + if (dma_spec->args_count != QBAM_OF_SLAVE_N_ARGS) { + qbam_err(qbam_dev, + "invalid number of dma arguments, expect:%d got:%d\n", + QBAM_OF_SLAVE_N_ARGS, dma_spec->args_count); + return NULL; + }; + + channel_index = dma_spec->args[0]; + + if (channel_index >= QBAM_MAX_CHANNELS) { + qbam_err(qbam_dev, + "error: channel_index:%d out of bounds", + channel_index); + return NULL; + } + qbam_chan = qbam_dev->channels[channel_index]; + /* return qbam_chan if exists, or create one */ + if (qbam_chan) { + qbam_chan->chan.client_count = 1; + return &qbam_chan->chan; + } + + num_descriptors = dma_spec->args[1]; + if (!num_descriptors || (num_descriptors > QBAM_MAX_DESCRIPTORS)) { + qbam_err(qbam_dev, + "invalid number of descriptors, range[1..%d] got:%d\n", + QBAM_MAX_DESCRIPTORS, num_descriptors); + return NULL; + } + + /* allocate a channel */ + qbam_chan = kzalloc(sizeof(*qbam_chan), GFP_KERNEL); + if (!qbam_chan) + return NULL; + + /* allocate BAM resources for that channel */ + qbam_chan->bam_pipe.handle = sps_alloc_endpoint(); + if (!qbam_chan->bam_pipe.handle) { + qbam_err(qbam_dev, "error: sps_alloc_endpoint() return NULL\n"); + kfree(qbam_chan); + return NULL; + } + + /* init dma_chan */ + qbam_chan->chan.device = &qbam_dev->dma_dev; + dma_cookie_init(&qbam_chan->chan); + qbam_chan->chan.client_count = 1; + /* init qbam_chan */ + qbam_chan->bam_pipe.index = channel_index; + qbam_chan->bam_pipe.num_descriptors = num_descriptors; + qbam_chan->bam_pipe.sps_connect_flags = dma_spec->args[2]; + qbam_chan->bam_pipe.sps_register_event_flags = dma_spec->args[3]; + qbam_chan->qbam_dev = qbam_dev; + mutex_init(&qbam_chan->lock); + + /* add to dma_device list of channels */ + list_add(&qbam_chan->chan.device_node, &qbam_dev->dma_dev.channels); + qbam_dev->channels[channel_index] = qbam_chan; + + return &qbam_chan->chan; +} + +static enum dma_status qbam_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(chan); + struct qbam_async_tx_descriptor *qbam_desc = &qbam_chan->pending_desc; + enum dma_status ret; + + mutex_lock(&qbam_chan->lock); + + if (qbam_chan->error) { + mutex_unlock(&qbam_chan->lock); + return DMA_ERROR; + } + + ret = dma_cookie_status(chan, cookie, state); + if (ret == DMA_IN_PROGRESS) { + struct scatterlist *sg; + int i; + u32 transfer_size = 0; + + for_each_sg(qbam_desc->sgl, sg, qbam_desc->sg_len, i) + transfer_size += sg_dma_len(sg); + + dma_set_residue(state, transfer_size); + } + mutex_unlock(&qbam_chan->lock); + + return ret; +} + +/* + * qbam_init_bam_handle - find or create bam handle. + * + * BAM device needs to be registered for each BLSP once and only once. if it + * was registered, then we find the handle to the registered bam and return + * it, otherwise we register it here. + * The module which registered BAM is responsible for deregistering it. + */ +static int qbam_init_bam_handle(struct qbam_device *qbam_dev) +{ + int ret = 0; + struct sps_bam_props bam_props = {0}; + + /* + * Check if BAM is already registred with SPS on the current + * BLSP. If it isn't then go ahead and register it. + */ + ret = sps_phy2h(qbam_dev->mem_resource->start, &qbam_dev->handle); + if (qbam_dev->handle) + return 0; + + qbam_dev->regs = devm_ioremap_resource(qbam_dev->dma_dev.dev, + qbam_dev->mem_resource); + if (IS_ERR(qbam_dev->regs)) { + qbam_err(qbam_dev, "error:%ld ioremap(phy:0x%lx len:0x%lx)\n", + PTR_ERR(qbam_dev->regs), + (ulong) qbam_dev->mem_resource->start, + (ulong) resource_size(qbam_dev->mem_resource)); + return PTR_ERR(qbam_dev->regs); + }; + + bam_props.phys_addr = qbam_dev->mem_resource->start; + bam_props.virt_addr = qbam_dev->regs; + bam_props.summing_threshold = qbam_dev->summing_threshold; + bam_props.manage = qbam_dev->manage; + bam_props.irq = qbam_dev->irq; + + ret = sps_register_bam_device(&bam_props, &qbam_dev->handle); + if (ret) + qbam_err(qbam_dev, "error:%d sps_register_bam_device\n" + "(phy:0x%lx virt:0x%lx irq:%d)\n", + ret, (ulong) bam_props.phys_addr, + (ulong) bam_props.virt_addr, qbam_dev->irq); + else + qbam_dev->deregister_required = true; + + return ret; +} + + +static int qbam_alloc_chan(struct dma_chan *chan) +{ + return 0; +} + +static void qbam_eot_callback(struct sps_event_notify *notify) +{ + struct qbam_async_tx_descriptor *qbam_desc = notify->data.transfer.user; + struct dma_async_tx_descriptor *dma_desc = &qbam_desc->dma_desc; + dma_async_tx_callback callback = dma_desc->callback; + void *param = dma_desc->callback_param; + + if (callback) + callback(param); +} + +static void qbam_error_callback(struct sps_event_notify *notify) +{ + struct qbam_channel *qbam_chan = notify->user; + + qbam_err(qbam_chan->qbam_dev, "error: qbam_error_callback(pipe:%d\n)", + qbam_chan->bam_pipe.index); +} + +static int qbam_connect_chan(struct qbam_channel *qbam_chan) +{ + int ret = 0; + struct qbam_device *qbam_dev = qbam_chan->qbam_dev; + struct sps_register_event bam_eot_event = { + .mode = SPS_TRIGGER_CALLBACK, + .options = qbam_chan->bam_pipe.sps_register_event_flags, + .callback = qbam_eot_callback, + }; + struct sps_register_event bam_error_event = { + .mode = SPS_TRIGGER_CALLBACK, + .options = SPS_O_ERROR, + .callback = qbam_error_callback, + .user = qbam_chan, + }; + + ret = sps_connect(qbam_chan->bam_pipe.handle, &qbam_chan->bam_pipe.cfg); + if (ret) { + qbam_err(qbam_dev, "error:%d sps_connect(pipe:%d)\n", ret, + qbam_chan->bam_pipe.index); + return ret; + } + + ret = sps_register_event(qbam_chan->bam_pipe.handle, &bam_eot_event); + if (ret) { + qbam_err(qbam_dev, "error:%d sps_register_event(eot@pipe:%d)\n", + ret, qbam_chan->bam_pipe.index); + goto need_disconnect; + } + + ret = sps_register_event(qbam_chan->bam_pipe.handle, &bam_error_event); + if (ret) { + qbam_err(qbam_dev, "error:%d sps_register_event(err@pipe:%d)\n", + ret, qbam_chan->bam_pipe.index); + goto need_disconnect; + } + + return 0; + +need_disconnect: + ret = sps_disconnect(qbam_chan->bam_pipe.handle); + if (ret) + qbam_err(qbam_dev, "error:%d sps_disconnect(pipe:%d)\n", ret, + qbam_chan->bam_pipe.index); + return ret; +} + +/* + * qbam_slave_cfg - configure and connect a BAM pipe + * + * @cfg only cares about cfg->direction + */ +static int qbam_slave_cfg(struct dma_chan *chan, + struct dma_slave_config *cfg) +{ + int ret = 0; + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(chan); + struct qbam_device *qbam_dev = qbam_chan->qbam_dev; + struct sps_connect *pipe_cfg = &qbam_chan->bam_pipe.cfg; + + if (!qbam_dev->handle) { + ret = qbam_init_bam_handle(qbam_dev); + if (ret) + return ret; + } + + if (qbam_chan->bam_pipe.cfg.desc.base) + goto cfg_done; + + ret = sps_get_config(qbam_chan->bam_pipe.handle, + &qbam_chan->bam_pipe.cfg); + if (ret) { + qbam_err(qbam_dev, "error:%d sps_get_config(0x%p)\n", + ret, qbam_chan->bam_pipe.handle); + return ret; + } + + qbam_chan->direction = cfg->direction; + if (cfg->direction == DMA_MEM_TO_DEV) { + pipe_cfg->source = SPS_DEV_HANDLE_MEM; + pipe_cfg->destination = qbam_dev->handle; + pipe_cfg->mode = SPS_MODE_DEST; + pipe_cfg->src_pipe_index = 0; + pipe_cfg->dest_pipe_index = qbam_chan->bam_pipe.index; + } else { + pipe_cfg->source = qbam_dev->handle; + pipe_cfg->destination = SPS_DEV_HANDLE_MEM; + pipe_cfg->mode = SPS_MODE_SRC; + pipe_cfg->src_pipe_index = qbam_chan->bam_pipe.index; + pipe_cfg->dest_pipe_index = 0; + } + pipe_cfg->options = qbam_chan->bam_pipe.sps_connect_flags; + pipe_cfg->desc.size = (qbam_chan->bam_pipe.num_descriptors + 1) * + sizeof(struct sps_iovec); + /* managed dma_alloc_coherent() */ + pipe_cfg->desc.base = dmam_alloc_coherent(qbam_dev->dma_dev.dev, + pipe_cfg->desc.size, + &pipe_cfg->desc.phys_base, + GFP_KERNEL); + if (!pipe_cfg->desc.base) { + qbam_err(qbam_dev, + "error dma_alloc_coherent(desc-sz:%llu * n-descs:%d)\n", + (u64) sizeof(struct sps_iovec), + qbam_chan->bam_pipe.num_descriptors); + return -ENOMEM; + } +cfg_done: + ret = qbam_connect_chan(qbam_chan); + if (ret) + dmam_free_coherent(qbam_dev->dma_dev.dev, pipe_cfg->desc.size, + pipe_cfg->desc.base, pipe_cfg->desc.phys_base); + + return ret; +} + +static int qbam_flush_chan(struct dma_chan *chan) +{ + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(chan); + int ret = qbam_disconnect_chan(qbam_chan); + + if (ret) { + qbam_err(qbam_chan->qbam_dev, + "error: disconnect flush(pipe:%d\n)", + qbam_chan->bam_pipe.index); + return ret; + } + ret = qbam_connect_chan(qbam_chan); + if (ret) + qbam_err(qbam_chan->qbam_dev, + "error: reconnect flush(pipe:%d\n)", + qbam_chan->bam_pipe.index); + return ret; +} + +/* qbam_tx_submit - sets the descriptor as the next one to be executed */ +static dma_cookie_t qbam_tx_submit(struct dma_async_tx_descriptor *dma_desc) +{ + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(dma_desc->chan); + dma_cookie_t ret; + + mutex_lock(&qbam_chan->lock); + + ret = dma_cookie_assign(dma_desc); + + mutex_unlock(&qbam_chan->lock); + + return ret; +} + +/* + * qbam_prep_slave_sg - creates qbam_xfer_buf from a list of sg + * + * @chan: dma channel + * @sgl: scatter gather list + * @sg_len: length of sg + * @direction: DMA transfer direction + * @flags: DMA flags + * @context: transfer context (unused) + * @return the newly created descriptor or negative ERR_PTR() on error + */ +static struct dma_async_tx_descriptor *qbam_prep_slave_sg(struct dma_chan *chan, + struct scatterlist *sgl, unsigned int sg_len, + enum dma_transfer_direction direction, unsigned long flags, + void *context) +{ + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(chan); + struct qbam_device *qbam_dev = qbam_chan->qbam_dev; + struct qbam_async_tx_descriptor *qbam_desc = &qbam_chan->pending_desc; + + if (qbam_chan->direction != direction) { + qbam_err(qbam_dev, + "invalid dma transfer direction expected:%d given:%d\n", + qbam_chan->direction, direction); + return ERR_PTR(-EINVAL); + } + + qbam_desc->dma_desc.chan = &qbam_chan->chan; + qbam_desc->dma_desc.tx_submit = qbam_tx_submit; + qbam_desc->sgl = sgl; + qbam_desc->sg_len = sg_len; + qbam_desc->flags = flags; + return &qbam_desc->dma_desc; +} + +/* + * qbam_issue_pending - queue pending descriptor to BAM + * + * Iterate over the transfers of the pending descriptor and push them to bam + */ +static void qbam_issue_pending(struct dma_chan *chan) +{ + int i; + int ret = 0; + struct qbam_channel *qbam_chan = DMA_TO_QBAM_CHAN(chan); + struct qbam_device *qbam_dev = qbam_chan->qbam_dev; + struct qbam_async_tx_descriptor *qbam_desc = &qbam_chan->pending_desc; + struct scatterlist *sg; + + mutex_lock(&qbam_chan->lock); + if (!qbam_chan->pending_desc.sgl) { + qbam_err(qbam_dev, + "error qbam_issue_pending() no pending descriptor pipe:%d\n", + qbam_chan->bam_pipe.index); + mutex_unlock(&qbam_chan->lock); + return; + } + + for_each_sg(qbam_desc->sgl, sg, qbam_desc->sg_len, i) { + + /* Add BAM flags only on the last buffer */ + bool is_last_buf = (i == ((qbam_desc->sg_len) - 1)); + + ret = sps_transfer_one(qbam_chan->bam_pipe.handle, + sg_dma_address(sg), sg_dma_len(sg), + qbam_desc, + (is_last_buf ? qbam_desc->flags : 0)); + if (ret < 0) { + qbam_chan->error = ret; + + qbam_err(qbam_dev, "erorr:%d sps_transfer_one\n" + "(addr:0x%lx len:%d flags:0x%lx pipe:%d)\n", + ret, (ulong) sg_dma_address(sg), sg_dma_len(sg), + qbam_desc->flags, qbam_chan->bam_pipe.index); + break; + } + } + + dma_cookie_complete(&qbam_desc->dma_desc); + qbam_chan->error = 0; + qbam_desc->sgl = NULL; + qbam_desc->sg_len = 0; + mutex_unlock(&qbam_chan->lock); +}; + +static int qbam_deregister_bam_dev(struct qbam_device *qbam_dev) +{ + int ret; + + if (!qbam_dev->handle) + return 0; + + ret = sps_deregister_bam_device(qbam_dev->handle); + if (ret) + qbam_err(qbam_dev, + "error:%d sps_deregister_bam_device(hndl:0x%lx) failed", + ret, qbam_dev->handle); + return ret; +} + +static void qbam_pipes_free(struct qbam_device *qbam_dev) +{ + struct qbam_channel *qbam_chan_cur, *qbam_chan_next; + + list_for_each_entry_safe(qbam_chan_cur, qbam_chan_next, + &qbam_dev->dma_dev.channels, chan.device_node) { + mutex_lock(&qbam_chan_cur->lock); + qbam_free_chan(&qbam_chan_cur->chan); + sps_free_endpoint(qbam_chan_cur->bam_pipe.handle); + list_del(&qbam_chan_cur->chan.device_node); + mutex_unlock(&qbam_chan_cur->lock); + kfree(qbam_chan_cur); + } +} + +static int qbam_probe(struct platform_device *pdev) +{ + struct qbam_device *qbam_dev; + int ret; + bool managed_locally; + struct device_node *of_node = pdev->dev.of_node; + + qbam_dev = devm_kzalloc(&pdev->dev, sizeof(*qbam_dev), GFP_KERNEL); + if (!qbam_dev) + return -ENOMEM; + + qbam_dev->dma_dev.dev = &pdev->dev; + platform_set_drvdata(pdev, qbam_dev); + + qbam_dev->mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!qbam_dev->mem_resource) { + qbam_err(qbam_dev, "missing 'reg' DT entry"); + return -ENODEV; + } + + qbam_dev->irq = platform_get_irq(pdev, 0); + if (qbam_dev->irq < 0) { + qbam_err(qbam_dev, "missing DT IRQ resource entry"); + return -EINVAL; + } + + ret = of_property_read_u32(of_node, QBAM_OF_SUM_THRESHOLD, + &qbam_dev->summing_threshold); + if (ret) { + qbam_err(qbam_dev, "missing '%s' DT entry", + QBAM_OF_SUM_THRESHOLD); + return ret; + } + + /* read from DT and set sps_bam_props.manage */ + managed_locally = of_property_read_bool(of_node, QBAM_OF_MANAGE_LOCAL); + qbam_dev->manage = managed_locally ? SPS_BAM_MGR_LOCAL : + SPS_BAM_MGR_DEVICE_REMOTE; + + /* Init channels */ + INIT_LIST_HEAD(&qbam_dev->dma_dev.channels); + + /* Set capabilities */ + dma_cap_zero(qbam_dev->dma_dev.cap_mask); + dma_cap_set(DMA_SLAVE, qbam_dev->dma_dev.cap_mask); + dma_cap_set(DMA_PRIVATE, qbam_dev->dma_dev.cap_mask); + + /* Initialize dmaengine callback apis */ + qbam_dev->dma_dev.device_alloc_chan_resources = qbam_alloc_chan; + qbam_dev->dma_dev.device_free_chan_resources = qbam_free_chan; + qbam_dev->dma_dev.device_prep_slave_sg = qbam_prep_slave_sg; + qbam_dev->dma_dev.device_terminate_all = qbam_flush_chan; + qbam_dev->dma_dev.device_config = qbam_slave_cfg; + qbam_dev->dma_dev.device_issue_pending = qbam_issue_pending; + qbam_dev->dma_dev.device_tx_status = qbam_tx_status; + + /* Regiser to DMA framework */ + dma_async_device_register(&qbam_dev->dma_dev); + + /* + * Do not return error in order to not break the existing + * way of requesting channels. + */ + ret = of_dma_controller_register(of_node, qbam_dma_xlate, qbam_dev); + if (ret) { + qbam_err(qbam_dev, "error:%d of_dma_controller_register()\n", + ret); + goto err_unregister_dma; + } + return 0; + +err_unregister_dma: + dma_async_device_unregister(&qbam_dev->dma_dev); + if (qbam_dev->deregister_required) + return qbam_deregister_bam_dev(qbam_dev); + + return ret; +} + +static int qbam_remove(struct platform_device *pdev) +{ + struct qbam_device *qbam_dev = platform_get_drvdata(pdev); + + dma_async_device_unregister(&qbam_dev->dma_dev); + + /* free BAM pipes resources */ + qbam_pipes_free(qbam_dev); + + if (qbam_dev->deregister_required) + return qbam_deregister_bam_dev(qbam_dev); + + return 0; +} + +static const struct of_device_id qbam_of_match[] = { + { .compatible = "qcom,sps-dma" }, + {} +}; +MODULE_DEVICE_TABLE(of, qbam_of_match); + +static struct platform_driver qbam_driver = { + .probe = qbam_probe, + .remove = qbam_remove, + .driver = { + .name = "qcom-sps-dma", + .owner = THIS_MODULE, + .of_match_table = qbam_of_match, + }, +}; + +module_platform_driver(qbam_driver); + +MODULE_DESCRIPTION("DMA-API driver to qcom BAM"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-sps-dma"); diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig index a7761c4025f4151a8488c25adedd8e5f37f3d3b4..2afceb1627a1fddc1de7da68c33169647e6f046c 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig @@ -27,3 +27,22 @@ config QCOM_HIDMA (user to kernel, kernel to kernel, etc.). It only supports memcpy interface. The core is not intended for general purpose slave DMA. + +config QCOM_GPI_DMA + tristate "Qualcomm Technologies Inc GPI DMA support" + depends on ARCH_QCOM + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for the QCOM GPI DMA controller. This controller + provides DMA capabilities for a variety of peripheral buses such + as I2C, UART, and SPI. By using GPI dmaengine driver, bus drivers + can use a standardize interface that is protocol independent to + transfer data between DDR and peripheral. + +config QCOM_GPI_DMA_DEBUG + bool "Qualcomm Technologies Inc GPI debug support" + depends on QCOM_GPI_DMA + help + Enable detailed logging for QCOM GPI driver. Extra logging will be + helpful when debugging critical issues. diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile index 4bfc38b45220a02d6ae5927ce6c19988e198209f..6476ac542e665b12f9fe0d6122d248a2bb8d332f 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o obj-$(CONFIG_QCOM_HIDMA) += hdma.o hdma-objs := hidma_ll.o hidma.o hidma_dbg.o +obj-$(CONFIG_QCOM_GPI_DMA) += gpi.o diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c new file mode 100644 index 0000000000000000000000000000000000000000..065b765c02b46964334a211fcef3074a325708fe --- /dev/null +++ b/drivers/dma/qcom/gpi.c @@ -0,0 +1,2895 @@ +/* Copyright (c) 2017-2018, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../dmaengine.h" +#include "../virt-dma.h" +#include "msm_gpi_mmio.h" + +/* global logging macros */ +#define GPI_LOG(gpi_dev, fmt, ...) do { \ + if (gpi_dev->klog_lvl != LOG_LVL_MASK_ALL) \ + dev_dbg(gpi_dev->dev, "%s: " fmt, __func__, ##__VA_ARGS__); \ + if (gpi_dev->ilctxt && gpi_dev->ipc_log_lvl != LOG_LVL_MASK_ALL) \ + ipc_log_string(gpi_dev->ilctxt, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) +#define GPI_ERR(gpi_dev, fmt, ...) do { \ + if (gpi_dev->klog_lvl >= LOG_LVL_ERROR) \ + dev_err(gpi_dev->dev, "%s: " fmt, __func__, ##__VA_ARGS__); \ + if (gpi_dev->ilctxt && gpi_dev->ipc_log_lvl >= LOG_LVL_ERROR) \ + ipc_log_string(gpi_dev->ilctxt, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + +/* gpii specific logging macros */ +#define GPII_INFO(gpii, ch, fmt, ...) do { \ + if (gpii->klog_lvl >= LOG_LVL_INFO) \ + pr_info("%s:%u:%s: " fmt, gpii->label, ch, \ + __func__, ##__VA_ARGS__); \ + if (gpii->ilctxt && gpii->ipc_log_lvl >= LOG_LVL_INFO) \ + ipc_log_string(gpii->ilctxt, \ + "ch:%u %s: " fmt, ch, \ + __func__, ##__VA_ARGS__); \ + } while (0) +#define GPII_ERR(gpii, ch, fmt, ...) do { \ + if (gpii->klog_lvl >= LOG_LVL_ERROR) \ + pr_err("%s:%u:%s: " fmt, gpii->label, ch, \ + __func__, ##__VA_ARGS__); \ + if (gpii->ilctxt && gpii->ipc_log_lvl >= LOG_LVL_ERROR) \ + ipc_log_string(gpii->ilctxt, \ + "ch:%u %s: " fmt, ch, \ + __func__, ##__VA_ARGS__); \ + } while (0) +#define GPII_CRITIC(gpii, ch, fmt, ...) do { \ + if (gpii->klog_lvl >= LOG_LVL_CRITICAL) \ + pr_err("%s:%u:%s: " fmt, gpii->label, ch, \ + __func__, ##__VA_ARGS__); \ + if (gpii->ilctxt && gpii->ipc_log_lvl >= LOG_LVL_CRITICAL) \ + ipc_log_string(gpii->ilctxt, \ + "ch:%u %s: " fmt, ch, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +enum DEBUG_LOG_LVL { + LOG_LVL_MASK_ALL, + LOG_LVL_CRITICAL, + LOG_LVL_ERROR, + LOG_LVL_INFO, + LOG_LVL_VERBOSE, + LOG_LVL_REG_ACCESS, +}; + +enum EV_PRIORITY { + EV_PRIORITY_ISR, + EV_PRIORITY_TASKLET, +}; + +#define GPI_DMA_DRV_NAME "gpi_dma" +#define DEFAULT_KLOG_LVL (LOG_LVL_CRITICAL) +#ifdef CONFIG_QCOM_GPI_DMA_DEBUG +#define DEFAULT_IPC_LOG_LVL (LOG_LVL_VERBOSE) +#define IPC_LOG_PAGES (40) +#define GPI_DBG_LOG_SIZE (SZ_1K) /* size must be power of 2 */ +#define CMD_TIMEOUT_MS (1000) +#define GPII_REG(gpii, ch, fmt, ...) do { \ + if (gpii->klog_lvl >= LOG_LVL_REG_ACCESS) \ + pr_info("%s:%u:%s: " fmt, gpii->label, \ + ch, __func__, ##__VA_ARGS__); \ + if (gpii->ilctxt && gpii->ipc_log_lvl >= LOG_LVL_REG_ACCESS) \ + ipc_log_string(gpii->ilctxt, \ + "ch:%u %s: " fmt, ch, \ + __func__, ##__VA_ARGS__); \ + } while (0) +#define GPII_VERB(gpii, ch, fmt, ...) do { \ + if (gpii->klog_lvl >= LOG_LVL_VERBOSE) \ + pr_info("%s:%u:%s: " fmt, gpii->label, \ + ch, __func__, ##__VA_ARGS__); \ + if (gpii->ilctxt && gpii->ipc_log_lvl >= LOG_LVL_VERBOSE) \ + ipc_log_string(gpii->ilctxt, \ + "ch:%u %s: " fmt, ch, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +#else +#define IPC_LOG_PAGES (2) +#define GPI_DBG_LOG_SIZE (0) /* size must be power of 2 */ +#define DEFAULT_IPC_LOG_LVL (LOG_LVL_ERROR) +#define CMD_TIMEOUT_MS (250) +/* verbose and register logging are disabled if !debug */ +#define GPII_REG(gpii, ch, fmt, ...) +#define GPII_VERB(gpii, ch, fmt, ...) +#endif + +#define GPI_LABEL_SIZE (256) +#define GPI_DBG_COMMON (99) +#define MAX_CHANNELS_PER_GPII (2) +#define GPI_TX_CHAN (0) +#define GPI_RX_CHAN (1) +#define STATE_IGNORE (U32_MAX) +#define REQ_OF_DMA_ARGS (5) /* # of arguments required from client */ + +struct __packed gpi_error_log_entry { + u32 routine : 4; + u32 type : 4; + u32 reserved0 : 4; + u32 code : 4; + u32 reserved1 : 3; + u32 chid : 5; + u32 reserved2 : 1; + u32 chtype : 1; + u32 ee : 1; +}; + +struct __packed xfer_compl_event { + u64 ptr; + u32 length : 24; + u8 code; + u16 status; + u8 type; + u8 chid; +}; + +struct __packed immediate_data_event { + u8 data_bytes[8]; + u8 length : 4; + u8 resvd : 4; + u16 tre_index; + u8 code; + u16 status; + u8 type; + u8 chid; +}; + +struct __packed qup_notif_event { + u32 status; + u32 time; + u32 count :24; + u8 resvd; + u16 resvd1; + u8 type; + u8 chid; +}; + +struct __packed gpi_ere { + u32 dword[4]; +}; + +enum GPI_EV_TYPE { + XFER_COMPLETE_EV_TYPE = 0x22, + IMMEDIATE_DATA_EV_TYPE = 0x30, + QUP_NOTIF_EV_TYPE = 0x31, + STALE_EV_TYPE = 0xFF, +}; + +union __packed gpi_event { + struct __packed xfer_compl_event xfer_compl_event; + struct __packed immediate_data_event immediate_data_event; + struct __packed qup_notif_event qup_notif_event; + struct __packed gpi_ere gpi_ere; +}; + +enum gpii_irq_settings { + DEFAULT_IRQ_SETTINGS, + MASK_IEOB_SETTINGS, +}; + +enum gpi_ev_state { + DEFAULT_EV_CH_STATE = 0, + EV_STATE_NOT_ALLOCATED = DEFAULT_EV_CH_STATE, + EV_STATE_ALLOCATED, + MAX_EV_STATES +}; + +static const char *const gpi_ev_state_str[MAX_EV_STATES] = { + [EV_STATE_NOT_ALLOCATED] = "NOT ALLOCATED", + [EV_STATE_ALLOCATED] = "ALLOCATED", +}; + +#define TO_GPI_EV_STATE_STR(state) ((state >= MAX_EV_STATES) ? \ + "INVALID" : gpi_ev_state_str[state]) + +enum gpi_ch_state { + DEFAULT_CH_STATE = 0x0, + CH_STATE_NOT_ALLOCATED = DEFAULT_CH_STATE, + CH_STATE_ALLOCATED = 0x1, + CH_STATE_STARTED = 0x2, + CH_STATE_STOPPED = 0x3, + CH_STATE_STOP_IN_PROC = 0x4, + CH_STATE_ERROR = 0xf, + MAX_CH_STATES +}; + +static const char *const gpi_ch_state_str[MAX_CH_STATES] = { + [CH_STATE_NOT_ALLOCATED] = "NOT ALLOCATED", + [CH_STATE_ALLOCATED] = "ALLOCATED", + [CH_STATE_STARTED] = "STARTED", + [CH_STATE_STOPPED] = "STOPPED", + [CH_STATE_STOP_IN_PROC] = "STOP IN PROCESS", + [CH_STATE_ERROR] = "ERROR", +}; + +#define TO_GPI_CH_STATE_STR(state) ((state >= MAX_CH_STATES) ? \ + "INVALID" : gpi_ch_state_str[state]) + +enum gpi_cmd { + GPI_CH_CMD_BEGIN, + GPI_CH_CMD_ALLOCATE = GPI_CH_CMD_BEGIN, + GPI_CH_CMD_START, + GPI_CH_CMD_STOP, + GPI_CH_CMD_RESET, + GPI_CH_CMD_DE_ALLOC, + GPI_CH_CMD_UART_SW_STALE, + GPI_CH_CMD_UART_RFR_READY, + GPI_CH_CMD_UART_RFR_NOT_READY, + GPI_CH_CMD_END = GPI_CH_CMD_UART_RFR_NOT_READY, + GPI_EV_CMD_BEGIN, + GPI_EV_CMD_ALLOCATE = GPI_EV_CMD_BEGIN, + GPI_EV_CMD_RESET, + GPI_EV_CMD_DEALLOC, + GPI_EV_CMD_END = GPI_EV_CMD_DEALLOC, + GPI_MAX_CMD, +}; + +#define IS_CHAN_CMD(cmd) (cmd <= GPI_CH_CMD_END) + +static const char *const gpi_cmd_str[GPI_MAX_CMD] = { + [GPI_CH_CMD_ALLOCATE] = "CH ALLOCATE", + [GPI_CH_CMD_START] = "CH START", + [GPI_CH_CMD_STOP] = "CH STOP", + [GPI_CH_CMD_RESET] = "CH_RESET", + [GPI_CH_CMD_DE_ALLOC] = "DE ALLOC", + [GPI_CH_CMD_UART_SW_STALE] = "UART SW STALE", + [GPI_CH_CMD_UART_RFR_READY] = "UART RFR READY", + [GPI_CH_CMD_UART_RFR_NOT_READY] = "UART RFR NOT READY", + [GPI_EV_CMD_ALLOCATE] = "EV ALLOCATE", + [GPI_EV_CMD_RESET] = "EV RESET", + [GPI_EV_CMD_DEALLOC] = "EV DEALLOC", +}; + +#define TO_GPI_CMD_STR(cmd) ((cmd >= GPI_MAX_CMD) ? "INVALID" : \ + gpi_cmd_str[cmd]) + +static const char *const gpi_cb_event_str[MSM_GPI_QUP_MAX_EVENT] = { + [MSM_GPI_QUP_NOTIFY] = "NOTIFY", + [MSM_GPI_QUP_ERROR] = "GLOBAL ERROR", + [MSM_GPI_QUP_CH_ERROR] = "CHAN ERROR", + [MSM_GPI_QUP_PENDING_EVENT] = "PENDING EVENT", + [MSM_GPI_QUP_EOT_DESC_MISMATCH] = "EOT/DESC MISMATCH", + [MSM_GPI_QUP_SW_ERROR] = "SW ERROR", +}; + +#define TO_GPI_CB_EVENT_STR(event) ((event >= MSM_GPI_QUP_MAX_EVENT) ? \ + "INVALID" : gpi_cb_event_str[event]) + +enum se_protocol { + SE_PROTOCOL_SPI = 1, + SE_PROTOCOL_UART = 2, + SE_PROTOCOL_I2C = 3, + SE_MAX_PROTOCOL +}; + +/* + * @DISABLE_STATE: no register access allowed + * @CONFIG_STATE: client has configured the channel + * @PREP_HARDWARE: register access is allowed + * however, no processing EVENTS + * @ACTIVE_STATE: channels are fully operational + * @PREPARE_TERIMNATE: graceful termination of channels + * register access is allowed + * @PAUSE_STATE: channels are active, but not processing any events + */ +enum gpi_pm_state { + DISABLE_STATE, + CONFIG_STATE, + PREPARE_HARDWARE, + ACTIVE_STATE, + PREPARE_TERMINATE, + PAUSE_STATE, + MAX_PM_STATE +}; + +#define REG_ACCESS_VALID(pm_state) (pm_state >= PREPARE_HARDWARE) + +static const char *const gpi_pm_state_str[MAX_PM_STATE] = { + [DISABLE_STATE] = "DISABLE", + [CONFIG_STATE] = "CONFIG", + [PREPARE_HARDWARE] = "PREPARE HARDWARE", + [ACTIVE_STATE] = "ACTIVE", + [PREPARE_TERMINATE] = "PREPARE TERMINATE", + [PAUSE_STATE] = "PAUSE", +}; + +#define TO_GPI_PM_STR(state) ((state >= MAX_PM_STATE) ? \ + "INVALID" : gpi_pm_state_str[state]) + +static const struct { + enum gpi_cmd gpi_cmd; + u32 opcode; + u32 state; + u32 timeout_ms; +} gpi_cmd_info[GPI_MAX_CMD] = { + { + GPI_CH_CMD_ALLOCATE, + GPI_GPII_n_CH_CMD_ALLOCATE, + CH_STATE_ALLOCATED, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_START, + GPI_GPII_n_CH_CMD_START, + CH_STATE_STARTED, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_STOP, + GPI_GPII_n_CH_CMD_STOP, + CH_STATE_STOPPED, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_RESET, + GPI_GPII_n_CH_CMD_RESET, + CH_STATE_ALLOCATED, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_DE_ALLOC, + GPI_GPII_n_CH_CMD_DE_ALLOC, + CH_STATE_NOT_ALLOCATED, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_UART_SW_STALE, + GPI_GPII_n_CH_CMD_UART_SW_STALE, + STATE_IGNORE, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_UART_RFR_READY, + GPI_GPII_n_CH_CMD_UART_RFR_READY, + STATE_IGNORE, + CMD_TIMEOUT_MS, + }, + { + GPI_CH_CMD_UART_RFR_NOT_READY, + GPI_GPII_n_CH_CMD_UART_RFR_NOT_READY, + STATE_IGNORE, + CMD_TIMEOUT_MS, + }, + { + GPI_EV_CMD_ALLOCATE, + GPI_GPII_n_EV_CH_CMD_ALLOCATE, + EV_STATE_ALLOCATED, + CMD_TIMEOUT_MS, + }, + { + GPI_EV_CMD_RESET, + GPI_GPII_n_EV_CH_CMD_RESET, + EV_STATE_ALLOCATED, + CMD_TIMEOUT_MS, + }, + { + GPI_EV_CMD_DEALLOC, + GPI_GPII_n_EV_CH_CMD_DE_ALLOC, + EV_STATE_NOT_ALLOCATED, + CMD_TIMEOUT_MS, + }, +}; + +struct gpi_ring { + void *pre_aligned; + size_t alloc_size; + phys_addr_t phys_addr; + dma_addr_t dma_handle; + void *base; + void *wp; + void *rp; + u32 len; + u32 el_size; + u32 elements; + bool configured; +}; + +struct sg_tre { + void *ptr; + void *wp; /* store chan wp for debugging */ +}; + +struct gpi_dbg_log { + void *addr; + u64 time; + u32 val; + bool read; +}; + +struct gpi_dev { + struct dma_device dma_device; + struct device *dev; + struct resource *res; + void __iomem *regs; + u32 max_gpii; /* maximum # of gpii instances available per gpi block */ + u32 gpii_mask; /* gpii instances available for apps */ + u32 ev_factor; /* ev ring length factor */ + u32 smmu_cfg; + dma_addr_t iova_base; + size_t iova_size; + struct gpii *gpiis; + void *ilctxt; + u32 ipc_log_lvl; + u32 klog_lvl; + struct dentry *dentry; +}; + +struct gpii_chan { + struct virt_dma_chan vc; + u32 chid; + u32 seid; + enum se_protocol protocol; + enum EV_PRIORITY priority; /* comes from clients DT node */ + struct gpii *gpii; + enum gpi_ch_state ch_state; + enum gpi_pm_state pm_state; + void __iomem *ch_cntxt_base_reg; + void __iomem *ch_cntxt_db_reg; + void __iomem *ch_ring_base_lsb_reg, + *ch_ring_rp_lsb_reg, + *ch_ring_wp_lsb_reg; + void __iomem *ch_cmd_reg; + u32 req_tres; /* # of tre's client requested */ + u32 dir; + struct gpi_ring ch_ring; + struct gpi_client_info client_info; +}; + +struct gpii { + u32 gpii_id; + struct gpii_chan gpii_chan[MAX_CHANNELS_PER_GPII]; + struct gpi_dev *gpi_dev; + enum EV_PRIORITY ev_priority; + enum se_protocol protocol; + int irq; + void __iomem *regs; /* points to gpi top */ + void __iomem *ev_cntxt_base_reg; + void __iomem *ev_cntxt_db_reg; + void __iomem *ev_ring_base_lsb_reg, + *ev_ring_rp_lsb_reg, + *ev_ring_wp_lsb_reg; + void __iomem *ev_cmd_reg; + void __iomem *ieob_src_reg; + void __iomem *ieob_clr_reg; + struct mutex ctrl_lock; + enum gpi_ev_state ev_state; + bool configured_irq; + enum gpi_pm_state pm_state; + rwlock_t pm_lock; + struct gpi_ring ev_ring; + struct tasklet_struct ev_task; /* event processing tasklet */ + struct completion cmd_completion; + enum gpi_cmd gpi_cmd; + u32 cntxt_type_irq_msk; + void *ilctxt; + u32 ipc_log_lvl; + u32 klog_lvl; + struct gpi_dbg_log dbg_log[GPI_DBG_LOG_SIZE]; + atomic_t dbg_index; + char label[GPI_LABEL_SIZE]; + struct dentry *dentry; +}; + +struct gpi_desc { + struct virt_dma_desc vd; + void *wp; /* points to TRE last queued during issue_pending */ + void *db; /* DB register to program */ + struct gpii_chan *gpii_chan; +}; + +#define GPI_SMMU_ATTACH BIT(0) +#define GPI_SMMU_S1_BYPASS BIT(1) +#define GPI_SMMU_FAST BIT(2) +#define GPI_SMMU_ATOMIC BIT(3) + +const u32 GPII_CHAN_DIR[MAX_CHANNELS_PER_GPII] = { + GPI_CHTYPE_DIR_OUT, GPI_CHTYPE_DIR_IN +}; + +struct dentry *pdentry; +static irqreturn_t gpi_handle_irq(int irq, void *data); +static void gpi_ring_recycle_ev_element(struct gpi_ring *ring); +static int gpi_ring_add_element(struct gpi_ring *ring, void **wp); +static void gpi_process_events(struct gpii *gpii); + +static inline struct gpii_chan *to_gpii_chan(struct dma_chan *dma_chan) +{ + return container_of(dma_chan, struct gpii_chan, vc.chan); +} + +static inline struct gpi_desc *to_gpi_desc(struct virt_dma_desc *vd) +{ + return container_of(vd, struct gpi_desc, vd); +} + +static inline phys_addr_t to_physical(const struct gpi_ring *const ring, + void *addr) +{ + return ring->phys_addr + (addr - ring->base); +} + +static inline void *to_virtual(const struct gpi_ring *const ring, + phys_addr_t addr) +{ + return ring->base + (addr - ring->phys_addr); +} + +#ifdef CONFIG_QCOM_GPI_DMA_DEBUG +static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) +{ + u64 time = sched_clock(); + unsigned int index = atomic_inc_return(&gpii->dbg_index) - 1; + u32 val; + + val = readl_relaxed(addr); + index &= (GPI_DBG_LOG_SIZE - 1); + (gpii->dbg_log + index)->addr = addr; + (gpii->dbg_log + index)->time = time; + (gpii->dbg_log + index)->val = val; + (gpii->dbg_log + index)->read = true; + GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", + addr - gpii->regs, val); + return val; +} +static inline void gpi_write_reg(struct gpii *gpii, void __iomem *addr, u32 val) +{ + u64 time = sched_clock(); + unsigned int index = atomic_inc_return(&gpii->dbg_index) - 1; + + index &= (GPI_DBG_LOG_SIZE - 1); + (gpii->dbg_log + index)->addr = addr; + (gpii->dbg_log + index)->time = time; + (gpii->dbg_log + index)->val = val; + (gpii->dbg_log + index)->read = false; + + GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", + addr - gpii->regs, val); + writel_relaxed(val, addr); +} +#else +static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) +{ + u32 val = readl_relaxed(addr); + + GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", + addr - gpii->regs, val); + return val; +} +static inline void gpi_write_reg(struct gpii *gpii, void __iomem *addr, u32 val) +{ + GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", + addr - gpii->regs, val); + writel_relaxed(val, addr); +} +#endif + +/* gpi_write_reg_field - write to specific bit field */ +static inline void gpi_write_reg_field(struct gpii *gpii, + void __iomem *addr, + u32 mask, + u32 shift, + u32 val) +{ + u32 tmp = gpi_read_reg(gpii, addr); + + tmp &= ~mask; + val = tmp | ((val << shift) & mask); + gpi_write_reg(gpii, addr, val); +} + +static void gpi_disable_interrupts(struct gpii *gpii) +{ + struct { + u32 offset; + u32 mask; + u32 shift; + u32 val; + } default_reg[] = { + { + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_SHFT, + 0, + }, + { + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_SHFT, + 0, + }, + { + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_SHFT, + 0, + }, + { + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_SHFT, + 0, + }, + { + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_BMSK, + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_SHFT, + 0, + }, + { + GPI_GPII_n_CNTXT_GPII_IRQ_EN_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_GPII_IRQ_EN_BMSK, + GPI_GPII_n_CNTXT_GPII_IRQ_EN_SHFT, + 0, + }, + { + GPI_GPII_n_CNTXT_INTSET_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_INTSET_BMSK, + GPI_GPII_n_CNTXT_INTSET_SHFT, + 0, + }, + { 0 }, + }; + int i; + + for (i = 0; default_reg[i].offset; i++) + gpi_write_reg_field(gpii, gpii->regs + + default_reg[i].offset, + default_reg[i].mask, + default_reg[i].shift, + default_reg[i].val); + gpii->cntxt_type_irq_msk = 0; + devm_free_irq(gpii->gpi_dev->dev, gpii->irq, gpii); + gpii->configured_irq = false; +} + +/* configure and enable interrupts */ +static int gpi_config_interrupts(struct gpii *gpii, + enum gpii_irq_settings settings, + bool mask) +{ + int ret; + int i; + const u32 def_type = (GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_GENERAL | + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_IEOB | + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_GLOB | + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL | + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL); + struct { + u32 offset; + u32 mask; + u32 shift; + u32 val; + } default_reg[] = { + { + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_SHFT, + def_type, + }, + { + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_SHFT, + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_BMSK, + }, + { + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_SHFT, + GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_BMSK, + }, + { + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_SHFT, + GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_BMSK, + }, + { + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_BMSK, + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_SHFT, + GPI_GPII_n_CNTXT_GLOB_IRQ_EN_ERROR_INT, + }, + { + GPI_GPII_n_CNTXT_GPII_IRQ_EN_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_GPII_IRQ_EN_BMSK, + GPI_GPII_n_CNTXT_GPII_IRQ_EN_SHFT, + GPI_GPII_n_CNTXT_GPII_IRQ_EN_BMSK, + }, + { + GPI_GPII_n_CNTXT_MSI_BASE_LSB_OFFS + (gpii->gpii_id), + U32_MAX, + 0, + 0x0, + }, + { + GPI_GPII_n_CNTXT_MSI_BASE_MSB_OFFS + (gpii->gpii_id), + U32_MAX, + 0, + 0x0, + }, + { + GPI_GPII_n_CNTXT_SCRATCH_0_OFFS + (gpii->gpii_id), + U32_MAX, + 0, + 0x0, + }, + { + GPI_GPII_n_CNTXT_SCRATCH_1_OFFS + (gpii->gpii_id), + U32_MAX, + 0, + 0x0, + }, + { + GPI_GPII_n_CNTXT_INTSET_OFFS + (gpii->gpii_id), + GPI_GPII_n_CNTXT_INTSET_BMSK, + GPI_GPII_n_CNTXT_INTSET_SHFT, + 0x01, + }, + { + GPI_GPII_n_ERROR_LOG_OFFS + (gpii->gpii_id), + U32_MAX, + 0, + 0x00, + }, + { 0 }, + }; + + GPII_VERB(gpii, GPI_DBG_COMMON, "configured:%c setting:%s mask:%c\n", + (gpii->configured_irq) ? 'F' : 'T', + (settings == DEFAULT_IRQ_SETTINGS) ? "default" : "user_spec", + (mask) ? 'T' : 'F'); + + if (gpii->configured_irq == false) { + ret = devm_request_irq(gpii->gpi_dev->dev, gpii->irq, + gpi_handle_irq, IRQF_TRIGGER_HIGH, + gpii->label, gpii); + if (ret < 0) { + GPII_CRITIC(gpii, GPI_DBG_COMMON, + "error request irq:%d ret:%d\n", + gpii->irq, ret); + return ret; + } + } + + if (settings == MASK_IEOB_SETTINGS) { + /* + * GPII only uses one EV ring per gpii so we can globally + * enable/disable IEOB interrupt + */ + if (mask) + gpii->cntxt_type_irq_msk |= + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_IEOB; + else + gpii->cntxt_type_irq_msk &= + ~(GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_IEOB); + gpi_write_reg_field(gpii, gpii->regs + + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_OFFS(gpii->gpii_id), + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_BMSK, + GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_SHFT, + gpii->cntxt_type_irq_msk); + } else { + for (i = 0; default_reg[i].offset; i++) + gpi_write_reg_field(gpii, gpii->regs + + default_reg[i].offset, + default_reg[i].mask, + default_reg[i].shift, + default_reg[i].val); + gpii->cntxt_type_irq_msk = def_type; + }; + + gpii->configured_irq = true; + + return 0; +} + +/* Sends gpii event or channel command */ +static int gpi_send_cmd(struct gpii *gpii, + struct gpii_chan *gpii_chan, + enum gpi_cmd gpi_cmd) +{ + u32 chid = MAX_CHANNELS_PER_GPII; + u32 cmd; + unsigned long timeout; + void __iomem *cmd_reg; + + if (gpi_cmd >= GPI_MAX_CMD) + return -EINVAL; + if (IS_CHAN_CMD(gpi_cmd)) + chid = gpii_chan->chid; + + GPII_INFO(gpii, chid, + "sending cmd: %s\n", TO_GPI_CMD_STR(gpi_cmd)); + + /* send opcode and wait for completion */ + reinit_completion(&gpii->cmd_completion); + gpii->gpi_cmd = gpi_cmd; + + cmd_reg = IS_CHAN_CMD(gpi_cmd) ? gpii_chan->ch_cmd_reg : + gpii->ev_cmd_reg; + cmd = IS_CHAN_CMD(gpi_cmd) ? + GPI_GPII_n_CH_CMD(gpi_cmd_info[gpi_cmd].opcode, chid) : + GPI_GPII_n_EV_CH_CMD(gpi_cmd_info[gpi_cmd].opcode, 0); + gpi_write_reg(gpii, cmd_reg, cmd); + timeout = wait_for_completion_timeout(&gpii->cmd_completion, + msecs_to_jiffies(gpi_cmd_info[gpi_cmd].timeout_ms)); + + if (!timeout) { + GPII_ERR(gpii, chid, "cmd: %s completion timeout\n", + TO_GPI_CMD_STR(gpi_cmd)); + return -EIO; + } + + /* confirm new ch state is correct , if the cmd is a state change cmd */ + if (gpi_cmd_info[gpi_cmd].state == STATE_IGNORE) + return 0; + if (IS_CHAN_CMD(gpi_cmd) && + gpii_chan->ch_state == gpi_cmd_info[gpi_cmd].state) + return 0; + if (!IS_CHAN_CMD(gpi_cmd) && + gpii->ev_state == gpi_cmd_info[gpi_cmd].state) + return 0; + + return -EIO; +} + +/* program transfer ring DB register */ +static inline void gpi_write_ch_db(struct gpii_chan *gpii_chan, + struct gpi_ring *ring, + void *wp) +{ + struct gpii *gpii = gpii_chan->gpii; + phys_addr_t p_wp; + + p_wp = to_physical(ring, wp); + gpi_write_reg(gpii, gpii_chan->ch_cntxt_db_reg, (u32)p_wp); +} + +/* program event ring DB register */ +static inline void gpi_write_ev_db(struct gpii *gpii, + struct gpi_ring *ring, + void *wp) +{ + phys_addr_t p_wp; + + p_wp = ring->phys_addr + (wp - ring->base); + gpi_write_reg(gpii, gpii->ev_cntxt_db_reg, (u32)p_wp); +} + +/* notify client with generic event */ +static void gpi_generate_cb_event(struct gpii_chan *gpii_chan, + enum msm_gpi_cb_event event, + u64 status) +{ + struct gpii *gpii = gpii_chan->gpii; + struct gpi_client_info *client_info = &gpii_chan->client_info; + struct msm_gpi_cb msm_gpi_cb = {0}; + + GPII_ERR(gpii, gpii_chan->chid, + "notifying event:%s with status:%llu\n", + TO_GPI_CB_EVENT_STR(event), status); + + msm_gpi_cb.cb_event = event; + msm_gpi_cb.status = status; + msm_gpi_cb.timestamp = sched_clock(); + client_info->callback(&gpii_chan->vc.chan, &msm_gpi_cb, + client_info->cb_param); +} + +/* process transfer completion interrupt */ +static void gpi_process_ieob(struct gpii *gpii) +{ + + gpi_write_reg(gpii, gpii->ieob_clr_reg, BIT(0)); + + /* process events based on priority */ + if (likely(gpii->ev_priority >= EV_PRIORITY_TASKLET)) { + GPII_VERB(gpii, GPI_DBG_COMMON, "scheduling tasklet\n"); + gpi_config_interrupts(gpii, MASK_IEOB_SETTINGS, 0); + tasklet_schedule(&gpii->ev_task); + } else { + GPII_VERB(gpii, GPI_DBG_COMMON, "processing events from isr\n"); + gpi_process_events(gpii); + } +} + +/* process channel control interrupt */ +static void gpi_process_ch_ctrl_irq(struct gpii *gpii) +{ + u32 gpii_id = gpii->gpii_id; + u32 offset = GPI_GPII_n_CNTXT_SRC_GPII_CH_IRQ_OFFS(gpii_id); + u32 ch_irq = gpi_read_reg(gpii, gpii->regs + offset); + u32 chid; + struct gpii_chan *gpii_chan; + u32 state; + + /* clear the status */ + offset = GPI_GPII_n_CNTXT_SRC_CH_IRQ_CLR_OFFS(gpii_id); + gpi_write_reg(gpii, gpii->regs + offset, (u32)ch_irq); + + for (chid = 0; chid < MAX_CHANNELS_PER_GPII; chid++) { + if (!(BIT(chid) & ch_irq)) + continue; + + gpii_chan = &gpii->gpii_chan[chid]; + GPII_VERB(gpii, chid, "processing channel ctrl irq\n"); + state = gpi_read_reg(gpii, gpii_chan->ch_cntxt_base_reg + + CNTXT_0_CONFIG); + state = (state & GPI_GPII_n_CH_k_CNTXT_0_CHSTATE_BMSK) >> + GPI_GPII_n_CH_k_CNTXT_0_CHSTATE_SHFT; + + /* + * CH_CMD_DEALLOC cmd always successful. However cmd does + * not change hardware status. So overwriting software state + * to default state. + */ + if (gpii->gpi_cmd == GPI_CH_CMD_DE_ALLOC) + state = DEFAULT_CH_STATE; + gpii_chan->ch_state = state; + GPII_VERB(gpii, chid, "setting channel to state:%s\n", + TO_GPI_CH_STATE_STR(gpii_chan->ch_state)); + + /* + * Triggering complete all if ch_state is not a stop in process. + * Stop in process is a transition state and we will wait for + * stop interrupt before notifying. + */ + if (gpii_chan->ch_state != CH_STATE_STOP_IN_PROC) + complete_all(&gpii->cmd_completion); + + /* notifying clients if in error state */ + if (gpii_chan->ch_state == CH_STATE_ERROR) + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_CH_ERROR, + __LINE__); + } +} + +/* processing gpi level error interrupts */ +static void gpi_process_glob_err_irq(struct gpii *gpii) +{ + u32 gpii_id = gpii->gpii_id; + u32 offset = GPI_GPII_n_CNTXT_GLOB_IRQ_STTS_OFFS(gpii_id); + u32 irq_stts = gpi_read_reg(gpii, gpii->regs + offset); + u32 error_log; + u32 chid; + struct gpii_chan *gpii_chan; + struct gpi_client_info *client_info; + struct msm_gpi_cb msm_gpi_cb; + struct gpi_error_log_entry *log_entry = + (struct gpi_error_log_entry *)&error_log; + + offset = GPI_GPII_n_CNTXT_GLOB_IRQ_CLR_OFFS(gpii_id); + gpi_write_reg(gpii, gpii->regs + offset, irq_stts); + + /* only error interrupt should be set */ + if (irq_stts & ~GPI_GLOB_IRQ_ERROR_INT_MSK) { + GPII_ERR(gpii, GPI_DBG_COMMON, "invalid error status:0x%x\n", + irq_stts); + goto error_irq; + } + + offset = GPI_GPII_n_ERROR_LOG_OFFS(gpii_id); + error_log = gpi_read_reg(gpii, gpii->regs + offset); + gpi_write_reg(gpii, gpii->regs + offset, 0); + + /* get channel info */ + chid = ((struct gpi_error_log_entry *)&error_log)->chid; + if (unlikely(chid >= MAX_CHANNELS_PER_GPII)) { + GPII_ERR(gpii, GPI_DBG_COMMON, "invalid chid reported:%u\n", + chid); + goto error_irq; + } + + gpii_chan = &gpii->gpii_chan[chid]; + client_info = &gpii_chan->client_info; + + /* notify client with error log */ + msm_gpi_cb.cb_event = MSM_GPI_QUP_ERROR; + msm_gpi_cb.error_log.routine = log_entry->routine; + msm_gpi_cb.error_log.type = log_entry->type; + msm_gpi_cb.error_log.error_code = log_entry->code; + GPII_INFO(gpii, gpii_chan->chid, "sending CB event:%s\n", + TO_GPI_CB_EVENT_STR(msm_gpi_cb.cb_event)); + GPII_ERR(gpii, gpii_chan->chid, + "ee:%u chtype:%u routine:%u type:%u error_code:%u\n", + log_entry->ee, log_entry->chtype, + msm_gpi_cb.error_log.routine, + msm_gpi_cb.error_log.type, + msm_gpi_cb.error_log.error_code); + client_info->callback(&gpii_chan->vc.chan, &msm_gpi_cb, + client_info->cb_param); + + return; + +error_irq: + for (chid = 0, gpii_chan = gpii->gpii_chan; + chid < MAX_CHANNELS_PER_GPII; chid++, gpii_chan++) + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_FW_ERROR, + irq_stts); +} + +/* gpii interrupt handler */ +static irqreturn_t gpi_handle_irq(int irq, void *data) +{ + struct gpii *gpii = data; + u32 type; + unsigned long flags; + u32 offset; + u32 gpii_id = gpii->gpii_id; + + GPII_VERB(gpii, GPI_DBG_COMMON, "enter\n"); + + read_lock_irqsave(&gpii->pm_lock, flags); + + /* + * States are out of sync to receive interrupt + * while software state is in DISABLE state, bailing out. + */ + if (!REG_ACCESS_VALID(gpii->pm_state)) { + GPII_CRITIC(gpii, GPI_DBG_COMMON, + "receive interrupt while in %s state\n", + TO_GPI_PM_STR(gpii->pm_state)); + goto exit_irq; + } + + offset = GPI_GPII_n_CNTXT_TYPE_IRQ_OFFS(gpii->gpii_id); + type = gpi_read_reg(gpii, gpii->regs + offset); + + do { + GPII_VERB(gpii, GPI_DBG_COMMON, "CNTXT_TYPE_IRQ:0x%08x\n", + type); + /* global gpii error */ + if (type & GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_GLOB) { + GPII_ERR(gpii, GPI_DBG_COMMON, + "processing global error irq\n"); + gpi_process_glob_err_irq(gpii); + type &= ~(GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_GLOB); + } + + /* transfer complete interrupt */ + if (type & GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_IEOB) { + GPII_VERB(gpii, GPI_DBG_COMMON, + "process IEOB interrupts\n"); + gpi_process_ieob(gpii); + type &= ~GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_IEOB; + } + + /* event control irq */ + if (type & GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL) { + u32 ev_state; + u32 ev_ch_irq; + + GPII_INFO(gpii, GPI_DBG_COMMON, + "processing EV CTRL interrupt\n"); + offset = GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_OFFS(gpii_id); + ev_ch_irq = gpi_read_reg(gpii, gpii->regs + offset); + + offset = GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS + (gpii_id); + gpi_write_reg(gpii, gpii->regs + offset, ev_ch_irq); + ev_state = gpi_read_reg(gpii, gpii->ev_cntxt_base_reg + + CNTXT_0_CONFIG); + ev_state &= GPI_GPII_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK; + ev_state >>= GPI_GPII_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT; + + /* + * CMD EV_CMD_DEALLOC is always successful. However + * cmd does not change hardware status. So overwriting + * software state to default state. + */ + if (gpii->gpi_cmd == GPI_EV_CMD_DEALLOC) + ev_state = DEFAULT_EV_CH_STATE; + + gpii->ev_state = ev_state; + GPII_INFO(gpii, GPI_DBG_COMMON, + "setting EV state to %s\n", + TO_GPI_EV_STATE_STR(gpii->ev_state)); + complete_all(&gpii->cmd_completion); + type &= ~(GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL); + } + + /* channel control irq */ + if (type & GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL) { + GPII_INFO(gpii, GPI_DBG_COMMON, + "process CH CTRL interrupts\n"); + gpi_process_ch_ctrl_irq(gpii); + type &= ~(GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL); + } + + if (type) { + GPII_CRITIC(gpii, GPI_DBG_COMMON, + "Unhandled interrupt status:0x%x\n", type); + goto exit_irq; + } + offset = GPI_GPII_n_CNTXT_TYPE_IRQ_OFFS(gpii->gpii_id); + type = gpi_read_reg(gpii, gpii->regs + offset); + } while (type); + +exit_irq: + read_unlock_irqrestore(&gpii->pm_lock, flags); + GPII_VERB(gpii, GPI_DBG_COMMON, "exit\n"); + + return IRQ_HANDLED; +} + +/* process qup notification events */ +static void gpi_process_qup_notif_event(struct gpii_chan *gpii_chan, + struct qup_notif_event *notif_event) +{ + struct gpi_client_info *client_info = &gpii_chan->client_info; + struct msm_gpi_cb msm_gpi_cb; + + GPII_VERB(gpii_chan->gpii, gpii_chan->chid, + "status:0x%x time:0x%x count:0x%x\n", + notif_event->status, notif_event->time, notif_event->count); + + msm_gpi_cb.cb_event = MSM_GPI_QUP_NOTIFY; + msm_gpi_cb.status = notif_event->status; + msm_gpi_cb.timestamp = notif_event->time; + msm_gpi_cb.count = notif_event->count; + GPII_VERB(gpii_chan->gpii, gpii_chan->chid, "sending CB event:%s\n", + TO_GPI_CB_EVENT_STR(msm_gpi_cb.cb_event)); + client_info->callback(&gpii_chan->vc.chan, &msm_gpi_cb, + client_info->cb_param); +} + +/* process DMA Immediate completion data events */ +static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, + struct immediate_data_event *imed_event) +{ + struct gpii *gpii = gpii_chan->gpii; + struct gpi_ring *ch_ring = &gpii_chan->ch_ring; + struct virt_dma_desc *vd; + struct gpi_desc *gpi_desc; + void *tre = ch_ring->base + + (ch_ring->el_size * imed_event->tre_index); + struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; + unsigned long flags; + + /* + * If channel not active don't process event but let + * client know pending event is available + */ + if (gpii_chan->pm_state != ACTIVE_STATE) { + GPII_ERR(gpii, gpii_chan->chid, + "skipping processing event because ch @ %s state\n", + TO_GPI_PM_STR(gpii_chan->pm_state)); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_PENDING_EVENT, + __LINE__); + return; + } + + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + vd = vchan_next_desc(&gpii_chan->vc); + if (!vd) { + struct gpi_ere *gpi_ere; + struct msm_gpi_tre *gpi_tre; + + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + GPII_ERR(gpii, gpii_chan->chid, + "event without a pending descriptor!\n"); + gpi_ere = (struct gpi_ere *)imed_event; + GPII_ERR(gpii, gpii_chan->chid, "Event: %08x %08x %08x %08x\n", + gpi_ere->dword[0], gpi_ere->dword[1], + gpi_ere->dword[2], gpi_ere->dword[3]); + gpi_tre = tre; + GPII_ERR(gpii, gpii_chan->chid, + "Pending TRE: %08x %08x %08x %08x\n", + gpi_tre->dword[0], gpi_tre->dword[1], + gpi_tre->dword[2], gpi_tre->dword[3]); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, + __LINE__); + return; + } + gpi_desc = to_gpi_desc(vd); + + /* Event TR RP gen. don't match descriptor TR */ + if (gpi_desc->wp != tre) { + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + GPII_ERR(gpii, gpii_chan->chid, + "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n", + to_physical(ch_ring, gpi_desc->wp), + to_physical(ch_ring, tre)); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, + __LINE__); + return; + } + + list_del(&vd->node); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + + + /* + * RP pointed by Event is to last TRE processed, + * we need to update ring rp to tre + 1 + */ + tre += ch_ring->el_size; + if (tre >= (ch_ring->base + ch_ring->len)) + tre = ch_ring->base; + ch_ring->rp = tre; + + /* make sure rp updates are immediately visible to all cores */ + smp_wmb(); + + tx_cb_param = vd->tx.callback_param; + if (vd->tx.callback && tx_cb_param) { + struct msm_gpi_tre *imed_tre = &tx_cb_param->imed_tre; + + GPII_VERB(gpii, gpii_chan->chid, + "cb_length:%u compl_code:0x%x status:0x%x\n", + imed_event->length, imed_event->code, + imed_event->status); + /* Update immediate data if any from event */ + *imed_tre = *((struct msm_gpi_tre *)imed_event); + tx_cb_param->length = imed_event->length; + tx_cb_param->completion_code = imed_event->code; + tx_cb_param->status = imed_event->status; + vd->tx.callback(tx_cb_param); + } + kfree(gpi_desc); +} + +/* processing transfer completion events */ +static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, + struct xfer_compl_event *compl_event) +{ + struct gpii *gpii = gpii_chan->gpii; + struct gpi_ring *ch_ring = &gpii_chan->ch_ring; + void *ev_rp = to_virtual(ch_ring, compl_event->ptr); + struct virt_dma_desc *vd; + struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; + struct gpi_desc *gpi_desc; + unsigned long flags; + + /* only process events on active channel */ + if (unlikely(gpii_chan->pm_state != ACTIVE_STATE)) { + GPII_ERR(gpii, gpii_chan->chid, + "skipping processing event because ch @ %s state\n", + TO_GPI_PM_STR(gpii_chan->pm_state)); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_PENDING_EVENT, + __LINE__); + return; + } + + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + vd = vchan_next_desc(&gpii_chan->vc); + if (!vd) { + struct gpi_ere *gpi_ere; + + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + GPII_ERR(gpii, gpii_chan->chid, + "Event without a pending descriptor!\n"); + gpi_ere = (struct gpi_ere *)compl_event; + GPII_ERR(gpii, gpii_chan->chid, "Event: %08x %08x %08x %08x\n", + gpi_ere->dword[0], gpi_ere->dword[1], + gpi_ere->dword[2], gpi_ere->dword[3]); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, + __LINE__); + return; + } + + gpi_desc = to_gpi_desc(vd); + + /* TRE Event generated didn't match descriptor's TRE */ + if (gpi_desc->wp != ev_rp) { + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + GPII_ERR(gpii, gpii_chan->chid, + "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n", + to_physical(ch_ring, gpi_desc->wp), + to_physical(ch_ring, ev_rp)); + gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, + __LINE__); + return; + } + + list_del(&vd->node); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + + + /* + * RP pointed by Event is to last TRE processed, + * we need to update ring rp to ev_rp + 1 + */ + ev_rp += ch_ring->el_size; + if (ev_rp >= (ch_ring->base + ch_ring->len)) + ev_rp = ch_ring->base; + ch_ring->rp = ev_rp; + + /* update must be visible to other cores */ + smp_wmb(); + + tx_cb_param = vd->tx.callback_param; + if (vd->tx.callback && tx_cb_param) { + GPII_VERB(gpii, gpii_chan->chid, + "cb_length:%u compl_code:0x%x status:0x%x\n", + compl_event->length, compl_event->code, + compl_event->status); + tx_cb_param->length = compl_event->length; + tx_cb_param->completion_code = compl_event->code; + tx_cb_param->status = compl_event->status; + vd->tx.callback(tx_cb_param); + } + kfree(gpi_desc); +} + +/* process all events */ +static void gpi_process_events(struct gpii *gpii) +{ + struct gpi_ring *ev_ring = &gpii->ev_ring; + phys_addr_t cntxt_rp, local_rp; + void *rp; + union gpi_event *gpi_event; + struct gpii_chan *gpii_chan; + u32 chid, type; + + cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); + rp = to_virtual(ev_ring, cntxt_rp); + local_rp = to_physical(ev_ring, ev_ring->rp); + + GPII_VERB(gpii, GPI_DBG_COMMON, "cntxt_rp:%pa local_rp:%pa\n", + &cntxt_rp, &local_rp); + + do { + while (rp != ev_ring->rp) { + gpi_event = ev_ring->rp; + chid = gpi_event->xfer_compl_event.chid; + type = gpi_event->xfer_compl_event.type; + GPII_VERB(gpii, GPI_DBG_COMMON, + "chid:%u type:0x%x %08x %08x %08x %08x\n", + chid, type, + gpi_event->gpi_ere.dword[0], + gpi_event->gpi_ere.dword[1], + gpi_event->gpi_ere.dword[2], + gpi_event->gpi_ere.dword[3]); + + switch (type) { + case XFER_COMPLETE_EV_TYPE: + gpii_chan = &gpii->gpii_chan[chid]; + gpi_process_xfer_compl_event(gpii_chan, + &gpi_event->xfer_compl_event); + break; + case STALE_EV_TYPE: + GPII_VERB(gpii, GPI_DBG_COMMON, + "stale event, not processing\n"); + break; + case IMMEDIATE_DATA_EV_TYPE: + gpii_chan = &gpii->gpii_chan[chid]; + gpi_process_imed_data_event(gpii_chan, + &gpi_event->immediate_data_event); + break; + case QUP_NOTIF_EV_TYPE: + gpii_chan = &gpii->gpii_chan[chid]; + gpi_process_qup_notif_event(gpii_chan, + &gpi_event->qup_notif_event); + break; + default: + GPII_VERB(gpii, GPI_DBG_COMMON, + "not supported event type:0x%x\n", + type); + } + gpi_ring_recycle_ev_element(ev_ring); + } + gpi_write_ev_db(gpii, ev_ring, ev_ring->wp); + + /* clear pending IEOB events */ + gpi_write_reg(gpii, gpii->ieob_clr_reg, BIT(0)); + + cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); + rp = to_virtual(ev_ring, cntxt_rp); + + } while (rp != ev_ring->rp); + + GPII_VERB(gpii, GPI_DBG_COMMON, "exit: c_rp:%pa\n", &cntxt_rp); +} + +/* processing events using tasklet */ +static void gpi_ev_tasklet(unsigned long data) +{ + struct gpii *gpii = (struct gpii *)data; + + GPII_VERB(gpii, GPI_DBG_COMMON, "enter\n"); + + read_lock_bh(&gpii->pm_lock); + if (!REG_ACCESS_VALID(gpii->pm_state)) { + read_unlock_bh(&gpii->pm_lock); + GPII_ERR(gpii, GPI_DBG_COMMON, + "not processing any events, pm_state:%s\n", + TO_GPI_PM_STR(gpii->pm_state)); + return; + } + + /* process the events */ + gpi_process_events(gpii); + + /* enable IEOB, switching back to interrupts */ + gpi_config_interrupts(gpii, MASK_IEOB_SETTINGS, 1); + read_unlock_bh(&gpii->pm_lock); + + GPII_VERB(gpii, GPI_DBG_COMMON, "exit\n"); +} + +/* marks all pending events for the channel as stale */ +void gpi_mark_stale_events(struct gpii_chan *gpii_chan) +{ + struct gpii *gpii = gpii_chan->gpii; + struct gpi_ring *ev_ring = &gpii->ev_ring; + void *ev_rp; + u32 cntxt_rp, local_rp; + + GPII_INFO(gpii, gpii_chan->chid, "Enter\n"); + cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); + + ev_rp = ev_ring->rp; + local_rp = (u32)to_physical(ev_ring, ev_rp); + while (local_rp != cntxt_rp) { + union gpi_event *gpi_event = ev_rp; + u32 chid = gpi_event->xfer_compl_event.chid; + + if (chid == gpii_chan->chid) + gpi_event->xfer_compl_event.type = STALE_EV_TYPE; + ev_rp += ev_ring->el_size; + if (ev_rp >= (ev_ring->base + ev_ring->len)) + ev_rp = ev_ring->base; + cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); + local_rp = (u32)to_physical(ev_ring, ev_rp); + } +} + +/* reset sw state and issue channel reset or de-alloc */ +static int gpi_reset_chan(struct gpii_chan *gpii_chan, enum gpi_cmd gpi_cmd) +{ + struct gpii *gpii = gpii_chan->gpii; + struct gpi_ring *ch_ring = &gpii_chan->ch_ring; + unsigned long flags; + LIST_HEAD(list); + int ret; + + GPII_INFO(gpii, gpii_chan->chid, "Enter\n"); + ret = gpi_send_cmd(gpii, gpii_chan, gpi_cmd); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "Error with cmd:%s ret:%d\n", + TO_GPI_CMD_STR(gpi_cmd), ret); + return ret; + } + + /* initialize the local ring ptrs */ + ch_ring->rp = ch_ring->base; + ch_ring->wp = ch_ring->base; + + /* visible to other cores */ + smp_wmb(); + + /* check event ring for any stale events */ + write_lock_irq(&gpii->pm_lock); + gpi_mark_stale_events(gpii_chan); + + /* remove all async descriptors */ + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + vchan_get_all_descriptors(&gpii_chan->vc, &list); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + write_unlock_irq(&gpii->pm_lock); + vchan_dma_desc_free_list(&gpii_chan->vc, &list); + + return 0; +} + +static int gpi_start_chan(struct gpii_chan *gpii_chan) +{ + struct gpii *gpii = gpii_chan->gpii; + int ret; + + GPII_INFO(gpii, gpii_chan->chid, "Enter\n"); + + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_START); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "Error with cmd:%s ret:%d\n", + TO_GPI_CMD_STR(GPI_CH_CMD_START), ret); + return ret; + } + + /* gpii CH is active now */ + write_lock_irq(&gpii->pm_lock); + gpii_chan->pm_state = ACTIVE_STATE; + write_unlock_irq(&gpii->pm_lock); + + return 0; +} + +/* allocate and configure the transfer channel */ +static int gpi_alloc_chan(struct gpii_chan *gpii_chan, bool send_alloc_cmd) +{ + struct gpii *gpii = gpii_chan->gpii; + struct gpi_ring *ring = &gpii_chan->ch_ring; + int i; + int ret; + struct { + void *base; + int offset; + u32 val; + } ch_reg[] = { + { + gpii_chan->ch_cntxt_base_reg, + CNTXT_0_CONFIG, + GPI_GPII_n_CH_k_CNTXT_0(ring->el_size, 0, + gpii_chan->dir, + GPI_CHTYPE_PROTO_GPI), + }, + { + gpii_chan->ch_cntxt_base_reg, + CNTXT_1_R_LENGTH, + ring->len, + }, + { + gpii_chan->ch_cntxt_base_reg, + CNTXT_2_RING_BASE_LSB, + (u32)ring->phys_addr, + }, + { + gpii_chan->ch_cntxt_base_reg, + CNTXT_3_RING_BASE_MSB, + (u32)(ring->phys_addr >> 32), + }, + { /* program MSB of DB register with ring base */ + gpii_chan->ch_cntxt_db_reg, + CNTXT_5_RING_RP_MSB - CNTXT_4_RING_RP_LSB, + (u32)(ring->phys_addr >> 32), + }, + { + gpii->regs, + GPI_GPII_n_CH_k_SCRATCH_0_OFFS(gpii->gpii_id, + gpii_chan->chid), + GPI_GPII_n_CH_K_SCRATCH_0(!gpii_chan->chid, + gpii_chan->protocol, + gpii_chan->seid), + }, + { + gpii->regs, + GPI_GPII_n_CH_k_SCRATCH_1_OFFS(gpii->gpii_id, + gpii_chan->chid), + 0, + }, + { + gpii->regs, + GPI_GPII_n_CH_k_SCRATCH_2_OFFS(gpii->gpii_id, + gpii_chan->chid), + 0, + }, + { + gpii->regs, + GPI_GPII_n_CH_k_SCRATCH_3_OFFS(gpii->gpii_id, + gpii_chan->chid), + 0, + }, + { + gpii->regs, + GPI_GPII_n_CH_k_QOS_OFFS(gpii->gpii_id, + gpii_chan->chid), + 1, + }, + { NULL }, + }; + + GPII_INFO(gpii, gpii_chan->chid, "Enter\n"); + + if (send_alloc_cmd) { + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_ALLOCATE); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "Error with cmd:%s ret:%d\n", + TO_GPI_CMD_STR(GPI_CH_CMD_ALLOCATE), ret); + return ret; + } + } + + /* program channel cntxt registers */ + for (i = 0; ch_reg[i].base; i++) + gpi_write_reg(gpii, ch_reg[i].base + ch_reg[i].offset, + ch_reg[i].val); + /* flush all the writes */ + wmb(); + return 0; +} + +/* allocate and configure event ring */ +static int gpi_alloc_ev_chan(struct gpii *gpii) +{ + struct gpi_ring *ring = &gpii->ev_ring; + int i; + int ret; + struct { + void *base; + int offset; + u32 val; + } ev_reg[] = { + { + gpii->ev_cntxt_base_reg, + CNTXT_0_CONFIG, + GPI_GPII_n_EV_CH_k_CNTXT_0(ring->el_size, + GPI_INTTYPE_IRQ, + GPI_CHTYPE_GPI_EV), + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_1_R_LENGTH, + ring->len, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_2_RING_BASE_LSB, + (u32)ring->phys_addr, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_3_RING_BASE_MSB, + (u32)(ring->phys_addr >> 32), + }, + { + /* program db msg with ring base msb */ + gpii->ev_cntxt_db_reg, + CNTXT_5_RING_RP_MSB - CNTXT_4_RING_RP_LSB, + (u32)(ring->phys_addr >> 32), + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_8_RING_INT_MOD, + 0, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_10_RING_MSI_LSB, + 0, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_11_RING_MSI_MSB, + 0, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_8_RING_INT_MOD, + 0, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_12_RING_RP_UPDATE_LSB, + 0, + }, + { + gpii->ev_cntxt_base_reg, + CNTXT_13_RING_RP_UPDATE_MSB, + 0, + }, + { NULL }, + }; + + GPII_INFO(gpii, GPI_DBG_COMMON, "enter\n"); + + ret = gpi_send_cmd(gpii, NULL, GPI_EV_CMD_ALLOCATE); + if (ret) { + GPII_ERR(gpii, GPI_DBG_COMMON, "error with cmd:%s ret:%d\n", + TO_GPI_CMD_STR(GPI_EV_CMD_ALLOCATE), ret); + return ret; + } + + /* program event context */ + for (i = 0; ev_reg[i].base; i++) + gpi_write_reg(gpii, ev_reg[i].base + ev_reg[i].offset, + ev_reg[i].val); + + /* add events to ring */ + ring->wp = (ring->base + ring->len - ring->el_size); + + /* flush all the writes */ + wmb(); + + /* gpii is active now */ + write_lock_irq(&gpii->pm_lock); + gpii->pm_state = ACTIVE_STATE; + write_unlock_irq(&gpii->pm_lock); + gpi_write_ev_db(gpii, ring, ring->wp); + + return 0; +} + +/* calculate # of ERE/TRE available to queue */ +static int gpi_ring_num_elements_avail(const struct gpi_ring * const ring) +{ + int elements = 0; + + if (ring->wp < ring->rp) + elements = ((ring->rp - ring->wp) / ring->el_size) - 1; + else { + elements = (ring->rp - ring->base) / ring->el_size; + elements += ((ring->base + ring->len - ring->wp) / + ring->el_size) - 1; + } + + return elements; +} + +static int gpi_ring_add_element(struct gpi_ring *ring, void **wp) +{ + + if (gpi_ring_num_elements_avail(ring) <= 0) + return -ENOMEM; + + *wp = ring->wp; + ring->wp += ring->el_size; + if (ring->wp >= (ring->base + ring->len)) + ring->wp = ring->base; + + /* visible to other cores */ + smp_wmb(); + + return 0; +} + +static void gpi_ring_recycle_ev_element(struct gpi_ring *ring) +{ + /* Update the WP */ + ring->wp += ring->el_size; + if (ring->wp >= (ring->base + ring->len)) + ring->wp = ring->base; + + /* Update the RP */ + ring->rp += ring->el_size; + if (ring->rp >= (ring->base + ring->len)) + ring->rp = ring->base; + + /* visible to other cores */ + smp_wmb(); +} + +static void gpi_free_ring(struct gpi_ring *ring, + struct gpii *gpii) +{ + dma_free_coherent(gpii->gpi_dev->dev, ring->alloc_size, + ring->pre_aligned, ring->dma_handle); + memset(ring, 0, sizeof(*ring)); +} + +/* allocate memory for transfer and event rings */ +static int gpi_alloc_ring(struct gpi_ring *ring, + u32 elements, + u32 el_size, + struct gpii *gpii) +{ + u64 len = elements * el_size; + int bit; + + /* ring len must be power of 2 */ + bit = find_last_bit((unsigned long *)&len, 32); + if (((1 << bit) - 1) & len) + bit++; + len = 1 << bit; + ring->alloc_size = (len + (len - 1)); + GPII_INFO(gpii, GPI_DBG_COMMON, + "#el:%u el_size:%u len:%u actual_len:%llu alloc_size:%lu\n", + elements, el_size, (elements * el_size), len, + ring->alloc_size); + ring->pre_aligned = dma_alloc_coherent(gpii->gpi_dev->dev, + ring->alloc_size, + &ring->dma_handle, GFP_KERNEL); + if (!ring->pre_aligned) { + GPII_CRITIC(gpii, GPI_DBG_COMMON, + "could not alloc size:%lu mem for ring\n", + ring->alloc_size); + return -ENOMEM; + } + + /* align the physical mem */ + ring->phys_addr = (ring->dma_handle + (len - 1)) & ~(len - 1); + ring->base = ring->pre_aligned + (ring->phys_addr - ring->dma_handle); + ring->rp = ring->base; + ring->wp = ring->base; + ring->len = len; + ring->el_size = el_size; + ring->elements = ring->len / ring->el_size; + memset(ring->base, 0, ring->len); + ring->configured = true; + + /* update to other cores */ + smp_wmb(); + + GPII_INFO(gpii, GPI_DBG_COMMON, + "phy_pre:0x%0llx phy_alig:0x%0llx len:%u el_size:%u elements:%u\n", + ring->dma_handle, ring->phys_addr, ring->len, ring->el_size, + ring->elements); + + return 0; +} + +/* copy tre into transfer ring */ +static void gpi_queue_xfer(struct gpii *gpii, + struct gpii_chan *gpii_chan, + struct msm_gpi_tre *gpi_tre, + void **wp) +{ + struct msm_gpi_tre *ch_tre; + int ret; + + /* get next tre location we can copy */ + ret = gpi_ring_add_element(&gpii_chan->ch_ring, (void **)&ch_tre); + if (unlikely(ret)) { + GPII_CRITIC(gpii, gpii_chan->chid, + "Error adding ring element to xfer ring\n"); + return; + } + + /* copy the tre info */ + memcpy(ch_tre, gpi_tre, sizeof(*ch_tre)); + *wp = ch_tre; +} + +/* reset and restart transfer channel */ +int gpi_terminate_all(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + int schid, echid, i; + int ret = 0; + + GPII_INFO(gpii, gpii_chan->chid, "Enter\n"); + mutex_lock(&gpii->ctrl_lock); + + /* + * treat both channels as a group if its protocol is not UART + * STOP, RESET, or START needs to be in lockstep + */ + schid = (gpii->protocol == SE_PROTOCOL_UART) ? gpii_chan->chid : 0; + echid = (gpii->protocol == SE_PROTOCOL_UART) ? schid + 1 : + MAX_CHANNELS_PER_GPII; + + /* stop the channel */ + for (i = schid; i < echid; i++) { + gpii_chan = &gpii->gpii_chan[i]; + + /* disable ch state so no more TRE processing */ + write_lock_irq(&gpii->pm_lock); + gpii_chan->pm_state = PREPARE_TERMINATE; + write_unlock_irq(&gpii->pm_lock); + + /* send command to Stop the channel */ + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP); + if (ret) + GPII_ERR(gpii, gpii_chan->chid, + "Error Stopping Channel:%d resetting anyway\n", + ret); + } + + /* reset the channels (clears any pending tre) */ + for (i = schid; i < echid; i++) { + gpii_chan = &gpii->gpii_chan[i]; + + ret = gpi_reset_chan(gpii_chan, GPI_CH_CMD_RESET); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "Error resetting channel ret:%d\n", ret); + goto terminate_exit; + } + + /* reprogram channel CNTXT */ + ret = gpi_alloc_chan(gpii_chan, false); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "Error alloc_channel ret:%d\n", ret); + goto terminate_exit; + } + } + + /* restart the channels */ + for (i = schid; i < echid; i++) { + gpii_chan = &gpii->gpii_chan[i]; + + ret = gpi_start_chan(gpii_chan); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "Error Starting Channel ret:%d\n", ret); + goto terminate_exit; + } + } + +terminate_exit: + mutex_unlock(&gpii->ctrl_lock); + return ret; +} + +/* pause dma transfer for all channels */ +static int gpi_pause(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + int i, ret; + + GPII_INFO(gpii, gpii_chan->chid, "Enter\n"); + mutex_lock(&gpii->ctrl_lock); + + /* + * pause/resume are per gpii not per channel, so + * client needs to call pause only once + */ + if (gpii->pm_state == PAUSE_STATE) { + GPII_INFO(gpii, gpii_chan->chid, + "channel is already paused\n"); + mutex_unlock(&gpii->ctrl_lock); + return 0; + } + + /* send stop command to stop the channels */ + for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) { + ret = gpi_send_cmd(gpii, &gpii->gpii_chan[i], GPI_CH_CMD_STOP); + if (ret) { + GPII_ERR(gpii, gpii->gpii_chan[i].chid, + "Error stopping chan, ret:%d\n", ret); + mutex_unlock(&gpii->ctrl_lock); + return ret; + } + } + + disable_irq(gpii->irq); + + /* Wait for threads to complete out */ + tasklet_kill(&gpii->ev_task); + + write_lock_irq(&gpii->pm_lock); + gpii->pm_state = PAUSE_STATE; + write_unlock_irq(&gpii->pm_lock); + mutex_unlock(&gpii->ctrl_lock); + + return 0; +} + +/* resume dma transfer */ +static int gpi_resume(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + int i; + int ret; + + GPII_INFO(gpii, gpii_chan->chid, "enter\n"); + + mutex_lock(&gpii->ctrl_lock); + if (gpii->pm_state == ACTIVE_STATE) { + GPII_INFO(gpii, gpii_chan->chid, + "channel is already active\n"); + mutex_unlock(&gpii->ctrl_lock); + return 0; + } + + enable_irq(gpii->irq); + + /* send start command to start the channels */ + for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) { + ret = gpi_send_cmd(gpii, &gpii->gpii_chan[i], GPI_CH_CMD_START); + if (ret) { + GPII_ERR(gpii, gpii->gpii_chan[i].chid, + "Erro starting chan, ret:%d\n", ret); + mutex_unlock(&gpii->ctrl_lock); + return ret; + } + } + + write_lock_irq(&gpii->pm_lock); + gpii->pm_state = ACTIVE_STATE; + write_unlock_irq(&gpii->pm_lock); + mutex_unlock(&gpii->ctrl_lock); + + return 0; +} + +void gpi_desc_free(struct virt_dma_desc *vd) +{ + struct gpi_desc *gpi_desc = to_gpi_desc(vd); + + kfree(gpi_desc); +} + +/* copy tre into transfer ring */ +struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, + struct scatterlist *sgl, + unsigned int sg_len, + enum dma_transfer_direction direction, + unsigned long flags, + void *context) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + u32 nr; + u32 nr_req = 0; + int i, j; + struct scatterlist *sg; + struct gpi_ring *ch_ring = &gpii_chan->ch_ring; + void *tre, *wp = NULL; + const gfp_t gfp = GFP_ATOMIC; + struct gpi_desc *gpi_desc; + + GPII_VERB(gpii, gpii_chan->chid, "enter\n"); + + if (!is_slave_direction(direction)) { + GPII_ERR(gpii, gpii_chan->chid, + "invalid dma direction: %d\n", direction); + return NULL; + } + + /* calculate # of elements required & available */ + nr = gpi_ring_num_elements_avail(ch_ring); + for_each_sg(sgl, sg, sg_len, i) { + GPII_VERB(gpii, gpii_chan->chid, + "%d of %u len:%u\n", i, sg_len, sg->length); + nr_req += (sg->length / ch_ring->el_size); + } + GPII_VERB(gpii, gpii_chan->chid, "el avail:%u req:%u\n", nr, nr_req); + + if (nr < nr_req) { + GPII_ERR(gpii, gpii_chan->chid, + "not enough space in ring, avail:%u required:%u\n", + nr, nr_req); + return NULL; + } + + gpi_desc = kzalloc(sizeof(*gpi_desc), gfp); + if (!gpi_desc) { + GPII_ERR(gpii, gpii_chan->chid, + "out of memory for descriptor\n"); + return NULL; + } + + /* copy each tre into transfer ring */ + for_each_sg(sgl, sg, sg_len, i) + for (j = 0, tre = sg_virt(sg); j < sg->length; + j += ch_ring->el_size, tre += ch_ring->el_size) + gpi_queue_xfer(gpii, gpii_chan, tre, &wp); + + /* set up the descriptor */ + gpi_desc->db = ch_ring->wp; + gpi_desc->wp = wp; + gpi_desc->gpii_chan = gpii_chan; + GPII_VERB(gpii, gpii_chan->chid, "exit wp:0x%0llx rp:0x%0llx\n", + to_physical(ch_ring, ch_ring->wp), + to_physical(ch_ring, ch_ring->rp)); + + return vchan_tx_prep(&gpii_chan->vc, &gpi_desc->vd, flags); +} + +/* rings transfer ring db to being transfer */ +static void gpi_issue_pending(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + unsigned long flags, pm_lock_flags; + struct virt_dma_desc *vd = NULL; + struct gpi_desc *gpi_desc; + + GPII_VERB(gpii, gpii_chan->chid, "Enter\n"); + + read_lock_irqsave(&gpii->pm_lock, pm_lock_flags); + + /* move all submitted discriptors to issued list */ + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + if (vchan_issue_pending(&gpii_chan->vc)) + vd = list_last_entry(&gpii_chan->vc.desc_issued, + struct virt_dma_desc, node); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + + /* nothing to do list is empty */ + if (!vd) { + read_unlock_irqrestore(&gpii->pm_lock, pm_lock_flags); + GPII_VERB(gpii, gpii_chan->chid, "no descriptors submitted\n"); + return; + } + + gpi_desc = to_gpi_desc(vd); + gpi_write_ch_db(gpii_chan, &gpii_chan->ch_ring, gpi_desc->db); + read_unlock_irqrestore(&gpii->pm_lock, pm_lock_flags); +} + +/* configure or issue async command */ +static int gpi_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + struct msm_gpi_ctrl *gpi_ctrl = chan->private; + const int ev_factor = gpii->gpi_dev->ev_factor; + u32 elements; + int i = 0; + int ret = 0; + + GPII_INFO(gpii, gpii_chan->chid, "enter\n"); + if (!gpi_ctrl) { + GPII_ERR(gpii, gpii_chan->chid, + "no config ctrl data provided"); + return -EINVAL; + } + + mutex_lock(&gpii->ctrl_lock); + + switch (gpi_ctrl->cmd) { + case MSM_GPI_INIT: + GPII_INFO(gpii, gpii_chan->chid, "cmd: msm_gpi_init\n"); + + gpii_chan->client_info.callback = gpi_ctrl->init.callback; + gpii_chan->client_info.cb_param = gpi_ctrl->init.cb_param; + gpii_chan->pm_state = CONFIG_STATE; + + /* check if both channels are configured before continue */ + for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) + if (gpii->gpii_chan[i].pm_state != CONFIG_STATE) + goto exit_gpi_init; + + /* configure to highest priority from two channels */ + gpii->ev_priority = min(gpii->gpii_chan[0].priority, + gpii->gpii_chan[1].priority); + + /* protocol must be same for both channels */ + if (gpii->gpii_chan[0].protocol != + gpii->gpii_chan[1].protocol) { + GPII_ERR(gpii, gpii_chan->chid, + "protocol did not match protocol %u != %u\n", + gpii->gpii_chan[0].protocol, + gpii->gpii_chan[1].protocol); + ret = -EINVAL; + goto exit_gpi_init; + } + gpii->protocol = gpii_chan->protocol; + + /* allocate memory for event ring */ + elements = max(gpii->gpii_chan[0].req_tres, + gpii->gpii_chan[1].req_tres); + ret = gpi_alloc_ring(&gpii->ev_ring, elements << ev_factor, + sizeof(union gpi_event), gpii); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "error allocating mem for ev ring\n"); + goto exit_gpi_init; + } + + /* configure interrupts */ + write_lock_irq(&gpii->pm_lock); + gpii->pm_state = PREPARE_HARDWARE; + write_unlock_irq(&gpii->pm_lock); + ret = gpi_config_interrupts(gpii, DEFAULT_IRQ_SETTINGS, 0); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "error config. interrupts, ret:%d\n", ret); + goto error_config_int; + } + + /* allocate event rings */ + ret = gpi_alloc_ev_chan(gpii); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "error alloc_ev_chan:%d\n", ret); + goto error_alloc_ev_ring; + } + + /* Allocate all channels */ + for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) { + ret = gpi_alloc_chan(&gpii->gpii_chan[i], true); + if (ret) { + GPII_ERR(gpii, gpii->gpii_chan[i].chid, + "Error allocating chan:%d\n", ret); + goto error_alloc_chan; + } + } + + /* start channels */ + for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) { + ret = gpi_start_chan(&gpii->gpii_chan[i]); + if (ret) { + GPII_ERR(gpii, gpii->gpii_chan[i].chid, + "Error start chan:%d\n", ret); + goto error_start_chan; + } + } + + break; + case MSM_GPI_CMD_UART_SW_STALE: + GPII_INFO(gpii, gpii_chan->chid, "sending UART SW STALE cmd\n"); + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_UART_SW_STALE); + break; + case MSM_GPI_CMD_UART_RFR_READY: + GPII_INFO(gpii, gpii_chan->chid, + "sending UART RFR READY cmd\n"); + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_UART_RFR_READY); + break; + case MSM_GPI_CMD_UART_RFR_NOT_READY: + GPII_INFO(gpii, gpii_chan->chid, + "sending UART RFR READY NOT READY cmd\n"); + ret = gpi_send_cmd(gpii, gpii_chan, + GPI_CH_CMD_UART_RFR_NOT_READY); + break; + default: + GPII_ERR(gpii, gpii_chan->chid, + "unsupported ctrl cmd:%d\n", gpi_ctrl->cmd); + ret = -EINVAL; + } + + mutex_unlock(&gpii->ctrl_lock); + return ret; + +error_start_chan: + for (i = i - 1; i >= 0; i++) { + gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP); + gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_RESET); + } + i = 2; +error_alloc_chan: + for (i = i - 1; i >= 0; i--) + gpi_reset_chan(gpii_chan, GPI_CH_CMD_DE_ALLOC); +error_alloc_ev_ring: + gpi_disable_interrupts(gpii); +error_config_int: + gpi_free_ring(&gpii->ev_ring, gpii); +exit_gpi_init: + mutex_unlock(&gpii->ctrl_lock); + return ret; +} + +/* release all channel resources */ +static void gpi_free_chan_resources(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + enum gpi_pm_state cur_state; + int ret, i; + + GPII_INFO(gpii, gpii_chan->chid, "enter\n"); + + mutex_lock(&gpii->ctrl_lock); + + cur_state = gpii_chan->pm_state; + + /* disable ch state so no more TRE processing for this channel */ + write_lock_irq(&gpii->pm_lock); + gpii_chan->pm_state = PREPARE_TERMINATE; + write_unlock_irq(&gpii->pm_lock); + + /* attemp to do graceful hardware shutdown */ + if (cur_state == ACTIVE_STATE) { + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP); + if (ret) + GPII_ERR(gpii, gpii_chan->chid, + "error stopping channel:%d\n", ret); + + ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_RESET); + if (ret) + GPII_ERR(gpii, gpii_chan->chid, + "error resetting channel:%d\n", ret); + + gpi_reset_chan(gpii_chan, GPI_CH_CMD_DE_ALLOC); + } + + /* free all allocated memory */ + gpi_free_ring(&gpii_chan->ch_ring, gpii); + vchan_free_chan_resources(&gpii_chan->vc); + + write_lock_irq(&gpii->pm_lock); + gpii_chan->pm_state = DISABLE_STATE; + write_unlock_irq(&gpii->pm_lock); + + /* if other rings are still active exit */ + for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) + if (gpii->gpii_chan[i].ch_ring.configured) + goto exit_free; + + GPII_INFO(gpii, gpii_chan->chid, "disabling gpii\n"); + + /* deallocate EV Ring */ + cur_state = gpii->pm_state; + write_lock_irq(&gpii->pm_lock); + gpii->pm_state = PREPARE_TERMINATE; + write_unlock_irq(&gpii->pm_lock); + + /* wait for threads to complete out */ + tasklet_kill(&gpii->ev_task); + + /* send command to de allocate event ring */ + if (cur_state == ACTIVE_STATE) + gpi_send_cmd(gpii, NULL, GPI_EV_CMD_DEALLOC); + + gpi_free_ring(&gpii->ev_ring, gpii); + + /* disable interrupts */ + if (cur_state == ACTIVE_STATE) + gpi_disable_interrupts(gpii); + + /* set final state to disable */ + write_lock_irq(&gpii->pm_lock); + gpii->pm_state = DISABLE_STATE; + write_unlock_irq(&gpii->pm_lock); + +exit_free: + mutex_unlock(&gpii->ctrl_lock); +} + +/* allocate channel resources */ +static int gpi_alloc_chan_resources(struct dma_chan *chan) +{ + struct gpii_chan *gpii_chan = to_gpii_chan(chan); + struct gpii *gpii = gpii_chan->gpii; + int ret; + + GPII_INFO(gpii, gpii_chan->chid, "enter\n"); + + mutex_lock(&gpii->ctrl_lock); + + /* allocate memory for transfer ring */ + ret = gpi_alloc_ring(&gpii_chan->ch_ring, gpii_chan->req_tres, + sizeof(struct msm_gpi_tre), gpii); + if (ret) { + GPII_ERR(gpii, gpii_chan->chid, + "error allocating xfer ring, ret:%d\n", ret); + goto xfer_alloc_err; + } + mutex_unlock(&gpii->ctrl_lock); + + return 0; +xfer_alloc_err: + mutex_unlock(&gpii->ctrl_lock); + + return ret; +} + +static int gpi_find_avail_gpii(struct gpi_dev *gpi_dev, u32 seid) +{ + int gpii; + struct gpii_chan *tx_chan, *rx_chan; + + /* check if same seid is already configured for another chid */ + for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) { + if (!((1 << gpii) & gpi_dev->gpii_mask)) + continue; + + tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN]; + rx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_RX_CHAN]; + + if (rx_chan->vc.chan.client_count && rx_chan->seid == seid) + return gpii; + if (tx_chan->vc.chan.client_count && tx_chan->seid == seid) + return gpii; + } + + /* no channels configured with same seid, return next avail gpii */ + for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) { + if (!((1 << gpii) & gpi_dev->gpii_mask)) + continue; + + tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN]; + rx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_RX_CHAN]; + + /* check if gpii is configured */ + if (tx_chan->vc.chan.client_count || + rx_chan->vc.chan.client_count) + continue; + + /* found a free gpii */ + return gpii; + } + + /* no gpii instance available to use */ + return -EIO; +} + +/* gpi_of_dma_xlate: open client requested channel */ +static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args, + struct of_dma *of_dma) +{ + struct gpi_dev *gpi_dev = (struct gpi_dev *)of_dma->of_dma_data; + u32 seid, chid; + int gpii; + struct gpii_chan *gpii_chan; + + if (args->args_count < REQ_OF_DMA_ARGS) { + GPI_ERR(gpi_dev, + "gpii require minimum 6 args, client passed:%d args\n", + args->args_count); + return NULL; + } + + chid = args->args[0]; + if (chid >= MAX_CHANNELS_PER_GPII) { + GPI_ERR(gpi_dev, "gpii channel:%d not valid\n", chid); + return NULL; + } + + seid = args->args[1]; + + /* find next available gpii to use */ + gpii = gpi_find_avail_gpii(gpi_dev, seid); + if (gpii < 0) { + GPI_ERR(gpi_dev, "no available gpii instances\n"); + return NULL; + } + + gpii_chan = &gpi_dev->gpiis[gpii].gpii_chan[chid]; + if (gpii_chan->vc.chan.client_count) { + GPI_ERR(gpi_dev, "gpii:%d chid:%d seid:%d already configured\n", + gpii, chid, gpii_chan->seid); + return NULL; + } + + /* get ring size, protocol, se_id, and priority */ + gpii_chan->seid = seid; + gpii_chan->protocol = args->args[2]; + gpii_chan->req_tres = args->args[3]; + gpii_chan->priority = args->args[4]; + + GPI_LOG(gpi_dev, + "client req. gpii:%u chid:%u #_tre:%u priority:%u protocol:%u\n", + gpii, chid, gpii_chan->req_tres, gpii_chan->priority, + gpii_chan->protocol); + + return dma_get_slave_channel(&gpii_chan->vc.chan); +} + +/* gpi_setup_debug - setup debug capabilities */ +static void gpi_setup_debug(struct gpi_dev *gpi_dev) +{ + char node_name[GPI_LABEL_SIZE]; + const umode_t mode = 0600; + int i; + + snprintf(node_name, sizeof(node_name), "%s%llx", GPI_DMA_DRV_NAME, + (u64)gpi_dev->res->start); + + gpi_dev->ilctxt = ipc_log_context_create(IPC_LOG_PAGES, + node_name, 0); + gpi_dev->ipc_log_lvl = DEFAULT_IPC_LOG_LVL; + if (!IS_ERR_OR_NULL(pdentry)) { + snprintf(node_name, sizeof(node_name), "%llx", + (u64)gpi_dev->res->start); + gpi_dev->dentry = debugfs_create_dir(node_name, pdentry); + if (!IS_ERR_OR_NULL(gpi_dev->dentry)) { + debugfs_create_u32("ipc_log_lvl", mode, gpi_dev->dentry, + &gpi_dev->ipc_log_lvl); + debugfs_create_u32("klog_lvl", mode, + gpi_dev->dentry, &gpi_dev->klog_lvl); + } + } + + for (i = 0; i < gpi_dev->max_gpii; i++) { + struct gpii *gpii; + + if (!((1 << i) & gpi_dev->gpii_mask)) + continue; + + gpii = &gpi_dev->gpiis[i]; + snprintf(gpii->label, sizeof(gpii->label), + "%s%llx_gpii%d", + GPI_DMA_DRV_NAME, (u64)gpi_dev->res->start, i); + gpii->ilctxt = ipc_log_context_create(IPC_LOG_PAGES, + gpii->label, 0); + gpii->ipc_log_lvl = DEFAULT_IPC_LOG_LVL; + gpii->klog_lvl = DEFAULT_KLOG_LVL; + + if (IS_ERR_OR_NULL(gpi_dev->dentry)) + continue; + + snprintf(node_name, sizeof(node_name), "gpii%d", i); + gpii->dentry = debugfs_create_dir(node_name, gpi_dev->dentry); + if (IS_ERR_OR_NULL(gpii->dentry)) + continue; + + debugfs_create_u32("ipc_log_lvl", mode, gpii->dentry, + &gpii->ipc_log_lvl); + debugfs_create_u32("klog_lvl", mode, gpii->dentry, + &gpii->klog_lvl); + } +} + +static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev) +{ + dma_addr_t base; + size_t size; + + /* + * If S1_BYPASS enabled then iommu space is not used, however framework + * still require clients to create a mapping space before attaching. So + * set to smallest size required by iommu framework. + */ + if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) { + base = 0; + size = PAGE_SIZE; + } else { + base = gpi_dev->iova_base; + size = gpi_dev->iova_size; + } + + GPI_LOG(gpi_dev, "Creating iommu mapping of base:0x%llx size:%lu\n", + base, size); + + return arm_iommu_create_mapping(&platform_bus_type, base, size); +} + +static int gpi_dma_mask(struct gpi_dev *gpi_dev) +{ + int mask = 64; + + if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { + unsigned long addr; + + addr = gpi_dev->iova_base + gpi_dev->iova_size + 1; + mask = find_last_bit(&addr, 64); + } + + GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask); + + return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask)); +} + +static int gpi_smmu_init(struct gpi_dev *gpi_dev) +{ + struct dma_iommu_mapping *mapping = NULL; + int ret; + + if (gpi_dev->smmu_cfg) { + + /* create mapping table */ + mapping = gpi_create_mapping(gpi_dev); + if (IS_ERR(mapping)) { + GPI_ERR(gpi_dev, + "Failed to create iommu mapping, ret:%ld\n", + PTR_ERR(mapping)); + return PTR_ERR(mapping); + } + + if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) { + int s1_bypass = 1; + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_S1_BYPASS, &s1_bypass); + if (ret) { + GPI_ERR(gpi_dev, + "Failed to set attr S1_BYPASS, ret:%d\n", + ret); + goto release_mapping; + } + } + + if (gpi_dev->smmu_cfg & GPI_SMMU_FAST) { + int fast = 1; + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_FAST, &fast); + if (ret) { + GPI_ERR(gpi_dev, + "Failed to set attr FAST, ret:%d\n", + ret); + goto release_mapping; + } + } + + if (gpi_dev->smmu_cfg & GPI_SMMU_ATOMIC) { + int atomic = 1; + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_ATOMIC, &atomic); + if (ret) { + GPI_ERR(gpi_dev, + "Failed to set attr ATOMIC, ret:%d\n", + ret); + goto release_mapping; + } + } + + ret = arm_iommu_attach_device(gpi_dev->dev, mapping); + if (ret) { + GPI_ERR(gpi_dev, + "Failed with iommu_attach, ret:%d\n", ret); + goto release_mapping; + } + } + + ret = gpi_dma_mask(gpi_dev); + if (ret) { + GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret); + goto error_set_mask; + } + + return ret; + +error_set_mask: + if (gpi_dev->smmu_cfg) + arm_iommu_detach_device(gpi_dev->dev); +release_mapping: + if (mapping) + arm_iommu_release_mapping(mapping); + return ret; +} + +static int gpi_probe(struct platform_device *pdev) +{ + struct gpi_dev *gpi_dev; + int ret, i; + + gpi_dev = devm_kzalloc(&pdev->dev, sizeof(*gpi_dev), GFP_KERNEL); + if (!gpi_dev) + return -ENOMEM; + + gpi_dev->dev = &pdev->dev; + gpi_dev->klog_lvl = DEFAULT_KLOG_LVL; + gpi_dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "gpi-top"); + if (!gpi_dev->res) { + GPI_ERR(gpi_dev, "missing 'reg' DT node\n"); + return -EINVAL; + } + gpi_dev->regs = devm_ioremap_nocache(gpi_dev->dev, gpi_dev->res->start, + resource_size(gpi_dev->res)); + if (!gpi_dev->regs) { + GPI_ERR(gpi_dev, "IO remap failed\n"); + return -EFAULT; + } + + ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,max-num-gpii", + &gpi_dev->max_gpii); + if (ret) { + GPI_ERR(gpi_dev, "missing 'max-no-gpii' DT node\n"); + return ret; + } + + ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,gpii-mask", + &gpi_dev->gpii_mask); + if (ret) { + GPI_ERR(gpi_dev, "missing 'gpii-mask' DT node\n"); + return ret; + } + + ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,ev-factor", + &gpi_dev->ev_factor); + if (ret) { + GPI_ERR(gpi_dev, "missing 'qcom,ev-factor' DT node\n"); + return ret; + } + + ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,smmu-cfg", + &gpi_dev->smmu_cfg); + if (ret) { + GPI_ERR(gpi_dev, "missing 'qcom,smmu-cfg' DT node\n"); + return ret; + } + if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { + u64 iova_range[2]; + + ret = of_property_count_elems_of_size(gpi_dev->dev->of_node, + "qcom,iova-range", + sizeof(iova_range)); + if (ret != 1) { + GPI_ERR(gpi_dev, + "missing or incorrect 'qcom,iova-range' DT node ret:%d\n", + ret); + } + + ret = of_property_read_u64_array(gpi_dev->dev->of_node, + "qcom,iova-range", iova_range, + sizeof(iova_range) / sizeof(u64)); + if (ret) { + GPI_ERR(gpi_dev, + "could not read DT prop 'qcom,iova-range\n"); + return ret; + } + gpi_dev->iova_base = iova_range[0]; + gpi_dev->iova_size = iova_range[1]; + } + + ret = gpi_smmu_init(gpi_dev); + if (ret) { + GPI_ERR(gpi_dev, "error configuring smmu, ret:%d\n", ret); + return ret; + } + + gpi_dev->gpiis = devm_kzalloc(gpi_dev->dev, + sizeof(*gpi_dev->gpiis) * gpi_dev->max_gpii, + GFP_KERNEL); + if (!gpi_dev->gpiis) + return -ENOMEM; + + + /* setup all the supported gpii */ + INIT_LIST_HEAD(&gpi_dev->dma_device.channels); + for (i = 0; i < gpi_dev->max_gpii; i++) { + struct gpii *gpii = &gpi_dev->gpiis[i]; + int chan; + + if (!((1 << i) & gpi_dev->gpii_mask)) + continue; + + /* set up ev cntxt register map */ + gpii->ev_cntxt_base_reg = gpi_dev->regs + + GPI_GPII_n_EV_CH_k_CNTXT_0_OFFS(i, 0); + gpii->ev_cntxt_db_reg = gpi_dev->regs + + GPI_GPII_n_EV_CH_k_DOORBELL_0_OFFS(i, 0); + gpii->ev_ring_base_lsb_reg = gpii->ev_cntxt_base_reg + + CNTXT_2_RING_BASE_LSB; + gpii->ev_ring_rp_lsb_reg = gpii->ev_cntxt_base_reg + + CNTXT_4_RING_RP_LSB; + gpii->ev_ring_wp_lsb_reg = gpii->ev_cntxt_base_reg + + CNTXT_6_RING_WP_LSB; + gpii->ev_cmd_reg = gpi_dev->regs + + GPI_GPII_n_EV_CH_CMD_OFFS(i); + gpii->ieob_src_reg = gpi_dev->regs + + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_OFFS(i); + gpii->ieob_clr_reg = gpi_dev->regs + + GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(i); + + /* set up irq */ + ret = platform_get_irq(pdev, i); + if (ret < 0) { + GPI_ERR(gpi_dev, "could not req. irq for gpii%d ret:%d", + i, ret); + return ret; + } + gpii->irq = ret; + + /* set up channel specific register info */ + for (chan = 0; chan < MAX_CHANNELS_PER_GPII; chan++) { + struct gpii_chan *gpii_chan = &gpii->gpii_chan[chan]; + + /* set up ch cntxt register map */ + gpii_chan->ch_cntxt_base_reg = gpi_dev->regs + + GPI_GPII_n_CH_k_CNTXT_0_OFFS(i, chan); + gpii_chan->ch_cntxt_db_reg = gpi_dev->regs + + GPI_GPII_n_CH_k_DOORBELL_0_OFFS(i, chan); + gpii_chan->ch_ring_base_lsb_reg = + gpii_chan->ch_cntxt_base_reg + + CNTXT_2_RING_BASE_LSB; + gpii_chan->ch_ring_rp_lsb_reg = + gpii_chan->ch_cntxt_base_reg + + CNTXT_4_RING_RP_LSB; + gpii_chan->ch_ring_wp_lsb_reg = + gpii_chan->ch_cntxt_base_reg + + CNTXT_6_RING_WP_LSB; + gpii_chan->ch_cmd_reg = gpi_dev->regs + + GPI_GPII_n_CH_CMD_OFFS(i); + + /* vchan setup */ + vchan_init(&gpii_chan->vc, &gpi_dev->dma_device); + gpii_chan->vc.desc_free = gpi_desc_free; + gpii_chan->chid = chan; + gpii_chan->gpii = gpii; + gpii_chan->dir = GPII_CHAN_DIR[chan]; + } + mutex_init(&gpii->ctrl_lock); + rwlock_init(&gpii->pm_lock); + tasklet_init(&gpii->ev_task, gpi_ev_tasklet, + (unsigned long)gpii); + init_completion(&gpii->cmd_completion); + gpii->gpii_id = i; + gpii->regs = gpi_dev->regs; + gpii->gpi_dev = gpi_dev; + atomic_set(&gpii->dbg_index, 0); + } + + platform_set_drvdata(pdev, gpi_dev); + + /* clear and Set capabilities */ + dma_cap_zero(gpi_dev->dma_device.cap_mask); + dma_cap_set(DMA_SLAVE, gpi_dev->dma_device.cap_mask); + + /* configure dmaengine apis */ + gpi_dev->dma_device.directions = + BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + gpi_dev->dma_device.residue_granularity = + DMA_RESIDUE_GRANULARITY_DESCRIPTOR; + gpi_dev->dma_device.src_addr_widths = DMA_SLAVE_BUSWIDTH_8_BYTES; + gpi_dev->dma_device.dst_addr_widths = DMA_SLAVE_BUSWIDTH_8_BYTES; + gpi_dev->dma_device.device_alloc_chan_resources = + gpi_alloc_chan_resources; + gpi_dev->dma_device.device_free_chan_resources = + gpi_free_chan_resources; + gpi_dev->dma_device.device_tx_status = dma_cookie_status; + gpi_dev->dma_device.device_issue_pending = gpi_issue_pending; + gpi_dev->dma_device.device_prep_slave_sg = gpi_prep_slave_sg; + gpi_dev->dma_device.device_config = gpi_config; + gpi_dev->dma_device.device_terminate_all = gpi_terminate_all; + gpi_dev->dma_device.dev = gpi_dev->dev; + gpi_dev->dma_device.device_pause = gpi_pause; + gpi_dev->dma_device.device_resume = gpi_resume; + + /* register with dmaengine framework */ + ret = dma_async_device_register(&gpi_dev->dma_device); + if (ret) { + GPI_ERR(gpi_dev, "async_device_register failed ret:%d", ret); + return ret; + } + + ret = of_dma_controller_register(gpi_dev->dev->of_node, + gpi_of_dma_xlate, gpi_dev); + if (ret) { + GPI_ERR(gpi_dev, "of_dma_controller_reg failed ret:%d", ret); + return ret; + } + + /* setup debug capabilities */ + gpi_setup_debug(gpi_dev); + GPI_LOG(gpi_dev, "probe success\n"); + + return ret; +} + +static const struct of_device_id gpi_of_match[] = { + { .compatible = "qcom,gpi-dma" }, + {} +}; +MODULE_DEVICE_TABLE(of, gpi_of_match); + +static struct platform_driver gpi_driver = { + .probe = gpi_probe, + .driver = { + .name = GPI_DMA_DRV_NAME, + .of_match_table = gpi_of_match, + }, +}; + +static int __init gpi_init(void) +{ + pdentry = debugfs_create_dir(GPI_DMA_DRV_NAME, NULL); + return platform_driver_register(&gpi_driver); +} +module_init(gpi_init) + +MODULE_DESCRIPTION("QCOM GPI DMA engine driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/qcom/msm_gpi_mmio.h b/drivers/dma/qcom/msm_gpi_mmio.h new file mode 100644 index 0000000000000000000000000000000000000000..3fcff9e5faaa57ed982874f4d1943e7f95d0e09e --- /dev/null +++ b/drivers/dma/qcom/msm_gpi_mmio.h @@ -0,0 +1,224 @@ +/* Copyright (c) 2017, 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. + */ + +/* Register offsets from gpi-top */ +#define GPI_GPII_n_CH_k_CNTXT_0_OFFS(n, k) \ + (0x20000 + (0x4000 * (n)) + (0x80 * (k))) +#define GPI_GPII_n_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK (0xFF000000) +#define GPI_GPII_n_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT (24) +#define GPI_GPII_n_CH_k_CNTXT_0_CHSTATE_BMSK (0xF00000) +#define GPI_GPII_n_CH_k_CNTXT_0_CHSTATE_SHFT (20) +#define GPI_GPII_n_CH_k_CNTXT_0_ERINDEX_BMSK (0x7C000) +#define GPI_GPII_n_CH_k_CNTXT_0_ERINDEX_SHFT (14) +#define GPI_GPII_n_CH_k_CNTXT_0_CHID_BMSK (0x1F00) +#define GPI_GPII_n_CH_k_CNTXT_0_CHID_SHFT (8) +#define GPI_GPII_n_CH_k_CNTXT_0_EE_BMSK (0xF0) +#define GPI_GPII_n_CH_k_CNTXT_0_EE_SHFT (4) +#define GPI_GPII_n_CH_k_CNTXT_0_CHTYPE_DIR_BMSK (0x8) +#define GPI_GPII_n_CH_k_CNTXT_0_CHTYPE_DIR_SHFT (3) +#define GPI_GPII_n_CH_k_CNTXT_0_CHTYPE_PROTO_BMSK (0x7) +#define GPI_GPII_n_CH_k_CNTXT_0_CHTYPE_PROTO_SHFT (0) +#define GPI_GPII_n_CH_k_CNTXT_0(el_size, erindex, chtype_dir, chtype_proto) \ + ((el_size << 24) | (erindex << 14) | (chtype_dir << 3) | (chtype_proto)) +#define GPI_CHTYPE_DIR_IN (0) +#define GPI_CHTYPE_DIR_OUT (1) +#define GPI_CHTYPE_PROTO_GPI (0x2) +#define GPI_GPII_n_CH_k_CNTXT_1_R_LENGTH_BMSK (0xFFFF) +#define GPI_GPII_n_CH_k_CNTXT_1_R_LENGTH_SHFT (0) +#define GPI_GPII_n_CH_k_DOORBELL_0_OFFS(n, k) (0x22000 + (0x4000 * (n)) \ + + (0x8 * (k))) +#define GPI_GPII_n_CH_CMD_OFFS(n) (0x23008 + (0x4000 * (n))) +#define GPI_GPII_n_CH_CMD_OPCODE_BMSK (0xFF000000) +#define GPI_GPII_n_CH_CMD_OPCODE_SHFT (24) +#define GPI_GPII_n_CH_CMD_CHID_BMSK (0xFF) +#define GPI_GPII_n_CH_CMD_CHID_SHFT (0) +#define GPI_GPII_n_CH_CMD(opcode, chid) ((opcode << 24) | chid) +#define GPI_GPII_n_CH_CMD_ALLOCATE (0) +#define GPI_GPII_n_CH_CMD_START (1) +#define GPI_GPII_n_CH_CMD_STOP (2) +#define GPI_GPII_n_CH_CMD_RESET (9) +#define GPI_GPII_n_CH_CMD_DE_ALLOC (10) +#define GPI_GPII_n_CH_CMD_UART_SW_STALE (32) +#define GPI_GPII_n_CH_CMD_UART_RFR_READY (33) +#define GPI_GPII_n_CH_CMD_UART_RFR_NOT_READY (34) + +/* EV Context Array */ +#define GPI_GPII_n_EV_CH_k_CNTXT_0_OFFS(n, k) \ + (0x21000 + (0x4000 * (n)) + (0x80 * (k))) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK (0xFF000000) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT (24) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK (0xF00000) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT (20) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_INTYPE_BMSK (0x10000) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_INTYPE_SHFT (16) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_EVCHID_BMSK (0xFF00) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_EVCHID_SHFT (8) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_EE_BMSK (0xF0) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_EE_SHFT (4) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK (0xF) +#define GPI_GPII_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT (0) +#define GPI_GPII_n_EV_CH_k_CNTXT_0(el_size, intype, chtype) \ + ((el_size << 24) | (intype << 16) | (chtype)) +#define GPI_INTTYPE_IRQ (1) +#define GPI_CHTYPE_GPI_EV (0x2) +#define GPI_GPII_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK (0xFFFF) +#define GPI_GPII_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT (0) + +enum CNTXT_OFFS { + CNTXT_0_CONFIG = 0x0, + CNTXT_1_R_LENGTH = 0x4, + CNTXT_2_RING_BASE_LSB = 0x8, + CNTXT_3_RING_BASE_MSB = 0xC, + CNTXT_4_RING_RP_LSB = 0x10, + CNTXT_5_RING_RP_MSB = 0x14, + CNTXT_6_RING_WP_LSB = 0x18, + CNTXT_7_RING_WP_MSB = 0x1C, + CNTXT_8_RING_INT_MOD = 0x20, + CNTXT_9_RING_INTVEC = 0x24, + CNTXT_10_RING_MSI_LSB = 0x28, + CNTXT_11_RING_MSI_MSB = 0x2C, + CNTXT_12_RING_RP_UPDATE_LSB = 0x30, + CNTXT_13_RING_RP_UPDATE_MSB = 0x34, +}; + +#define GPI_GPII_n_EV_CH_k_DOORBELL_0_OFFS(n, k) \ + (0x22100 + (0x4000 * (n)) + (0x8 * (k))) +#define GPI_GPII_n_EV_CH_CMD_OFFS(n) \ + (0x23010 + (0x4000 * (n))) +#define GPI_GPII_n_EV_CH_CMD_OPCODE_BMSK (0xFF000000) +#define GPI_GPII_n_EV_CH_CMD_OPCODE_SHFT (24) +#define GPI_GPII_n_EV_CH_CMD_CHID_BMSK (0xFF) +#define GPI_GPII_n_EV_CH_CMD_CHID_SHFT (0) +#define GPI_GPII_n_EV_CH_CMD(opcode, chid) \ + ((opcode << 24) | chid) +#define GPI_GPII_n_EV_CH_CMD_ALLOCATE (0x00) +#define GPI_GPII_n_EV_CH_CMD_RESET (0x09) +#define GPI_GPII_n_EV_CH_CMD_DE_ALLOC (0x0A) + +#define GPI_GPII_n_CNTXT_TYPE_IRQ_OFFS(n) \ + (0x23080 + (0x4000 * (n))) + +/* mask type register */ +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ + (0x23088 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_BMSK (0x7F) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_SHFT (0) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_GENERAL (0x40) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_INTER_GPII_EV_CTRL (0x20) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_INTER_GPII_CH_CTRL (0x10) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_IEOB (0x08) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_GLOB (0x04) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL (0x02) +#define GPI_GPII_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL (0x01) + +#define GPI_GPII_n_CNTXT_SRC_GPII_CH_IRQ_OFFS(n) \ + (0x23090 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ + (0x23094 + (0x4000 * (n))) + +/* Mask channel control interrupt register */ +#define GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_OFFS(n) \ + (0x23098 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_BMSK (0x3) +#define GPI_GPII_n_CNTXT_SRC_CH_IRQ_MSK_SHFT (0) + +/* Mask event control interrupt register */ +#define GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ + (0x2309C + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_BMSK (0x1) +#define GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_MSK_SHFT (0) + +#define GPI_GPII_n_CNTXT_SRC_CH_IRQ_CLR_OFFS(n) \ + (0x230A0 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (0x230A4 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ + (0x230B0 + (0x4000 * (n))) + +/* Mask event interrupt register */ +#define GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ + (0x230B8 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_BMSK (0x1) +#define GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_SHFT (0) + +#define GPI_GPII_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ + (0x230C0 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ + (0x23100 + (0x4000 * (n))) +#define GPI_GLOB_IRQ_ERROR_INT_MSK (0x1) +#define GPI_GLOB_IRQ_GP_INT1_MSK (0x2) +#define GPI_GLOB_IRQ_GP_INT2_MSK (0x4) +#define GPI_GLOB_IRQ_GP_INT3_MSK (0x8) + +/* GPII specific Global - Enable bit register */ +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ + (0x23108 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_BMSK (0xF) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_SHFT (0) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_GP_INT3 (0x8) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_GP_INT2 (0x4) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_GP_INT1 (0x2) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_ERROR_INT (0x1) + +#define GPI_GPII_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ + (0x23110 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_GPII_IRQ_STTS_OFFS(n) \ + (0x23118 + (0x4000 * (n))) + +/* GPII general interrupt - Enable bit register */ +#define GPI_GPII_n_CNTXT_GPII_IRQ_EN_OFFS(n) \ + (0x23120 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_GPII_IRQ_EN_BMSK (0xF) +#define GPI_GPII_n_CNTXT_GPII_IRQ_EN_SHFT (0) +#define GPI_GPII_n_CNTXT_GPII_IRQ_EN_STACK_OVRFLOW (0x8) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_CMD_FIFO_OVRFLOW (0x4) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_BUS_ERROR (0x2) +#define GPI_GPII_n_CNTXT_GLOB_IRQ_EN_BREAK_POINT (0x1) + +#define GPI_GPII_n_CNTXT_GPII_IRQ_CLR_OFFS(n) \ + (0x23128 + (0x4000 * (n))) + +/* GPII Interrupt Type register */ +#define GPI_GPII_n_CNTXT_INTSET_OFFS(n) \ + (0x23180 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_INTSET_BMSK (0x1) +#define GPI_GPII_n_CNTXT_INTSET_SHFT (0) + +#define GPI_GPII_n_CNTXT_MSI_BASE_LSB_OFFS(n) \ + (0x23188 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_MSI_BASE_MSB_OFFS(n) \ + (0x2318C + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SCRATCH_0_OFFS(n) \ + (0x23400 + (0x4000 * (n))) +#define GPI_GPII_n_CNTXT_SCRATCH_1_OFFS(n) \ + (0x23404 + (0x4000 * (n))) + +#define GPI_GPII_n_ERROR_LOG_OFFS(n) \ + (0x23200 + (0x4000 * (n))) +#define GPI_GPII_n_ERROR_LOG_CLR_OFFS(n) \ + (0x23210 + (0x4000 * (n))) + +/* QOS Registers */ +#define GPI_GPII_n_CH_k_QOS_OFFS(n, k) \ + (0x2005C + (0x4000 * (n)) + (0x80 * (k))) + +/* Scratch registeres */ +#define GPI_GPII_n_CH_k_SCRATCH_0_OFFS(n, k) \ + (0x20060 + (0x4000 * (n)) + (0x80 * (k))) +#define GPI_GPII_n_CH_K_SCRATCH_0(pair, proto, seid) \ + ((pair << 16) | (proto << 4) | seid) +#define GPI_GPII_n_CH_k_SCRATCH_1_OFFS(n, k) \ + (0x20064 + (0x4000 * (n)) + (0x80 * (k))) +#define GPI_GPII_n_CH_k_SCRATCH_2_OFFS(n, k) \ + (0x20068 + (0x4000 * (n)) + (0x80 * (k))) +#define GPI_GPII_n_CH_k_SCRATCH_3_OFFS(n, k) \ + (0x2006C + (0x4000 * (n)) + (0x80 * (k))) diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 06ecdc38cee0a32dfa312a6ada4d807a560aa47d..6682b3eec2b66728c38e2630679284c656c68656 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -117,7 +117,7 @@ struct usb_dmac { #define USB_DMASWR 0x0008 #define USB_DMASWR_SWR (1 << 0) #define USB_DMAOR 0x0060 -#define USB_DMAOR_AE (1 << 2) +#define USB_DMAOR_AE (1 << 1) #define USB_DMAOR_DME (1 << 0) #define USB_DMASAR 0x0000 diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 307547f4848db818c254cbf67c63fe527fc6a189..ae3f60be7759e80a68a2354968fa0521222f1790 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -884,7 +884,7 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, struct virt_dma_desc *vdesc; enum dma_status status; unsigned long flags; - u32 residue; + u32 residue = 0; status = dma_cookie_status(c, cookie, state); if ((status == DMA_COMPLETE) || (!state)) @@ -892,16 +892,12 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, spin_lock_irqsave(&chan->vchan.lock, flags); vdesc = vchan_find_desc(&chan->vchan, cookie); - if (cookie == chan->desc->vdesc.tx.cookie) { + if (chan->desc && cookie == chan->desc->vdesc.tx.cookie) residue = stm32_dma_desc_residue(chan, chan->desc, chan->next_sg); - } else if (vdesc) { + else if (vdesc) residue = stm32_dma_desc_residue(chan, to_stm32_dma_desc(vdesc), 0); - } else { - residue = 0; - } - dma_set_residue(state, residue); spin_unlock_irqrestore(&chan->vchan.lock, flags); @@ -976,21 +972,18 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, struct stm32_dma_chan *chan; struct dma_chan *c; - if (dma_spec->args_count < 3) + if (dma_spec->args_count < 4) return NULL; cfg.channel_id = dma_spec->args[0]; cfg.request_line = dma_spec->args[1]; cfg.stream_config = dma_spec->args[2]; - cfg.threshold = 0; + cfg.threshold = dma_spec->args[3]; if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >= STM32_DMA_MAX_REQUEST_ID)) return NULL; - if (dma_spec->args_count > 3) - cfg.threshold = dma_spec->args[3]; - chan = &dmadev->chan[cfg.channel_id]; c = dma_get_slave_channel(&chan->vchan.chan); diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 3f24aeb48c0e6735f13995ded459cac776b2620f..43e88d85129e4fb6de951f8bbd55581f6a5a5fcf 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -49,12 +49,12 @@ struct ti_am335x_xbar_data { struct ti_am335x_xbar_map { u16 dma_line; - u16 mux_val; + u8 mux_val; }; -static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u16 val) +static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val) { - writeb_relaxed(val & 0x1f, iomem + event); + writeb_relaxed(val, iomem + event); } static void ti_am335x_xbar_free(struct device *dev, void *route_data) @@ -105,7 +105,7 @@ static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, } map->dma_line = (u16)dma_spec->args[0]; - map->mux_val = (u16)dma_spec->args[2]; + map->mux_val = (u8)dma_spec->args[2]; dma_spec->args[2] = 0; dma_spec->args_count = 2; @@ -149,6 +149,7 @@ static int ti_am335x_xbar_probe(struct platform_device *pdev) match = of_match_node(ti_am335x_master_match, dma_node); if (!match) { dev_err(&pdev->dev, "DMA master is not supported\n"); + of_node_put(dma_node); return -EINVAL; } @@ -261,13 +262,14 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, mutex_lock(&xbar->mutex); map->xbar_out = find_first_zero_bit(xbar->dma_inuse, xbar->dma_requests); - mutex_unlock(&xbar->mutex); if (map->xbar_out == xbar->dma_requests) { + mutex_unlock(&xbar->mutex); dev_err(&pdev->dev, "Run out of free DMA requests\n"); kfree(map); return ERR_PTR(-ENOMEM); } set_bit(map->xbar_out, xbar->dma_inuse); + mutex_unlock(&xbar->mutex); map->xbar_in = (u16)dma_spec->args[0]; @@ -339,6 +341,7 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev) match = of_match_node(ti_dra7_master_match, dma_node); if (!match) { dev_err(&pdev->dev, "DMA master is not supported\n"); + of_node_put(dma_node); return -EINVAL; } diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index 245d759d5ffcd3846edc6bd541f4f254457bc38f..6059d81e701ac70f8b3f75dcb3e467a7cddf3d0e 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -813,6 +813,7 @@ static int zx_dma_probe(struct platform_device *op) INIT_LIST_HEAD(&d->slave.channels); dma_cap_set(DMA_SLAVE, d->slave.cap_mask); dma_cap_set(DMA_MEMCPY, d->slave.cap_mask); + dma_cap_set(DMA_CYCLIC, d->slave.cap_mask); dma_cap_set(DMA_PRIVATE, d->slave.cap_mask); d->slave.dev = &op->dev; d->slave.device_free_chan_resources = zx_dma_free_chan_resources; diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index ee181c53626f5b574d0d5a1a2a559eaf00006673..6e197c1c213da8563e25c0867acacfba0fd98532 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2984,8 +2984,11 @@ static int __init amd64_edac_init(void) int err = -ENODEV; int i; + if (!x86_match_cpu(amd64_cpuids)) + return -ENODEV; + if (amd_cache_northbridges() < 0) - goto err_ret; + return -ENODEV; opstate_init(); @@ -2998,14 +3001,16 @@ static int __init amd64_edac_init(void) if (!msrs) goto err_free; - for (i = 0; i < amd_nb_num(); i++) - if (probe_one_instance(i)) { + for (i = 0; i < amd_nb_num(); i++) { + err = probe_one_instance(i); + if (err) { /* unwind properly */ while (--i >= 0) remove_one_instance(i); goto err_pci; } + } setup_pci_device(); @@ -3025,7 +3030,6 @@ static int __init amd64_edac_init(void) kfree(ecc_stngs); ecc_stngs = NULL; -err_ret: return err; } diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index c08870479054c6277c3eefcd7bc776c687efd783..dcb5f9481735afbd1b8074ff110e2496bd454658 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "edac_core.h" #include "mce_amd.h" diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 72e07e3cf718fb760c62cda09023b199857bcb13..16e0eb523439a8193df821056b68d3bd6a3a431f 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -227,7 +227,7 @@ #define NREC_RDWR(x) (((x)>>11) & 1) #define NREC_RANK(x) (((x)>>8) & 0x7) #define NRECMEMB 0xC0 -#define NREC_CAS(x) (((x)>>16) & 0xFFFFFF) +#define NREC_CAS(x) (((x)>>16) & 0xFFF) #define NREC_RAS(x) ((x) & 0x7FFF) #define NRECFGLOG 0xC4 #define NREEECFBDA 0xC8 @@ -371,7 +371,7 @@ struct i5000_error_info { /* These registers are input ONLY if there was a * Non-Recoverable Error */ u16 nrecmema; /* Non-Recoverable Mem log A */ - u16 nrecmemb; /* Non-Recoverable Mem log B */ + u32 nrecmemb; /* Non-Recoverable Mem log B */ }; @@ -407,7 +407,7 @@ static void i5000_get_error_info(struct mem_ctl_info *mci, NERR_FAT_FBD, &info->nerr_fat_fbd); pci_read_config_word(pvt->branchmap_werrors, NRECMEMA, &info->nrecmema); - pci_read_config_word(pvt->branchmap_werrors, + pci_read_config_dword(pvt->branchmap_werrors, NRECMEMB, &info->nrecmemb); /* Clear the error bits, by writing them back */ @@ -1293,7 +1293,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci) dimm->mtype = MEM_FB_DDR2; /* ask what device type on this row */ - if (MTR_DRAM_WIDTH(mtr)) + if (MTR_DRAM_WIDTH(mtr) == 8) dimm->dtype = DEV_X8; else dimm->dtype = DEV_X4; diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index 6ef6ad1ba16ef3351217074f2ba63316a07276e4..2ea2f32e608be9f916a038301cd90c0260a8d508 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -368,7 +368,7 @@ struct i5400_error_info { /* These registers are input ONLY if there was a Non-Rec Error */ u16 nrecmema; /* Non-Recoverable Mem log A */ - u16 nrecmemb; /* Non-Recoverable Mem log B */ + u32 nrecmemb; /* Non-Recoverable Mem log B */ }; @@ -458,7 +458,7 @@ static void i5400_get_error_info(struct mem_ctl_info *mci, NERR_FAT_FBD, &info->nerr_fat_fbd); pci_read_config_word(pvt->branchmap_werrors, NRECMEMA, &info->nrecmema); - pci_read_config_word(pvt->branchmap_werrors, + pci_read_config_dword(pvt->branchmap_werrors, NRECMEMB, &info->nrecmemb); /* Clear the error bits, by writing them back */ @@ -1207,13 +1207,14 @@ static int i5400_init_dimms(struct mem_ctl_info *mci) dimm->nr_pages = size_mb << 8; dimm->grain = 8; - dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4; + dimm->dtype = MTR_DRAM_WIDTH(mtr) == 8 ? + DEV_X8 : DEV_X4; dimm->mtype = MEM_FB_DDR2; /* * The eccc mechanism is SDDC (aka SECC), with * is similar to Chipkill. */ - dimm->edac_mode = MTR_DRAM_WIDTH(mtr) ? + dimm->edac_mode = MTR_DRAM_WIDTH(mtr) == 8 ? EDAC_S8ECD8ED : EDAC_S4ECD4ED; ndimms++; } diff --git a/drivers/edac/kryo3xx_arm64_edac.c b/drivers/edac/kryo3xx_arm64_edac.c index 4ac880bb97a2fe5ca9e8e538062964db2814108c..cf3fdde9337edc7d03bb02482e35d32a2b21d23b 100644 --- a/drivers/edac/kryo3xx_arm64_edac.c +++ b/drivers/edac/kryo3xx_arm64_edac.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -29,10 +30,11 @@ module_param(poll_msec, int, 0444); #endif #ifdef CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_CE -#define ARM64_ERP_PANIC_ON_CE 1 +static bool panic_on_ce = 1; #else -#define ARM64_ERP_PANIC_ON_CE 0 +static bool panic_on_ce; #endif +module_param_named(panic_on_ce, panic_on_ce, bool, 0664); #ifdef CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_UE #define ARM64_ERP_PANIC_ON_UE 1 @@ -62,7 +64,7 @@ static inline void set_errxctlr_el1(void) static inline void set_errxmisc_overflow(void) { - u64 val = 0x7F7F00000000; + u64 val = 0x7F7F00000000ULL; asm volatile("msr s3_0_c5_c5_0, %0" : : "r" (val)); } @@ -118,12 +120,14 @@ static const struct errors_edac errors[] = { #define DATA_BUF_ERR 0x2 #define CACHE_DATA_ERR 0x6 #define CACHE_TAG_DIRTY_ERR 0x7 -#define TLB_PARITY_ERR 0x8 -#define BUS_ERROR 0x18 +#define TLB_PARITY_ERR_DATA 0x8 +#define TLB_PARITY_ERR_TAG 0x9 +#define BUS_ERROR 0x12 struct erp_drvdata { struct edac_device_ctl_info *edev_ctl; struct erp_drvdata __percpu **erp_cpu_drvdata; + struct notifier_block nb_pm; int ppi; }; @@ -217,10 +221,13 @@ static void dump_err_reg(int errorcode, int level, u64 errxstatus, u64 errxmisc, edac_printk(KERN_CRIT, EDAC_CPU, "ECC Error from cache tag or dirty RAM\n"); break; - case TLB_PARITY_ERR: + case TLB_PARITY_ERR_DATA: edac_printk(KERN_CRIT, EDAC_CPU, "Parity error on TLB RAM\n"); break; + case TLB_PARITY_ERR_TAG: + edac_printk(KERN_CRIT, EDAC_CPU, "Parity error on TLB DATA\n"); + case BUS_ERROR: edac_printk(KERN_CRIT, EDAC_CPU, "Bus Error\n"); break; @@ -232,6 +239,8 @@ static void dump_err_reg(int errorcode, int level, u64 errxstatus, u64 errxmisc, else edac_printk(KERN_CRIT, EDAC_CPU, "Way: %d\n", (int) KRYO3XX_ERRXMISC_WAY(errxmisc) >> 2); + + edev_ctl->panic_on_ce = panic_on_ce; errors[errorcode].func(edev_ctl, smp_processor_id(), level, errors[errorcode].msg); } @@ -283,6 +292,16 @@ static void kryo3xx_check_l1_l2_ecc(void *info) spin_unlock_irqrestore(&local_handler_lock, flags); } +static bool l3_is_bus_error(u64 errxstatus) +{ + if (KRYO3XX_ERRXSTATUS_SERR(errxstatus) == BUS_ERROR) { + edac_printk(KERN_CRIT, EDAC_CPU, "Bus Error\n"); + return true; + } + + return false; +} + static void kryo3xx_check_l3_scu_error(struct edac_device_ctl_info *edev_ctl) { u64 errxstatus = 0; @@ -296,6 +315,11 @@ static void kryo3xx_check_l3_scu_error(struct edac_device_ctl_info *edev_ctl) if (KRYO3XX_ERRXSTATUS_VALID(errxstatus) && KRYO3XX_ERRXMISC_LVL(errxmisc) == L3) { + if (l3_is_bus_error(errxstatus)) { + if (edev_ctl->panic_on_ue) + panic("Causing panic due to Bus Error\n"); + return; + } if (KRYO3XX_ERRXSTATUS_UE(errxstatus)) { edac_printk(KERN_CRIT, EDAC_CPU, "Detected L3 uncorrectable error\n"); dump_err_reg(KRYO3XX_L3_UE, L3, errxstatus, errxmisc, @@ -345,17 +369,44 @@ static void initialize_registers(void *info) set_errxmisc_overflow(); } +static void init_regs_on_cpu(bool all_cpus) +{ + int cpu; + + write_errselr_el1(0); + if (all_cpus) { + for_each_possible_cpu(cpu) + smp_call_function_single(cpu, initialize_registers, + NULL, 1); + } else + initialize_registers(NULL); + + write_errselr_el1(1); + initialize_registers(NULL); +} + +static int kryo3xx_pmu_cpu_pm_notify(struct notifier_block *self, + unsigned long action, void *v) +{ + switch (action) { + case CPU_PM_EXIT: + init_regs_on_cpu(false); + kryo3xx_check_l3_scu_error(panic_handler_drvdata->edev_ctl); + kryo3xx_check_l1_l2_ecc(panic_handler_drvdata->edev_ctl); + break; + } + + return NOTIFY_OK; +} + static int kryo3xx_cpu_erp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct erp_drvdata *drv; int rc = 0; int fail = 0; - int cpu; - - for_each_possible_cpu(cpu) - smp_call_function_single(cpu, initialize_registers, NULL, 1); + init_regs_on_cpu(true); drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); @@ -379,8 +430,9 @@ static int kryo3xx_cpu_erp_probe(struct platform_device *pdev) drv->edev_ctl->mod_name = dev_name(dev); drv->edev_ctl->dev_name = dev_name(dev); drv->edev_ctl->ctl_name = "cache"; - drv->edev_ctl->panic_on_ce = ARM64_ERP_PANIC_ON_CE; + drv->edev_ctl->panic_on_ce = panic_on_ce; drv->edev_ctl->panic_on_ue = ARM64_ERP_PANIC_ON_UE; + drv->nb_pm.notifier_call = kryo3xx_pmu_cpu_pm_notify; platform_set_drvdata(pdev, drv); rc = edac_device_add_device(drv->edev_ctl); @@ -405,6 +457,8 @@ static int kryo3xx_cpu_erp_probe(struct platform_device *pdev) goto out_dev; } + cpu_pm_register_notifier(&(drv->nb_pm)); + return 0; out_dev: diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index daaac2c79ca7a73def4c899b0f14919c04ad5aa2..7db692ed3dea8798ddc56ef94fb2bcd0956f3ef5 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -981,20 +981,19 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) pr_cont("]: 0x%016llx\n", m->status); if (m->status & MCI_STATUS_ADDRV) - pr_emerg(HW_ERR "Error Addr: 0x%016llx", m->addr); + pr_emerg(HW_ERR "Error Addr: 0x%016llx\n", m->addr); if (boot_cpu_has(X86_FEATURE_SMCA)) { + pr_emerg(HW_ERR "IPID: 0x%016llx", m->ipid); + if (m->status & MCI_STATUS_SYNDV) pr_cont(", Syndrome: 0x%016llx", m->synd); - pr_cont(", IPID: 0x%016llx", m->ipid); - pr_cont("\n"); decode_smca_errors(m); goto err_code; - } else - pr_cont("\n"); + } if (!fam_ops) goto err_code; diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c index 4403f86fda5ebdf0a4c868f75e36b25420ca2eb1..038e89c592521bf6e4c1204392ef9ca3a65446b5 100644 --- a/drivers/edac/qcom_llcc_edac.c +++ b/drivers/edac/qcom_llcc_edac.c @@ -103,7 +103,7 @@ struct errors_edac { struct erp_drvdata { struct regmap *llcc_map; - phys_addr_t *llcc_banks; + u32 *llcc_banks; u32 ecc_irq; u32 num_banks; u32 b_off; @@ -291,7 +291,7 @@ static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl, qcom_llcc_clear_errors(err_type, drv); - errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg); + errors[err_type].func(edev_ctl, 0, bank, errors[err_type].msg); } static void qcom_llcc_check_cache_errors @@ -353,12 +353,29 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) struct erp_drvdata *drv; struct edac_device_ctl_info *edev_ctl; struct device *dev = &pdev->dev; - u32 *banks; - u32 i; + u32 num_banks; + struct regmap *llcc_map = NULL; + + llcc_map = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(llcc_map)) { + dev_err(dev, "no regmap for syscon llcc parent\n"); + return -ENOMEM; + } + + /* Find the number of LLC banks supported */ + regmap_read(llcc_map, LLCC_COMMON_STATUS0, + &num_banks); + + num_banks &= LLCC_LB_CNT_MASK; + num_banks >>= LLCC_LB_CNT_SHIFT; /* Allocate edac control info */ edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1, - NULL, 1, 1, NULL, 0, edac_device_alloc_index()); + "bank", num_banks, 1, NULL, 0, + edac_device_alloc_index()); + + if (!edev_ctl) + return -ENOMEM; edev_ctl->dev = dev; edev_ctl->mod_name = dev_name(dev); @@ -373,72 +390,59 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; drv = edev_ctl->pvt_info; + drv->num_banks = num_banks; + drv->llcc_map = llcc_map; - drv->llcc_map = syscon_node_to_regmap(dev->parent->of_node); - if (IS_ERR(drv->llcc_map)) { - dev_err(dev, "no regmap for syscon llcc parent\n"); - rc = -ENOMEM; - goto out; - } - - if (interrupt_mode) { - drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq"); - if (!drv->ecc_irq) { - rc = -ENODEV; - goto out; - } - - rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler, - IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); - if (rc) { - dev_err(dev, "failed to request ecc irq\n"); - goto out; - } - } - - /* Find the number of LLC banks supported */ - regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0, - &drv->num_banks); - - drv->num_banks &= LLCC_LB_CNT_MASK; - drv->num_banks >>= LLCC_LB_CNT_SHIFT; + rc = edac_device_add_device(edev_ctl); + if (rc) + goto out_mem; drv->llcc_banks = devm_kzalloc(&pdev->dev, - sizeof(phys_addr_t) * drv->num_banks, GFP_KERNEL); + sizeof(u32) * drv->num_banks, GFP_KERNEL); - if (!drv->num_banks) { + if (!drv->llcc_banks) { dev_err(dev, "Cannot allocate memory for llcc_banks\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_dev; } - banks = devm_kzalloc(&pdev->dev, - sizeof(u32) * drv->num_banks, GFP_KERNEL); - if (!banks) - return -ENOMEM; - rc = of_property_read_u32_array(dev->parent->of_node, - "qcom,llcc-banks-off", banks, drv->num_banks); + "qcom,llcc-banks-off", drv->llcc_banks, drv->num_banks); if (rc) { dev_err(dev, "Cannot read llcc-banks-off property\n"); - return -EINVAL; + goto out_dev; } rc = of_property_read_u32(dev->parent->of_node, "qcom,llcc-broadcast-off", &drv->b_off); if (rc) { dev_err(dev, "Cannot read llcc-broadcast-off property\n"); - return -EINVAL; + goto out_dev; } - for (i = 0; i < drv->num_banks; i++) - drv->llcc_banks[i] = banks[i]; - platform_set_drvdata(pdev, edev_ctl); - rc = edac_device_add_device(edev_ctl); -out: - if (rc) - edac_device_free_ctl_info(edev_ctl); + if (interrupt_mode) { + drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq"); + if (!drv->ecc_irq) { + rc = -ENODEV; + goto out_dev; + } + + rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler, + IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); + if (rc) { + dev_err(dev, "failed to request ecc irq\n"); + goto out_dev; + } + } + + return 0; + +out_dev: + edac_device_del_device(edev_ctl->dev); +out_mem: + edac_device_free_ctl_info(edev_ctl); return rc; } diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 54775221a01fbe73d6a184ac903ccafc7e76c50c..3c47e6361d8127faeacce4d8b88df28d849a1eb2 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -2510,6 +2510,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, break; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: pvt->pci_ta = pdev; + break; case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS: pvt->pci_ras = pdev; break; diff --git a/drivers/esoc/Kconfig b/drivers/esoc/Kconfig index a56c7e0a66495e0ada7490944297856d33a61ae2..461315062c78c0963b917164bc87417486548edf 100644 --- a/drivers/esoc/Kconfig +++ b/drivers/esoc/Kconfig @@ -38,7 +38,7 @@ config ESOC_DEBUG allow logging of different esoc driver traces. config ESOC_MDM_4x - bool "Add support for external mdm9x25/mdm9x35/mdm9x45/mdm9x55" + bool "Add support for external modem" help In some Qualcomm Technologies, Inc. boards, an external modem such as mdm9x25 or mdm9x35 is connected to a primary msm. The primary soc can @@ -49,7 +49,7 @@ config ESOC_MDM_DRV tristate "Command engine for 4x series external modems" help Provides a command engine to control the behavior of an external modem - such as mdm9x25/mdm9x35/mdm9x45/mdm9x55/QSC. Allows the primary soc to put the + such as mdm9x25/mdm9x35/mdm9x55/sdxpoorwills/QSC. Allows the primary soc to put the external modem in a specific mode. Also listens for events on the external modem. diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index 334278b1a831f89c45544c694e4da79e6646672a..bbec9d3b33f7176f2cc156b71612d6f8348daee0 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2017-2018, 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 @@ -88,12 +88,10 @@ static void mdm_enable_irqs(struct mdm_ctrl *mdm) return; if (mdm->irq_mask & IRQ_ERRFATAL) { enable_irq(mdm->errfatal_irq); - irq_set_irq_wake(mdm->errfatal_irq, 1); mdm->irq_mask &= ~IRQ_ERRFATAL; } if (mdm->irq_mask & IRQ_STATUS) { enable_irq(mdm->status_irq); - irq_set_irq_wake(mdm->status_irq, 1); mdm->irq_mask &= ~IRQ_STATUS; } if (mdm->irq_mask & IRQ_PBLRDY) { @@ -107,12 +105,10 @@ static void mdm_disable_irqs(struct mdm_ctrl *mdm) if (!mdm) return; if (!(mdm->irq_mask & IRQ_ERRFATAL)) { - irq_set_irq_wake(mdm->errfatal_irq, 0); disable_irq_nosync(mdm->errfatal_irq); mdm->irq_mask |= IRQ_ERRFATAL; } if (!(mdm->irq_mask & IRQ_STATUS)) { - irq_set_irq_wake(mdm->status_irq, 0); disable_irq_nosync(mdm->status_irq); mdm->irq_mask |= IRQ_STATUS; } @@ -179,26 +175,48 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc) struct device *dev = mdm->dev; int ret; bool graceful_shutdown = false; + u32 status, err_fatal; switch (cmd) { case ESOC_PWR_ON: + if (esoc->auto_boot) { + /* + * If esoc has already booted, we would have missed + * status change interrupt. Read status and err_fatal + * signals to arrive at the state of esoc. + */ + esoc->clink_ops->get_status(&status, esoc); + esoc->clink_ops->get_err_fatal(&err_fatal, esoc); + if (err_fatal) + return -EIO; + if (status && !mdm->ready) { + mdm->ready = true; + esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc); + } + } gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0); - mdm_enable_irqs(mdm); mdm->init = 1; mdm_do_first_power_on(mdm); + mdm_enable_irqs(mdm); break; case ESOC_PWR_OFF: mdm_disable_irqs(mdm); mdm->debug = 0; mdm->ready = false; mdm->trig_cnt = 0; + if (esoc->primary) + break; graceful_shutdown = true; - ret = sysmon_send_shutdown(&esoc->subsys); - if (ret) { - dev_err(mdm->dev, "sysmon shutdown fail, ret = %d\n", - ret); - graceful_shutdown = false; - goto force_poff; + if (!esoc->userspace_handle_shutdown) { + ret = sysmon_send_shutdown(&esoc->subsys); + if (ret) { + dev_err(mdm->dev, + "sysmon shutdown fail, ret = %d\n", ret); + graceful_shutdown = false; + goto force_poff; + } + } else { + esoc_clink_queue_request(ESOC_REQ_SEND_SHUTDOWN, esoc); } dev_dbg(mdm->dev, "Waiting for status gpio go low\n"); status_down = false; @@ -229,12 +247,17 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc) esoc->subsys.sysmon_shutdown_ret); } + if (esoc->primary) + break; /* * Force a shutdown of the mdm. This is required in order * to prevent the mdm from immediately powering back on - * after the shutdown + * after the shutdown. Avoid setting status to 0, if line is + * monitored by multiple mdms(might be wrongly interpreted as + * a primary crash). */ - gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0); + if (esoc->statusline_not_a_powersource == false) + gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0); esoc_clink_queue_request(ESOC_REQ_SHUTDOWN, esoc); mdm_power_down(mdm); mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG); @@ -250,9 +273,12 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc) */ mdm->ready = false; cancel_delayed_work(&mdm->mdm2ap_status_check_work); - gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); - dev_dbg(mdm->dev, "set ap2mdm errfatal to force reset\n"); - msleep(mdm->ramdump_delay_ms); + if (!mdm->esoc->auto_boot) { + gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); + dev_dbg(mdm->dev, + "set ap2mdm errfatal to force reset\n"); + msleep(mdm->ramdump_delay_ms); + } break; case ESOC_EXE_DEBUG: mdm->debug = 1; @@ -380,6 +406,8 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) status_down = false; dev_dbg(dev, "signal apq err fatal for graceful restart\n"); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); + if (esoc->primary) + break; timeout = local_clock(); do_div(timeout, NSEC_PER_MSEC); timeout += MDM_MODEM_TIMEOUT; @@ -421,7 +449,8 @@ static irqreturn_t mdm_errfatal(int irq, void *dev_id) goto mdm_pwroff_irq; esoc = mdm->esoc; dev_err(dev, "%s: mdm sent errfatal interrupt\n", - __func__); + __func__); + subsys_set_crash_status(esoc->subsys_dev, true); /* disable irq ?*/ esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc); return IRQ_HANDLED; @@ -442,11 +471,26 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id) return IRQ_HANDLED; dev = mdm->dev; esoc = mdm->esoc; + /* + * On auto boot devices, there is a possibility of receiving + * status change interrupt before esoc_clink structure is + * initialized. Ignore them. + */ + if (!esoc) + return IRQ_HANDLED; value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)); if (value == 0 && mdm->ready) { dev_err(dev, "unexpected reset external modem\n"); + subsys_set_crash_status(esoc->subsys_dev, true); esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc); } else if (value == 1) { + /* + * In auto_boot cases, bailout early if mdm + * is up already. + */ + if (esoc->auto_boot && mdm->ready) + return IRQ_HANDLED; + cancel_delayed_work(&mdm->mdm2ap_status_check_work); dev_dbg(dev, "status = 1: mdm is now ready\n"); mdm->ready = true; @@ -454,6 +498,8 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id) queue_work(mdm->mdm_queue, &mdm->mdm_status_work); if (mdm->get_restart_reason) queue_work(mdm->mdm_queue, &mdm->restart_reason_work); + if (esoc->auto_boot) + esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc); } return IRQ_HANDLED; } @@ -482,7 +528,7 @@ static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id) return IRQ_HANDLED; } -static int mdm_get_status(u32 *status, struct esoc_clink *esoc) +static void mdm_get_status(u32 *status, struct esoc_clink *esoc) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); @@ -490,7 +536,16 @@ static int mdm_get_status(u32 *status, struct esoc_clink *esoc) *status = 0; else *status = 1; - return 0; +} + +static void mdm_get_err_fatal(u32 *status, struct esoc_clink *esoc) +{ + struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); + + if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)) == 0) + *status = 0; + else + *status = 1; } static void mdm_configure_debug(struct mdm_ctrl *mdm) @@ -573,13 +628,21 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) &mdm->ramdump_delay_ms); if (ret) mdm->ramdump_delay_ms = DEF_RAMDUMP_DELAY; - /* Multilple gpio_request calls are allowed */ + /* + * In certain scenarios, multiple esoc devices are monitoring + * same AP2MDM_STATUS line. But only one of them will have a + * successful gpio_request call. Initialize gpio only if request + * succeeds. + */ if (gpio_request(MDM_GPIO(mdm, AP2MDM_STATUS), "AP2MDM_STATUS")) dev_err(dev, "Failed to configure AP2MDM_STATUS gpio\n"); - /* Multilple gpio_request calls are allowed */ + else + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0); if (gpio_request(MDM_GPIO(mdm, AP2MDM_ERRFATAL), "AP2MDM_ERRFATAL")) dev_err(dev, "%s Failed to configure AP2MDM_ERRFATAL gpio\n", __func__); + else + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0); if (gpio_request(MDM_GPIO(mdm, MDM2AP_STATUS), "MDM2AP_STATUS")) { dev_err(dev, "%s Failed to configure MDM2AP_STATUS gpio\n", __func__); @@ -612,9 +675,6 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) } } - gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0); - gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0); - if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_CHNLRDY))) gpio_direction_output(MDM_GPIO(mdm, AP2MDM_CHNLRDY), 0); @@ -637,6 +697,7 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) goto errfatal_err; } mdm->errfatal_irq = irq; + irq_set_irq_wake(mdm->errfatal_irq, 1); errfatal_err: /* status irq */ @@ -655,6 +716,7 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) goto status_err; } mdm->status_irq = irq; + irq_set_irq_wake(mdm->status_irq, 1); status_err: if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) { irq = platform_get_irq_byname(pdev, "plbrdy_irq"); @@ -732,6 +794,28 @@ static int mdm_pinctrl_init(struct mdm_ctrl *mdm) mdm->gpio_state_running = NULL; return retval; } + +static void mdm_release_ipc_gpio(struct mdm_ctrl *mdm) +{ + int i; + + if (!mdm) + return; + + for (i = 0; i < NUM_GPIOS; ++i) + if (gpio_is_valid(MDM_GPIO(mdm, i))) + gpio_free(MDM_GPIO(mdm, i)); +} + +static void mdm_free_irq(struct mdm_ctrl *mdm) +{ + if (!mdm) + return; + + free_irq(mdm->errfatal_irq, mdm); + free_irq(mdm->status_irq, mdm); +} + static int mdm9x25_setup_hw(struct mdm_ctrl *mdm, const struct mdm_ops *ops, struct platform_device *pdev) @@ -748,6 +832,7 @@ static int mdm9x25_setup_hw(struct mdm_ctrl *mdm, dev_err(mdm->dev, "cannot allocate esoc device\n"); return PTR_ERR(esoc); } + esoc->pdev = pdev; mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); if (!mdm->mdm_queue) { dev_err(mdm->dev, "could not create mdm_queue\n"); @@ -818,6 +903,7 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm, dev_err(mdm->dev, "cannot allocate esoc device\n"); return PTR_ERR(esoc); } + esoc->pdev = pdev; mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); if (!mdm->mdm_queue) { dev_err(mdm->dev, "could not create mdm_queue\n"); @@ -906,6 +992,7 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, dev_err(mdm->dev, "cannot allocate esoc device\n"); return PTR_ERR(esoc); } + esoc->pdev = pdev; mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); if (!mdm->mdm_queue) { dev_err(mdm->dev, "could not create mdm_queue\n"); @@ -963,9 +1050,112 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm, return 0; } +static int sdxpoorwills_setup_hw(struct mdm_ctrl *mdm, + const struct mdm_ops *ops, + struct platform_device *pdev) +{ + int ret; + struct device_node *node; + struct esoc_clink *esoc; + const struct esoc_clink_ops *clink_ops = ops->clink_ops; + const struct mdm_pon_ops *pon_ops = ops->pon_ops; + + mdm->dev = &pdev->dev; + mdm->pon_ops = pon_ops; + node = pdev->dev.of_node; + + esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL); + if (IS_ERR_OR_NULL(esoc)) { + dev_err(mdm->dev, "cannot allocate esoc device\n"); + return PTR_ERR(esoc); + } + + esoc->pdev = pdev; + + mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); + if (!mdm->mdm_queue) { + dev_err(mdm->dev, "could not create mdm_queue\n"); + return -ENOMEM; + } + + mdm->irq_mask = 0; + mdm->ready = false; + + ret = mdm_dt_parse_gpios(mdm); + if (ret) { + dev_err(mdm->dev, "Failed to parse DT gpios\n"); + goto err_destroy_wrkq; + } + + ret = mdm_pon_dt_init(mdm); + if (ret) { + dev_err(mdm->dev, "Failed to parse PON DT gpio\n"); + goto err_destroy_wrkq; + } + + ret = mdm_pinctrl_init(mdm); + if (ret) { + dev_err(mdm->dev, "Failed to init pinctrl\n"); + goto err_destroy_wrkq; + } + + ret = mdm_pon_setup(mdm); + if (ret) { + dev_err(mdm->dev, "Failed to setup PON\n"); + goto err_destroy_wrkq; + } + + ret = mdm_configure_ipc(mdm, pdev); + if (ret) { + dev_err(mdm->dev, "Failed to configure the ipc\n"); + goto err_release_ipc; + } + + esoc->name = SDXPOORWILLS_LABEL; + esoc->link_name = SDXPOORWILLS_PCIE; + + ret = of_property_read_string(node, "qcom,mdm-link-info", + &esoc->link_info); + if (ret) + dev_info(mdm->dev, "esoc link info missing\n"); + + esoc->clink_ops = clink_ops; + esoc->parent = mdm->dev; + esoc->owner = THIS_MODULE; + esoc->np = pdev->dev.of_node; + set_esoc_clink_data(esoc, mdm); + + ret = esoc_clink_register(esoc); + if (ret) { + dev_err(mdm->dev, "esoc registration failed\n"); + goto err_free_irq; + } + dev_dbg(mdm->dev, "esoc registration done\n"); + + init_completion(&mdm->debug_done); + INIT_WORK(&mdm->mdm_status_work, mdm_status_fn); + INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason); + INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check); + mdm->get_restart_reason = false; + mdm->debug_fail = false; + mdm->esoc = esoc; + mdm->init = 0; + + return 0; + +err_free_irq: + mdm_free_irq(mdm); +err_release_ipc: + mdm_release_ipc_gpio(mdm); +err_destroy_wrkq: + destroy_workqueue(mdm->mdm_queue); + return ret; +} + static struct esoc_clink_ops mdm_cops = { .cmd_exe = mdm_cmd_exe, .get_status = mdm_get_status, + .get_err_fatal = mdm_get_err_fatal, .notify = mdm_notify, }; @@ -987,6 +1177,12 @@ static struct mdm_ops mdm9x55_ops = { .pon_ops = &mdm9x55_pon_ops, }; +static struct mdm_ops sdxpoorwills_ops = { + .clink_ops = &mdm_cops, + .config_hw = sdxpoorwills_setup_hw, + .pon_ops = &sdxpoorwills_pon_ops, +}; + static const struct of_device_id mdm_dt_match[] = { { .compatible = "qcom,ext-mdm9x25", .data = &mdm9x25_ops, }, @@ -994,6 +1190,8 @@ static const struct of_device_id mdm_dt_match[] = { .data = &mdm9x35_ops, }, { .compatible = "qcom,ext-mdm9x55", .data = &mdm9x55_ops, }, + { .compatible = "qcom,ext-sdxpoorwills", + .data = &sdxpoorwills_ops, }, {}, }; MODULE_DEVICE_TABLE(of, mdm_dt_match); diff --git a/drivers/esoc/esoc-mdm-dbg-eng.c b/drivers/esoc/esoc-mdm-dbg-eng.c index 309c82090c48a0ded20c653f9f97deb1e263d7c7..a61588a714d426458085af8cb0f099a59aa051ca 100644 --- a/drivers/esoc/esoc-mdm-dbg-eng.c +++ b/drivers/esoc/esoc-mdm-dbg-eng.c @@ -269,7 +269,7 @@ static ssize_t last_esoc_req_show(struct device_driver *drv, char *buf) { unsigned int i; unsigned long flags; - size_t count; + size_t count = 0; spin_lock_irqsave(&req_lock, flags); for (i = 0; i < ARRAY_SIZE(req_to_str); i++) { diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index 31cd8c49a878126a0bedd22de0a997168baf3730..4291bbc770f45f447df01c665fd757ad776421d5 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ #include #include #include +#include #include "esoc.h" #include "mdm-dbg.h" @@ -74,7 +75,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, break; case ESOC_UNEXPECTED_RESET: case ESOC_ERR_FATAL: - if (mdm_drv->mode == CRASH) + /* + * Modem can crash while we are waiting for boot_done during + * a subsystem_get(). Setting mode to CRASH will prevent a + * subsequent subsystem_get() from entering poweron ops. Avoid + * this by seting mode to CRASH only if device was up and + * running. + */ + if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN) return; mdm_drv->mode = CRASH; queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work); @@ -164,8 +172,9 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) subsys); struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops; + int timeout = INT_MAX; - if (!esoc_req_eng_enabled(esoc_clink)) { + if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) { dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n"); wait_for_completion(&mdm_drv->req_eng_wait); } @@ -190,8 +199,17 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) return ret; } } - wait_for_completion(&mdm_drv->boot_done); - if (mdm_drv->boot_fail) { + + /* + * In autoboot case, it is possible that we can forever wait for + * boot completion, when esoc fails to boot. This is because there + * is no helper application which can alert esoc driver about boot + * failure. Prevent going to wait forever in such case. + */ + if (esoc_clink->auto_boot) + timeout = 10 * HZ; + ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout); + if (mdm_drv->boot_fail || ret <= 0) { dev_err(&esoc_clink->dev, "booting failed\n"); return -EIO; } @@ -219,10 +237,12 @@ static int mdm_subsys_ramdumps(int want_dumps, static int mdm_register_ssr(struct esoc_clink *esoc_clink) { - esoc_clink->subsys.shutdown = mdm_subsys_shutdown; - esoc_clink->subsys.ramdump = mdm_subsys_ramdumps; - esoc_clink->subsys.powerup = mdm_subsys_powerup; - esoc_clink->subsys.crash_shutdown = mdm_crash_shutdown; + struct subsys_desc *subsys = &esoc_clink->subsys; + + subsys->shutdown = mdm_subsys_shutdown; + subsys->ramdump = mdm_subsys_ramdumps; + subsys->powerup = mdm_subsys_powerup; + subsys->crash_shutdown = mdm_crash_shutdown; return esoc_clink_register_ssr(esoc_clink); } @@ -289,6 +309,10 @@ static struct esoc_compat compat_table[] = { .name = "MDM9x55", .data = NULL, }, + { + .name = "SDXPOORWILLS", + .data = NULL, + }, }; static struct esoc_drv esoc_ssr_drv = { diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c index 47d54dbc79c96b748aaeb830e0110b4dd7e1e12e..9624275e93d60523b0c7ca3623abba7ff7410cf0 100644 --- a/drivers/esoc/esoc-mdm-pon.c +++ b/drivers/esoc/esoc-mdm-pon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2017-2018, 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 @@ -60,6 +60,24 @@ static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) return 0; } +/* This function can be called from atomic context. */ +static int sdxpoorwills_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) +{ + int soft_reset_direction_assert = mdm->soft_reset_inverted; + + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + soft_reset_direction_assert); + /* + * Allow PS hold assert to be detected + */ + if (!atomic) + usleep_range(80000, 180000); + else + mdelay(100); + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + !soft_reset_direction_assert); + return 0; +} static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm) { @@ -68,6 +86,9 @@ static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm) struct device *dev = mdm->dev; dev_dbg(dev, "Powering on modem for the first time\n"); + if (mdm->esoc->auto_boot) + return 0; + mdm_toggle_soft_reset(mdm, false); /* Add a delay to allow PON sequence to complete*/ mdelay(50); @@ -96,6 +117,7 @@ static int mdm4x_power_down(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0; + /* Assert the soft reset line whether mdm2ap_status went low or not */ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); @@ -132,8 +154,32 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm) return 0; } +static int sdxpoorwills_power_down(struct mdm_ctrl *mdm) +{ + struct device *dev = mdm->dev; + int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0; + + /* Assert the soft reset line whether mdm2ap_status went low or not */ + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + soft_reset_direction); + dev_info(dev, "Doing a hard reset\n"); + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + soft_reset_direction); + /* + * Currently, there is a debounce timer on the charm PMIC. It is + * necessary to hold the PMIC RESET low for 325ms + * for the reset to fully take place. Sleep here to ensure the + * reset has occurred before the function exits. + */ + mdelay(325); + return 0; +} + static void mdm4x_cold_reset(struct mdm_ctrl *mdm) { + if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET))) + return; + dev_dbg(mdm->dev, "Triggering mdm cold reset"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); @@ -152,6 +198,16 @@ static void mdm9x55_cold_reset(struct mdm_ctrl *mdm) !mdm->soft_reset_inverted); } +static void sdxpoorwills_cold_reset(struct mdm_ctrl *mdm) +{ + dev_info(mdm->dev, "Triggering mdm cold reset"); + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + !!mdm->soft_reset_inverted); + mdelay(600); + gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), + !mdm->soft_reset_inverted); +} + static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm) { int val; @@ -201,20 +257,20 @@ struct mdm_pon_ops mdm9x35_pon_ops = { .setup = mdm4x_pon_setup, }; -struct mdm_pon_ops mdm9x45_pon_ops = { +struct mdm_pon_ops mdm9x55_pon_ops = { .pon = mdm4x_do_first_power_on, - .soft_reset = mdm4x_toggle_soft_reset, - .poff_force = mdm4x_power_down, - .cold_reset = mdm4x_cold_reset, + .soft_reset = mdm9x55_toggle_soft_reset, + .poff_force = mdm9x55_power_down, + .cold_reset = mdm9x55_cold_reset, .dt_init = mdm4x_pon_dt_init, .setup = mdm4x_pon_setup, }; -struct mdm_pon_ops mdm9x55_pon_ops = { +struct mdm_pon_ops sdxpoorwills_pon_ops = { .pon = mdm4x_do_first_power_on, - .soft_reset = mdm9x55_toggle_soft_reset, - .poff_force = mdm9x55_power_down, - .cold_reset = mdm9x55_cold_reset, + .soft_reset = sdxpoorwills_toggle_soft_reset, + .poff_force = sdxpoorwills_power_down, + .cold_reset = sdxpoorwills_cold_reset, .dt_init = mdm4x_pon_dt_init, .setup = mdm4x_pon_setup, }; diff --git a/drivers/esoc/esoc-mdm.h b/drivers/esoc/esoc-mdm.h index fa3a576dfb3c42bb4b3f6d527cffd5244a132896..baf4e0b8185e43c8b7fb5a09dab1889b7392ce25 100644 --- a/drivers/esoc/esoc-mdm.h +++ b/drivers/esoc/esoc-mdm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2017-2018, 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 @@ -33,10 +33,10 @@ #define MDM9x35_PCIE "PCIe" #define MDM9x35_DUAL_LINK "HSIC+PCIe" #define MDM9x35_HSIC "HSIC" -#define MDM9x45_LABEL "MDM9x45" -#define MDM9x45_PCIE "PCIe" #define MDM9x55_LABEL "MDM9x55" #define MDM9x55_PCIE "PCIe" +#define SDXPOORWILLS_LABEL "SDXPOORWILLS" +#define SDXPOORWILLS_PCIE "PCIe" #define MDM2AP_STATUS_TIMEOUT_MS 120000L #define MDM_MODEM_TIMEOUT 3000 #define DEF_RAMDUMP_TIMEOUT 120000 @@ -151,6 +151,6 @@ static inline int mdm_pon_setup(struct mdm_ctrl *mdm) extern struct mdm_pon_ops mdm9x25_pon_ops; extern struct mdm_pon_ops mdm9x35_pon_ops; -extern struct mdm_pon_ops mdm9x45_pon_ops; extern struct mdm_pon_ops mdm9x55_pon_ops; +extern struct mdm_pon_ops sdxpoorwills_pon_ops; #endif diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h index 9fc319253a8f508b92ba0f92c4353806985c5324..df3c9dfab60d9781f1372ce96c0ed9150e483401 100644 --- a/drivers/esoc/esoc.h +++ b/drivers/esoc/esoc.h @@ -49,6 +49,7 @@ struct esoc_eng { * @link_info: additional info about the physical link. * @parent: parent device. * @dev: device for userspace interface. + * @pdev: platform device to interface with SSR driver. * @id: id of the external device. * @owner: owner of the device. * @clink_ops: control operations for the control link @@ -59,6 +60,12 @@ struct esoc_eng { * @subsys_desc: descriptor for subsystem restart * @subsys_dev: ssr device handle. * @np: device tree node for esoc_clink. + * @auto_boot: boots independently. + * @primary: primary esoc controls(reset/poweroff) all secondary + * esocs, but not otherway around. + * @statusline_not_a_powersource: True if status line to esoc is not a + * power source. + * @userspace_handle_shutdown: True if user space handles shutdown requests. */ struct esoc_clink { const char *name; @@ -66,6 +73,7 @@ struct esoc_clink { const char *link_info; struct device *parent; struct device dev; + struct platform_device *pdev; unsigned int id; struct module *owner; const struct esoc_clink_ops *clink_ops; @@ -77,17 +85,23 @@ struct esoc_clink { struct subsys_desc subsys; struct subsys_device *subsys_dev; struct device_node *np; + bool auto_boot; + bool primary; + bool statusline_not_a_powersource; + bool userspace_handle_shutdown; }; /** * struct esoc_clink_ops: Operations to control external soc * @cmd_exe: Execute control command * @get_status: Get current status, or response to previous command + * @get_err_fatal: Get status of err fatal signal * @notify_esoc: notify external soc of events */ struct esoc_clink_ops { int (*cmd_exe)(enum esoc_cmd cmd, struct esoc_clink *dev); - int (*get_status)(u32 *status, struct esoc_clink *dev); + void (*get_status)(u32 *status, struct esoc_clink *dev); + void (*get_err_fatal)(u32 *status, struct esoc_clink *dev); void (*notify)(enum esoc_notify notify, struct esoc_clink *dev); }; diff --git a/drivers/esoc/esoc_bus.c b/drivers/esoc/esoc_bus.c index cef570bb1ef15e7fd2ac8460b3ed4a7118dcdfd6..d9ab99348382274eb49362472a406d40bf5fa533 100644 --- a/drivers/esoc/esoc_bus.c +++ b/drivers/esoc/esoc_bus.c @@ -189,7 +189,7 @@ int esoc_clink_register_ssr(struct esoc_clink *esoc_clink) snprintf(subsys_name, len, "esoc%d", esoc_clink->id); esoc_clink->subsys.name = subsys_name; esoc_clink->dev.of_node = esoc_clink->np; - esoc_clink->subsys.dev = &esoc_clink->dev; + esoc_clink->subsys.dev = &esoc_clink->pdev->dev; esoc_clink->subsys_dev = subsys_register(&esoc_clink->subsys); if (IS_ERR_OR_NULL(esoc_clink->subsys_dev)) { dev_err(&esoc_clink->dev, "failed to register ssr node\n"); diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c index 0c9e42838844f8b443cf3450d7b75aa79475dda7..1d9e623c95f2e5c3e7e6538cb2a7d27232b58381 100644 --- a/drivers/esoc/esoc_dev.c +++ b/drivers/esoc/esoc_dev.c @@ -224,9 +224,11 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd, clink_ops->notify(esoc_cmd, esoc_clink); break; case ESOC_GET_STATUS: - err = clink_ops->get_status(&status, esoc_clink); - if (err) - return err; + clink_ops->get_status(&status, esoc_clink); + put_user(status, (unsigned int __user *)uarg); + break; + case ESOC_GET_ERR_FATAL: + clink_ops->get_err_fatal(&status, esoc_clink); put_user(status, (unsigned int __user *)uarg); break; case ESOC_WAIT_FOR_CRASH: @@ -336,7 +338,6 @@ int esoc_clink_del_device(struct device *dev, void *dummy) esoc_udev = esoc_udev_get_by_minor(esoc_clink->id); if (!esoc_udev) return 0; - return_esoc_udev(esoc_udev); device_destroy(esoc_class, MKDEV(esoc_major, esoc_clink->id)); return_esoc_udev(esoc_udev); return 0; diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 42f41e8082924e229d99ceac264549494449b9d3..27f67c28e700c941ff3f735a4df1e81100d380aa 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -168,7 +168,7 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) return ret; } - vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT); + vbus_attach = (pwr_stat & PS_STAT_VBUS_VALID); if (!vbus_attach) goto notify_otg; diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index ebed22f22d75701e020716c0bd2c4c1da3722fb1..296ec122996c515d03af41d4b9e11d0bedd10f85 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -28,6 +28,7 @@ #include #include #include +#include struct gpio_extcon_data { struct extcon_dev *edev; @@ -37,6 +38,7 @@ struct gpio_extcon_data { struct gpio_desc *id_gpiod; struct gpio_extcon_pdata *pdata; + unsigned int *supported_cable; }; static void gpio_extcon_work(struct work_struct *work) @@ -91,15 +93,93 @@ static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data) return 0; } +static int extcon_parse_pinctrl_data(struct device *dev, + struct gpio_extcon_pdata *pdata) +{ + struct pinctrl *pctrl; + int ret = 0; + + /* Try to obtain pinctrl handle */ + pctrl = devm_pinctrl_get(dev); + if (IS_ERR(pctrl)) { + ret = PTR_ERR(pctrl); + goto out; + } + pdata->pctrl = pctrl; + + /* Look-up and keep the state handy to be used later */ + pdata->pins_default = pinctrl_lookup_state(pdata->pctrl, + "default"); + if (IS_ERR(pdata->pins_default)) { + ret = PTR_ERR(pdata->pins_default); + dev_err(dev, "Can't get default pinctrl state, ret %d\n", ret); + } +out: + return ret; +} + +/* Parse platform data */ +static +struct gpio_extcon_pdata *extcon_populate_pdata(struct device *dev) +{ + struct gpio_extcon_pdata *pdata = NULL; + struct device_node *np = dev->of_node; + enum of_gpio_flags flags; + u32 val; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto out; + + if (of_property_read_u32(np, "extcon-id", &pdata->extcon_id)) { + dev_err(dev, "extcon-id property not found\n"); + goto out; + } + + pdata->gpio = of_get_named_gpio_flags(np, "gpio", 0, &flags); + if (gpio_is_valid(pdata->gpio)) { + if (flags & OF_GPIO_ACTIVE_LOW) + pdata->gpio_active_low = true; + } else { + dev_err(dev, "gpio property not found or invalid\n"); + goto out; + } + + if (of_property_read_u32(np, "irq-flags", &val)) { + dev_err(dev, "irq-flags property not found\n"); + goto out; + } + pdata->irq_flags = val; + + if (of_property_read_u32(np, "debounce-ms", &val)) { + dev_err(dev, "debounce-ms property not found\n"); + goto out; + } + pdata->debounce = val; + + if (extcon_parse_pinctrl_data(dev, pdata)) { + dev_err(dev, "failed to parse pinctrl data\n"); + goto out; + } + + return pdata; +out: + return NULL; +} + static int gpio_extcon_probe(struct platform_device *pdev) { struct gpio_extcon_pdata *pdata = dev_get_platdata(&pdev->dev); struct gpio_extcon_data *data; int ret; - if (!pdata) - return -EBUSY; - if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE) + if (!pdata) { + /* try populating pdata from device tree */ + pdata = extcon_populate_pdata(&pdev->dev); + if (!pdata) + return -EBUSY; + } + if (!pdata->irq_flags || pdata->extcon_id >= EXTCON_NUM) return -EINVAL; data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), @@ -108,13 +188,27 @@ static int gpio_extcon_probe(struct platform_device *pdev) return -ENOMEM; data->pdata = pdata; + ret = pinctrl_select_state(pdata->pctrl, pdata->pins_default); + if (ret < 0) + dev_err(&pdev->dev, "pinctrl state select failed, ret %d\n", + ret); + /* Initialize the gpio */ ret = gpio_extcon_init(&pdev->dev, data); if (ret < 0) return ret; + data->supported_cable = devm_kzalloc(&pdev->dev, + sizeof(*data->supported_cable) * 2, + GFP_KERNEL); + if (!data->supported_cable) + return -ENOMEM; + + data->supported_cable[0] = pdata->extcon_id; + data->supported_cable[1] = EXTCON_NONE; /* Allocate the memory of extcon devie and register extcon device */ - data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id); + data->edev = devm_extcon_dev_allocate(&pdev->dev, + data->supported_cable); if (IS_ERR(data->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; @@ -168,12 +262,18 @@ static int gpio_extcon_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume); +static const struct of_device_id extcon_gpio_of_match[] = { + { .compatible = "extcon-gpio"}, + {}, +}; + static struct platform_driver gpio_extcon_driver = { .probe = gpio_extcon_probe, .remove = gpio_extcon_remove, .driver = { .name = "extcon-gpio", .pm = &gpio_extcon_pm_ops, + .of_match_table = of_match_ptr(extcon_gpio_of_match), }, }; diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 634ba70782de9c92f256e9e5cdd535f71dd642f2..a128fd2eb187b6c42d9282b07b9289b417241b41 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -190,6 +190,11 @@ static int palmas_usb_probe(struct platform_device *pdev) struct palmas_usb *palmas_usb; int status; + if (!palmas) { + dev_err(&pdev->dev, "failed to get valid parent\n"); + return -EINVAL; + } + palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL); if (!palmas_usb) return -ENOMEM; diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 7c1e3a7b14e0c1f540a0bbe7d6b924b124561729..51355717da3d5f80ce46a3ddbe4d81fddf4525d7 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -482,6 +482,21 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) } EXPORT_SYMBOL_GPL(extcon_sync); +int extcon_blocking_sync(struct extcon_dev *edev, unsigned int id, bool val) +{ + int index; + + if (!edev) + return -EINVAL; + + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + return blocking_notifier_call_chain(&edev->bnh[index], val, edev); +} +EXPORT_SYMBOL(extcon_blocking_sync); + /** * extcon_get_state() - Get the state of a external connector. * @edev: the extcon device that has the cable. @@ -906,40 +921,53 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, unsigned long flags; int ret, idx = -EINVAL; - if (!nb) + if (!edev || !nb) return -EINVAL; - if (edev) { - idx = find_cable_index_by_id(edev, id); - if (idx < 0) - return idx; - - spin_lock_irqsave(&edev->lock, flags); - ret = raw_notifier_chain_register(&edev->nh[idx], nb); - spin_unlock_irqrestore(&edev->lock, flags); - } else { - struct extcon_dev *extd; - - mutex_lock(&extcon_dev_list_lock); - list_for_each_entry(extd, &extcon_dev_list, entry) { - idx = find_cable_index_by_id(extd, id); - if (idx >= 0) - break; - } - mutex_unlock(&extcon_dev_list_lock); + idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; - if (idx >= 0) { - edev = extd; - return extcon_register_notifier(extd, id, nb); - } else { - ret = -ENODEV; - } - } + spin_lock_irqsave(&edev->lock, flags); + ret = raw_notifier_chain_register(&edev->nh[idx], nb); + spin_unlock_irqrestore(&edev->lock, flags); return ret; } EXPORT_SYMBOL_GPL(extcon_register_notifier); +int extcon_register_blocking_notifier(struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + int idx = -EINVAL; + + if (!edev || !nb) + return -EINVAL; + + idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; + + return blocking_notifier_chain_register(&edev->bnh[idx], nb); +} +EXPORT_SYMBOL(extcon_register_blocking_notifier); + +int extcon_unregister_blocking_notifier(struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb) +{ + int idx; + + if (!edev || !nb) + return -EINVAL; + + idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; + + return blocking_notifier_chain_unregister(&edev->bnh[idx], nb); +} +EXPORT_SYMBOL(extcon_unregister_blocking_notifier); + /** * extcon_unregister_notifier() - Unregister a notifiee from the extcon device. * @edev: the extcon device that has the external connecotr. @@ -1222,6 +1250,13 @@ int extcon_dev_register(struct extcon_dev *edev) goto err_dev; } + edev->bnh = devm_kzalloc(&edev->dev, + sizeof(*edev->bnh) * edev->max_supported, GFP_KERNEL); + if (!edev->bnh) { + ret = -ENOMEM; + goto err_dev; + } + for (index = 0; index < edev->max_supported; index++) RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a4944e22f294b321fba70d572dc4996fcbb838f7..2f47c5b5f4cb8fb837f4c154a976112e06ea37d2 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -120,8 +120,7 @@ static ssize_t systab_show(struct kobject *kobj, return str - buf; } -static struct kobj_attribute efi_attr_systab = - __ATTR(systab, 0400, systab_show, NULL); +static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400); #define EFI_FIELD(var) efi.var @@ -385,7 +384,6 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) return 0; } } - pr_err_once("requested map not found.\n"); return -ENOENT; } diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 14914074f716ed41cc3fccc42c1e333810ecf890..311c9d0e8cbb126a7d4edfa25374d7e9cd9d30b2 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -106,7 +106,7 @@ static const struct sysfs_ops esre_attr_ops = { }; /* Generic ESRT Entry ("ESRE") support. */ -static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf) +static ssize_t fw_class_show(struct esre_entry *entry, char *buf) { char *str = buf; @@ -117,18 +117,16 @@ static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf) return str - buf; } -static struct esre_attribute esre_fw_class = __ATTR(fw_class, 0400, - esre_fw_class_show, NULL); +static struct esre_attribute esre_fw_class = __ATTR_RO_MODE(fw_class, 0400); #define esre_attr_decl(name, size, fmt) \ -static ssize_t esre_##name##_show(struct esre_entry *entry, char *buf) \ +static ssize_t name##_show(struct esre_entry *entry, char *buf) \ { \ return sprintf(buf, fmt "\n", \ le##size##_to_cpu(entry->esre.esre1->name)); \ } \ \ -static struct esre_attribute esre_##name = __ATTR(name, 0400, \ - esre_##name##_show, NULL) +static struct esre_attribute esre_##name = __ATTR_RO_MODE(name, 0400) esre_attr_decl(fw_type, 32, "%u"); esre_attr_decl(fw_version, 32, "%u"); @@ -193,14 +191,13 @@ static int esre_create_sysfs_entry(void *esre, int entry_num) /* support for displaying ESRT fields at the top level */ #define esrt_attr_decl(name, size, fmt) \ -static ssize_t esrt_##name##_show(struct kobject *kobj, \ +static ssize_t name##_show(struct kobject *kobj, \ struct kobj_attribute *attr, char *buf)\ { \ return sprintf(buf, fmt "\n", le##size##_to_cpu(esrt->name)); \ } \ \ -static struct kobj_attribute esrt_##name = __ATTR(name, 0400, \ - esrt_##name##_show, NULL) +static struct kobj_attribute esrt_##name = __ATTR_RO_MODE(name, 0400) esrt_attr_decl(fw_resource_count, 32, "%u"); esrt_attr_decl(fw_resource_count_max, 32, "%u"); @@ -254,7 +251,7 @@ void __init efi_esrt_init(void) rc = efi_mem_desc_lookup(efi.esrt, &md); if (rc < 0) { - pr_err("ESRT header is not in the memory map.\n"); + pr_warn("ESRT header is not in the memory map.\n"); return; } @@ -431,7 +428,7 @@ static int __init esrt_sysfs_init(void) err_remove_esrt: kobject_put(esrt_kobj); err: - kfree(esrt); + memunmap(esrt); esrt = NULL; return error; } diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5e23e2d305e71db52a7f9e27a63ce760f4c752fd..f9a1e982a3a641eb119d7a03fbc6e99ec63c9262 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -17,6 +17,7 @@ cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ + -D__NO_FORTIFY \ $(call cc-option,-ffreestanding) \ $(call cc-option,-fno-stack-protector) diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 8e64b77aeac95e43c0e0571694f42bbe6c8ba73f..f377609ff141bca733bf498babc25f9d215aefad 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -63,11 +63,11 @@ static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, return map_attr->show(entry, buf); } -static struct map_attribute map_type_attr = __ATTR_RO(type); -static struct map_attribute map_phys_addr_attr = __ATTR_RO(phys_addr); -static struct map_attribute map_virt_addr_attr = __ATTR_RO(virt_addr); -static struct map_attribute map_num_pages_attr = __ATTR_RO(num_pages); -static struct map_attribute map_attribute_attr = __ATTR_RO(attribute); +static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400); +static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400); +static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400); +static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400); +static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400); /* * These are default attributes that are added for every memmap entry. diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 8fe8805721ac747d0576c6c56899cfb31ae02b5d..2b6b1122e7460819f6d344c329ff0e6fcf0a32fd 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -493,6 +493,8 @@ static void __init psci_init_migrate(void) static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_ops.get_version = psci_get_version; + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_FN_NATIVE(0_2, CPU_SUSPEND); psci_ops.cpu_suspend = psci_cpu_suspend; diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index 1b51d088ebb8bd31db650ebf0241447183e8f4ec..9c1c81b66ad6a75bbff2e742a75916c89066ab11 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -477,10 +477,10 @@ static int _disp_tz_reset_stats(void) static int _disp_tz_interrupt_stats(void) { - int i, j, int_info_size; + int i, j; int len = 0; int *num_int; - unsigned char *ptr; + void *ptr; struct tzdbg_int_t *tzdbg_ptr; struct tzdbg_int_t_tz40 *tzdbg_ptr_tz40; @@ -488,14 +488,12 @@ static int _disp_tz_interrupt_stats(void) (tzdbg.diag_buf->int_info_off - sizeof(uint32_t))); ptr = ((unsigned char *)tzdbg.diag_buf + tzdbg.diag_buf->int_info_off); - int_info_size = ((tzdbg.diag_buf->ring_off - - tzdbg.diag_buf->int_info_off)/(*num_int)); pr_info("qsee_version = 0x%x\n", tzdbg.tz_version); if (tzdbg.tz_version < QSEE_VERSION_TZ_4_X) { + tzdbg_ptr = ptr; for (i = 0; i < (*num_int); i++) { - tzdbg_ptr = (struct tzdbg_int_t *)ptr; len += snprintf(tzdbg.disp_buf + len, (debug_rw_buf_size - 1) - len, " Interrupt Number : 0x%x\n" @@ -519,11 +517,11 @@ static int _disp_tz_interrupt_stats(void) __func__); break; } - ptr += int_info_size; + tzdbg_ptr++; } } else { + tzdbg_ptr_tz40 = ptr; for (i = 0; i < (*num_int); i++) { - tzdbg_ptr_tz40 = (struct tzdbg_int_t_tz40 *)ptr; len += snprintf(tzdbg.disp_buf + len, (debug_rw_buf_size - 1) - len, " Interrupt Number : 0x%x\n" @@ -547,7 +545,7 @@ static int _disp_tz_interrupt_stats(void) __func__); break; } - ptr += int_info_size; + tzdbg_ptr_tz40++; } } @@ -962,7 +960,7 @@ static int tzdbgfs_init(struct platform_device *pdev) for (i = 0; i < TZDBG_STATS_MAX; i++) { tzdbg.debug_tz[i] = i; - dent = debugfs_create_file(tzdbg.stat[i].name, + dent = debugfs_create_file_unsafe(tzdbg.stat[i].name, 0444, dent_dir, &tzdbg.debug_tz[i], &tzdbg_fops); if (dent == NULL) { diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9338ff7a69470ba9c1456b3e7d31870e8dbf6bd1..642fa03f9292ac1d06b17e348fd39e80ecb65f09 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1206,6 +1206,8 @@ config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" depends on OF_GPIO select GPIOLIB_IRQCHIP + select REGMAP_I2C if I2C + select REGMAP if SPI_MASTER help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 I/O expanders. diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 5bddbd507ca9f105aa18cfe5f43b673b676d551d..3fe6a21e05a5718d8769bf2dd505cb5968f41207 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -90,21 +90,18 @@ static int altera_gpio_irq_set_type(struct irq_data *d, altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - if (type == IRQ_TYPE_NONE) + if (type == IRQ_TYPE_NONE) { + irq_set_handler_locked(d, handle_bad_irq); return 0; - if (type == IRQ_TYPE_LEVEL_HIGH && - altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH) - return 0; - if (type == IRQ_TYPE_EDGE_RISING && - altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_RISING) - return 0; - if (type == IRQ_TYPE_EDGE_FALLING && - altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_FALLING) - return 0; - if (type == IRQ_TYPE_EDGE_BOTH && - altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_BOTH) + } + if (type == altera_gc->interrupt_trigger) { + if (type == IRQ_TYPE_LEVEL_HIGH) + irq_set_handler_locked(d, handle_level_irq); + else + irq_set_handler_locked(d, handle_simple_irq); return 0; - + } + irq_set_handler_locked(d, handle_bad_irq); return -EINVAL; } @@ -230,7 +227,6 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } - static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc) { struct altera_gpio_chip *altera_gc; @@ -310,7 +306,7 @@ static int altera_gpio_probe(struct platform_device *pdev) altera_gc->interrupt_trigger = reg; ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_err(&pdev->dev, "could not add irqchip\n"); diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 1ef85b0c2b1f2cc414f2393cd035a94a03ed7565..d27e9361e236c0e4246debe5ad22c3008c416a00 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -126,7 +126,7 @@ static int mockup_gpio_probe(struct platform_device *pdev) int i; int base; int ngpio; - char chip_name[sizeof(GPIO_NAME) + 3]; + char *chip_name; if (gpio_mockup_params_nr < 2) return -EINVAL; @@ -146,8 +146,12 @@ static int mockup_gpio_probe(struct platform_device *pdev) ngpio = gpio_mockup_ranges[i * 2 + 1] - base; if (ngpio >= 0) { - sprintf(chip_name, "%s-%c", GPIO_NAME, - pins_name_start + i); + chip_name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%c", GPIO_NAME, + pins_name_start + i); + if (!chip_name) + return -ENOMEM; + ret = mockup_gpio_add(dev, &cntr[i], chip_name, base, ngpio); } else { diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index b98ede78c9d854deffa8c79d205c3ddf253ac42e..6f9c9ac6ee7008027c238b2ef2768f6560f8d1d2 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -208,9 +208,11 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) * OMAP's debounce time is in 31us steps * = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 * so we need to convert and round up to the closest unit. + * + * Return: 0 on success, negative error otherwise. */ -static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, - unsigned debounce) +static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, + unsigned debounce) { void __iomem *reg; u32 val; @@ -218,11 +220,12 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, bool enable = !!debounce; if (!bank->dbck_flag) - return; + return -ENOTSUPP; if (enable) { debounce = DIV_ROUND_UP(debounce, 31) - 1; - debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; + if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) + return -EINVAL; } l = BIT(offset); @@ -255,6 +258,8 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, bank->context.debounce = debounce; bank->context.debounce_en = val; } + + return 0; } /** @@ -964,14 +969,20 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, { struct gpio_bank *bank; unsigned long flags; + int ret; bank = gpiochip_get_data(chip); raw_spin_lock_irqsave(&bank->lock, flags); - omap2_set_gpio_debounce(bank, offset, debounce); + ret = omap2_set_gpio_debounce(bank, offset, debounce); raw_spin_unlock_irqrestore(&bank->lock, flags); - return 0; + if (ret) + dev_info(chip->parent, + "Could not set line %u debounce to %u microseconds (%d)", + offset, debounce, ret); + + return ret; } static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 92159313361b1a2527410062c75a26a3c9a5addd..063d176baa24a887ee4c561c32449e1c425c0b82 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -703,23 +703,23 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) { struct lineevent_state *le = p; struct gpioevent_data ge; - int ret; + int ret, level; ge.timestamp = ktime_get_real_ns(); + level = gpiod_get_value_cansleep(le->desc); - if (le->eflags & GPIOEVENT_REQUEST_BOTH_EDGES) { - int level = gpiod_get_value_cansleep(le->desc); - + if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE + && le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) { if (level) /* Emit low-to-high event */ ge.id = GPIOEVENT_EVENT_RISING_EDGE; else /* Emit high-to-low event */ ge.id = GPIOEVENT_EVENT_FALLING_EDGE; - } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) { + } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) { /* Emit low-to-high event */ ge.id = GPIOEVENT_EVENT_RISING_EDGE; - } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) { + } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) { /* Emit high-to-low event */ ge.id = GPIOEVENT_EVENT_FALLING_EDGE; } else { diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 6898aa0458875dde021a01282965bbe5ef0942b1..2f936a76e44092875e8d4e1bd79145aad2f93161 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -13,6 +13,7 @@ menuconfig DRM select I2C select I2C_ALGOBIT select DMA_SHARED_BUFFER + select SYNC_FILE help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select diff --git a/drivers/gpu/drm/amd/acp/Makefile b/drivers/gpu/drm/amd/acp/Makefile index 8363cb57915b0b726c704b8be37805ecef2a18ee..8a08e81ee90d579774ca96bc70853093ba623f09 100644 --- a/drivers/gpu/drm/amd/acp/Makefile +++ b/drivers/gpu/drm/amd/acp/Makefile @@ -3,6 +3,4 @@ # of AMDSOC/AMDGPU drm driver. # It provides the HW control for ACP related functionalities. -subdir-ccflags-y += -I$(AMDACPPATH)/ -I$(AMDACPPATH)/include - AMD_ACP_FILES := $(AMDACPPATH)/acp_hw.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 8e6bf548d68907f871952f0109186a03373cdd5f..26afdffab5a06ccc4fee8322ef074366b6edb57e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -693,6 +693,10 @@ int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev) DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n", adev->clock.default_dispclk / 100); adev->clock.default_dispclk = 60000; + } else if (adev->clock.default_dispclk <= 60000) { + DRM_INFO("Changing default dispclk from %dMhz to 625Mhz\n", + adev->clock.default_dispclk / 100); + adev->clock.default_dispclk = 62500; } adev->clock.dp_extclk = le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq); @@ -1784,34 +1788,32 @@ void amdgpu_atombios_scratch_regs_restore(struct amdgpu_device *adev) WREG32(mmBIOS_SCRATCH_0 + i, adev->bios_scratch[i]); } -/* Atom needs data in little endian format - * so swap as appropriate when copying data to - * or from atom. Note that atom operates on - * dw units. +/* Atom needs data in little endian format so swap as appropriate when copying + * data to or from atom. Note that atom operates on dw units. + * + * Use to_le=true when sending data to atom and provide at least + * ALIGN(num_bytes,4) bytes in the dst buffer. + * + * Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4) + * byes in the src buffer. */ void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le) { #ifdef __BIG_ENDIAN - u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */ - u32 *dst32, *src32; + u32 src_tmp[5], dst_tmp[5]; int i; + u8 align_num_bytes = ALIGN(num_bytes, 4); - memcpy(src_tmp, src, num_bytes); - src32 = (u32 *)src_tmp; - dst32 = (u32 *)dst_tmp; if (to_le) { - for (i = 0; i < ((num_bytes + 3) / 4); i++) - dst32[i] = cpu_to_le32(src32[i]); - memcpy(dst, dst_tmp, num_bytes); + memcpy(src_tmp, src, num_bytes); + for (i = 0; i < align_num_bytes / 4; i++) + dst_tmp[i] = cpu_to_le32(src_tmp[i]); + memcpy(dst, dst_tmp, align_num_bytes); } else { - u8 dws = num_bytes & ~3; - for (i = 0; i < ((num_bytes + 3) / 4); i++) - dst32[i] = le32_to_cpu(src32[i]); - memcpy(dst, dst_tmp, dws); - if (num_bytes % 4) { - for (i = 0; i < (num_bytes % 4); i++) - dst[dws+i] = dst_tmp[dws+i]; - } + memcpy(src_tmp, src, align_num_bytes); + for (i = 0; i < align_num_bytes / 4; i++) + dst_tmp[i] = le32_to_cpu(src_tmp[i]); + memcpy(dst, dst_tmp, num_bytes); } #else memcpy(dst, src, num_bytes); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 82dc8d20e28acfdd2c2c4c2e9dca8ea0cca88d53..f26d1fd53bef1e6c12e26a5b14bb19f894f2418e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -83,6 +83,13 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type, } break; } + + if (!(*out_ring && (*out_ring)->adev)) { + DRM_ERROR("Ring %d is not initialized on IP %d\n", + ring, ip_type); + return -EINVAL; + } + return 0; } @@ -233,6 +240,8 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) for (; i >= 0; i--) drm_free_large(p->chunks[i].kdata); kfree(p->chunks); + p->chunks = NULL; + p->nchunks = 0; put_ctx: amdgpu_ctx_put(p->ctx); free_chunk: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e41d4baebf86ea39b7e604071d72b0ca29ded612..ce9797b6f9c75091e099062a3ef18c69aacb6a20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2020,8 +2020,11 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) } r = amdgpu_late_init(adev); - if (r) + if (r) { + if (fbcon) + console_unlock(); return r; + } /* pin cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dcaf691f56b5577352d2238bdfd27e2f1aca2386..05ff98b43c50f3677dcd5ef971c9fd5bc0548203 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -491,6 +491,9 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ case TTM_PL_TT: break; case TTM_PL_VRAM: + if (mem->start == AMDGPU_BO_INVALID_OFFSET) + return -EINVAL; + mem->bus.offset = mem->start << PAGE_SHIFT; /* check if it's visible */ if ((mem->bus.offset + mem->bus.size) > adev->mc.visible_vram_size) @@ -1419,6 +1422,9 @@ static ssize_t amdgpu_ttm_vram_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; + if (*pos >= adev->mc.mc_vram_size) + return -ENXIO; + while (size) { unsigned long flags; uint32_t value; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 7fe8fd884f0600a83d98c6230f8a7292395b1f1e..3bb2b9b5ef9c5e8d1038dd572699c77b7bc974c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -315,6 +315,10 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work) amdgpu_dpm_enable_vce(adev, false); } else { amdgpu_asic_set_vce_clocks(adev, 0, 0); + amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, + AMD_PG_STATE_GATE); + amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, + AMD_CG_STATE_GATE); } } else { schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT); @@ -340,6 +344,11 @@ void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring) amdgpu_dpm_enable_vce(adev, true); } else { amdgpu_asic_set_vce_clocks(adev, 53300, 40000); + amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, + AMD_CG_STATE_UNGATE); + amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, + AMD_PG_STATE_UNGATE); + } } mutex_unlock(&adev->vce.idle_mutex); @@ -639,7 +648,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) uint32_t allocated = 0; uint32_t tmp, handle = 0; uint32_t *size = &tmp; - int i, r, idx = 0; + int i, r = 0, idx = 0; r = amdgpu_cs_sysvm_access_required(p); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 968c4260d7a7e0ccfa94f4a3f069acc9f73e1830..47503759906b8e1f6ab0b2d20dcbcc3fcf333e5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -744,7 +744,7 @@ static int amdgpu_vm_update_pd_or_shadow(struct amdgpu_device *adev, int amdgpu_vm_update_page_directory(struct amdgpu_device *adev, struct amdgpu_vm *vm) { - int r; + int r = 0; r = amdgpu_vm_update_pd_or_shadow(adev, vm, true); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c index f7d236f95e74262dd6970050de140c1b01f0b017..57fbde14e978959e043b523e8654301feeb3b9ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c @@ -164,7 +164,7 @@ void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) struct drm_device *dev = crtc->dev; struct amdgpu_device *adev = dev->dev_private; int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); - ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; + ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; memset(&args, 0, sizeof(args)); @@ -177,7 +177,7 @@ void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state) void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev) { int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating); - ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args; + ENABLE_DISP_POWER_GATING_PS_ALLOCATION args; memset(&args, 0, sizeof(args)); diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index 5be788b269e22232a61b75e83bdd822bf142c583..1679727c22ef3c661bd452f2c775b3d19001b7fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -900,6 +900,12 @@ static bool ci_dpm_vblank_too_short(struct amdgpu_device *adev) u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300; + /* disable mclk switching if the refresh is >120Hz, even if the + * blanking period would allow it + */ + if (amdgpu_dpm_get_vrefresh(adev) > 120) + return true; + if (vblank_time < switch_limit) return true; else diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 882404cefbc23881973ed766f320590afe117042..db9b79a8b16011055db0e52c4c7dbf2526f5f515 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1173,23 +1173,10 @@ static u32 dce_v10_0_latency_watermark(struct dce10_wm_params *wm) a.full = dfixed_const(available_bandwidth); b.full = dfixed_const(wm->num_heads); a.full = dfixed_div(a, b); + tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512); + tmp = min(dfixed_trunc(a), tmp); - b.full = dfixed_const(mc_latency + 512); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(b, c); - - c.full = dfixed_const(dmif_size); - b.full = dfixed_div(c, b); - - tmp = min(dfixed_trunc(a), dfixed_trunc(b)); - - b.full = dfixed_const(1000); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(c, b); - c.full = dfixed_const(wm->bytes_per_pixel); - b.full = dfixed_mul(b, c); - - lb_fill_bw = min(tmp, dfixed_trunc(b)); + lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000); a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel); b.full = dfixed_const(1000); @@ -1297,14 +1284,17 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, { struct drm_display_mode *mode = &amdgpu_crtc->base.mode; struct dce10_wm_params wm_low, wm_high; - u32 pixel_period; + u32 active_time; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; u32 tmp, wm_mask, lb_vblank_lead_lines = 0; if (amdgpu_crtc->base.enabled && num_heads && mode) { - pixel_period = 1000000 / (u32)mode->clock; - line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535); + active_time = (u32) div_u64((u64)mode->crtc_hdisplay * 1000000, + (u32)mode->clock); + line_time = (u32) div_u64((u64)mode->crtc_htotal * 1000000, + (u32)mode->clock); + line_time = min(line_time, (u32)65535); /* watermark for high clocks */ if (adev->pm.dpm_enabled) { @@ -1319,7 +1309,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, wm_high.disp_clk = mode->clock; wm_high.src_width = mode->crtc_hdisplay; - wm_high.active_time = mode->crtc_hdisplay * pixel_period; + wm_high.active_time = active_time; wm_high.blank_time = line_time - wm_high.active_time; wm_high.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -1358,7 +1348,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, wm_low.disp_clk = mode->clock; wm_low.src_width = mode->crtc_hdisplay; - wm_low.active_time = mode->crtc_hdisplay * pixel_period; + wm_low.active_time = active_time; wm_low.blank_time = line_time - wm_low.active_time; wm_low.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 64a1df62cc65a2920c817e78b77495d7641cef4b..36d5128a2aadd93d05a937409f7efe0262d98887 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1140,23 +1140,10 @@ static u32 dce_v11_0_latency_watermark(struct dce10_wm_params *wm) a.full = dfixed_const(available_bandwidth); b.full = dfixed_const(wm->num_heads); a.full = dfixed_div(a, b); + tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512); + tmp = min(dfixed_trunc(a), tmp); - b.full = dfixed_const(mc_latency + 512); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(b, c); - - c.full = dfixed_const(dmif_size); - b.full = dfixed_div(c, b); - - tmp = min(dfixed_trunc(a), dfixed_trunc(b)); - - b.full = dfixed_const(1000); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(c, b); - c.full = dfixed_const(wm->bytes_per_pixel); - b.full = dfixed_mul(b, c); - - lb_fill_bw = min(tmp, dfixed_trunc(b)); + lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000); a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel); b.full = dfixed_const(1000); @@ -1264,14 +1251,17 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, { struct drm_display_mode *mode = &amdgpu_crtc->base.mode; struct dce10_wm_params wm_low, wm_high; - u32 pixel_period; + u32 active_time; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; u32 tmp, wm_mask, lb_vblank_lead_lines = 0; if (amdgpu_crtc->base.enabled && num_heads && mode) { - pixel_period = 1000000 / (u32)mode->clock; - line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535); + active_time = (u32) div_u64((u64)mode->crtc_hdisplay * 1000000, + (u32)mode->clock); + line_time = (u32) div_u64((u64)mode->crtc_htotal * 1000000, + (u32)mode->clock); + line_time = min(line_time, (u32)65535); /* watermark for high clocks */ if (adev->pm.dpm_enabled) { @@ -1286,7 +1276,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, wm_high.disp_clk = mode->clock; wm_high.src_width = mode->crtc_hdisplay; - wm_high.active_time = mode->crtc_hdisplay * pixel_period; + wm_high.active_time = active_time; wm_high.blank_time = line_time - wm_high.active_time; wm_high.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -1325,7 +1315,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, wm_low.disp_clk = mode->clock; wm_low.src_width = mode->crtc_hdisplay; - wm_low.active_time = mode->crtc_hdisplay * pixel_period; + wm_low.active_time = active_time; wm_low.blank_time = line_time - wm_low.active_time; wm_low.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index fde6ee1f6f2b3bbab424ed08ee699a1a3dfcf021..75689a2c2de6b30a575b5e92973052d05bc2d1b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -932,23 +932,10 @@ static u32 dce_v6_0_latency_watermark(struct dce6_wm_params *wm) a.full = dfixed_const(available_bandwidth); b.full = dfixed_const(wm->num_heads); a.full = dfixed_div(a, b); + tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512); + tmp = min(dfixed_trunc(a), tmp); - b.full = dfixed_const(mc_latency + 512); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(b, c); - - c.full = dfixed_const(dmif_size); - b.full = dfixed_div(c, b); - - tmp = min(dfixed_trunc(a), dfixed_trunc(b)); - - b.full = dfixed_const(1000); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(c, b); - c.full = dfixed_const(wm->bytes_per_pixel); - b.full = dfixed_mul(b, c); - - lb_fill_bw = min(tmp, dfixed_trunc(b)); + lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000); a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel); b.full = dfixed_const(1000); @@ -1057,18 +1044,21 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, struct drm_display_mode *mode = &amdgpu_crtc->base.mode; struct dce6_wm_params wm_low, wm_high; u32 dram_channels; - u32 pixel_period; + u32 active_time; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; u32 priority_a_mark = 0, priority_b_mark = 0; u32 priority_a_cnt = PRIORITY_OFF; u32 priority_b_cnt = PRIORITY_OFF; - u32 tmp, arb_control3; + u32 tmp, arb_control3, lb_vblank_lead_lines = 0; fixed20_12 a, b, c; if (amdgpu_crtc->base.enabled && num_heads && mode) { - pixel_period = 1000000 / (u32)mode->clock; - line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535); + active_time = (u32) div_u64((u64)mode->crtc_hdisplay * 1000000, + (u32)mode->clock); + line_time = (u32) div_u64((u64)mode->crtc_htotal * 1000000, + (u32)mode->clock); + line_time = min(line_time, (u32)65535); priority_a_cnt = 0; priority_b_cnt = 0; @@ -1087,7 +1077,7 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, wm_high.disp_clk = mode->clock; wm_high.src_width = mode->crtc_hdisplay; - wm_high.active_time = mode->crtc_hdisplay * pixel_period; + wm_high.active_time = active_time; wm_high.blank_time = line_time - wm_high.active_time; wm_high.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -1114,7 +1104,7 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, wm_low.disp_clk = mode->clock; wm_low.src_width = mode->crtc_hdisplay; - wm_low.active_time = mode->crtc_hdisplay * pixel_period; + wm_low.active_time = active_time; wm_low.blank_time = line_time - wm_low.active_time; wm_low.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -1175,6 +1165,8 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, c.full = dfixed_div(c, a); priority_b_mark = dfixed_trunc(c); priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; + + lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ @@ -1204,6 +1196,9 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev, /* save values for DPM */ amdgpu_crtc->line_time = line_time; amdgpu_crtc->wm_high = latency_watermark_a; + + /* Save number of lines the linebuffer leads before the scanout */ + amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines; } /* watermark setup */ diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 7d9ffde0a628db4051fed12bc19f09a9e6fcb808..ba2321ea800e488e011a8c23227f4887c62d98f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1094,23 +1094,10 @@ static u32 dce_v8_0_latency_watermark(struct dce8_wm_params *wm) a.full = dfixed_const(available_bandwidth); b.full = dfixed_const(wm->num_heads); a.full = dfixed_div(a, b); + tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512); + tmp = min(dfixed_trunc(a), tmp); - b.full = dfixed_const(mc_latency + 512); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(b, c); - - c.full = dfixed_const(dmif_size); - b.full = dfixed_div(c, b); - - tmp = min(dfixed_trunc(a), dfixed_trunc(b)); - - b.full = dfixed_const(1000); - c.full = dfixed_const(wm->disp_clk); - b.full = dfixed_div(c, b); - c.full = dfixed_const(wm->bytes_per_pixel); - b.full = dfixed_mul(b, c); - - lb_fill_bw = min(tmp, dfixed_trunc(b)); + lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000); a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel); b.full = dfixed_const(1000); @@ -1218,14 +1205,17 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, { struct drm_display_mode *mode = &amdgpu_crtc->base.mode; struct dce8_wm_params wm_low, wm_high; - u32 pixel_period; + u32 active_time; u32 line_time = 0; u32 latency_watermark_a = 0, latency_watermark_b = 0; u32 tmp, wm_mask, lb_vblank_lead_lines = 0; if (amdgpu_crtc->base.enabled && num_heads && mode) { - pixel_period = 1000000 / (u32)mode->clock; - line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535); + active_time = (u32) div_u64((u64)mode->crtc_hdisplay * 1000000, + (u32)mode->clock); + line_time = (u32) div_u64((u64)mode->crtc_htotal * 1000000, + (u32)mode->clock); + line_time = min(line_time, (u32)65535); /* watermark for high clocks */ if (adev->pm.dpm_enabled) { @@ -1240,7 +1230,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, wm_high.disp_clk = mode->clock; wm_high.src_width = mode->crtc_hdisplay; - wm_high.active_time = mode->crtc_hdisplay * pixel_period; + wm_high.active_time = active_time; wm_high.blank_time = line_time - wm_high.active_time; wm_high.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -1279,7 +1269,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev, wm_low.disp_clk = mode->clock; wm_low.src_width = mode->crtc_hdisplay; - wm_low.active_time = mode->crtc_hdisplay * pixel_period; + wm_low.active_time = active_time; wm_low.blank_time = line_time - wm_low.active_time; wm_low.interlaced = false; if (mode->flags & DRM_MODE_FLAG_INTERLACE) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index c2bd9f045532b3f24b6f34004233ec9ed4e70614..6d75fd0e3105f297c9a3bd435a7f28c528c67d74 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -565,11 +565,8 @@ static const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = static void dce_virtual_encoder_destroy(struct drm_encoder *encoder) { - struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); - - kfree(amdgpu_encoder->enc_priv); drm_encoder_cleanup(encoder); - kfree(amdgpu_encoder); + kfree(encoder); } static const struct drm_encoder_funcs dce_virtual_encoder_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index dc9511c5ecb8ea393cc3097a9507b2e2e959f962..327bdf13e8bc864231f697a91c1cf891eb1f44c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1301,6 +1301,7 @@ static void si_init_golden_registers(struct amdgpu_device *adev) amdgpu_program_register_sequence(adev, pitcairn_mgcg_cgcg_init, (const u32)ARRAY_SIZE(pitcairn_mgcg_cgcg_init)); + break; case CHIP_VERDE: amdgpu_program_register_sequence(adev, verde_golden_registers, @@ -1325,6 +1326,7 @@ static void si_init_golden_registers(struct amdgpu_device *adev) amdgpu_program_register_sequence(adev, oland_mgcg_cgcg_init, (const u32)ARRAY_SIZE(oland_mgcg_cgcg_init)); + break; case CHIP_HAINAN: amdgpu_program_register_sequence(adev, hainan_golden_registers, diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 6f3c89178b6ab9c089939d81786a5a06c58fa15d..4cb347e88cf07639e779fa658b80b91a90dc7387 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -64,6 +64,7 @@ MODULE_FIRMWARE("radeon/oland_smc.bin"); MODULE_FIRMWARE("radeon/oland_k_smc.bin"); MODULE_FIRMWARE("radeon/hainan_smc.bin"); MODULE_FIRMWARE("radeon/hainan_k_smc.bin"); +MODULE_FIRMWARE("radeon/banks_k_2_smc.bin"); union power_info { struct _ATOM_POWERPLAY_INFO info; @@ -7721,10 +7722,11 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev) ((adev->pdev->device == 0x6660) || (adev->pdev->device == 0x6663) || (adev->pdev->device == 0x6665) || - (adev->pdev->device == 0x6667))) || - ((adev->pdev->revision == 0xc3) && - (adev->pdev->device == 0x6665))) + (adev->pdev->device == 0x6667)))) chip_name = "hainan_k"; + else if ((adev->pdev->revision == 0xc3) && + (adev->pdev->device == 0x6665)) + chip_name = "banks_k_2"; else chip_name = "hainan"; break; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index ab3df6d756562ee33b97d2c48aaf6f7bfadc6f2a..3f445df9124d63e7d0d2397cff77a5580e3f3612 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -89,6 +89,10 @@ static int uvd_v6_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + if (!(adev->flags & AMD_IS_APU) && + (RREG32_SMC(ixCC_HARVEST_FUSES) & CC_HARVEST_FUSES__UVD_DISABLE_MASK)) + return -ENOENT; + uvd_v6_0_set_ring_funcs(adev); uvd_v6_0_set_irq_funcs(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 6feed726e299378e39d08cf74f5d7e71b20a2cc4..7522f796f19b64edc729a04971600254a79020de 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -43,9 +43,13 @@ #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 +#define GRBM_GFX_INDEX__VCE_ALL_PIPE 0x07 + #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 +#define mmGRBM_GFX_INDEX_DEFAULT 0xE0000000 + #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 #define VCE_V3_0_FW_SIZE (384 * 1024) @@ -54,6 +58,9 @@ #define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8)) +#define GET_VCE_INSTANCE(i) ((i) << GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT \ + | GRBM_GFX_INDEX__VCE_ALL_PIPE) + static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); @@ -175,7 +182,7 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, WREG32(mmVCE_UENC_CLOCK_GATING_2, data); data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); - data &= ~0xffc00000; + data &= ~0x3ff; WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); @@ -249,7 +256,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev) if (adev->vce.harvest_config & (1 << idx)) continue; - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx)); vce_v3_0_mc_resume(adev, idx); WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); @@ -273,7 +280,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev) } } - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); + WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); mutex_unlock(&adev->grbm_idx_mutex); return 0; @@ -288,7 +295,7 @@ static int vce_v3_0_stop(struct amdgpu_device *adev) if (adev->vce.harvest_config & (1 << idx)) continue; - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx)); if (adev->asic_type >= CHIP_STONEY) WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); @@ -306,7 +313,7 @@ static int vce_v3_0_stop(struct amdgpu_device *adev) vce_v3_0_set_vce_sw_clock_gating(adev, false); } - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); + WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); mutex_unlock(&adev->grbm_idx_mutex); return 0; @@ -586,17 +593,17 @@ static bool vce_v3_0_check_soft_reset(void *handle) * VCE team suggest use bit 3--bit 6 for busy status check */ mutex_lock(&adev->grbm_idx_mutex); - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); } - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); } - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); mutex_unlock(&adev->grbm_idx_mutex); if (srbm_soft_reset) { @@ -734,7 +741,7 @@ static int vce_v3_0_set_clockgating_state(void *handle, if (adev->vce.harvest_config & (1 << i)) continue; - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(i)); if (enable) { /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ @@ -753,7 +760,7 @@ static int vce_v3_0_set_clockgating_state(void *handle, vce_v3_0_set_vce_sw_clock_gating(adev, enable); } - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); + WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); mutex_unlock(&adev->grbm_idx_mutex); return 0; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index a6a4b2b1c0d901bb6d59497f5595355490d3f74e..6a3470f849989a7bf77ccaff862ad792daa25408 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -739,8 +739,10 @@ int kfd_wait_on_events(struct kfd_process *p, struct kfd_event_data event_data; if (copy_from_user(&event_data, &events[i], - sizeof(struct kfd_event_data))) + sizeof(struct kfd_event_data))) { + ret = -EFAULT; goto fail; + } ret = init_event_waiter(p, &event_waiters[i], event_data.event_id, i); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c index 2028980f1ed4f5be9694ce8fed4abb32e94fe014..5b261c1dcc9fb4d508c21de503564d2968d18795 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c @@ -200,7 +200,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) cgs_set_clockgating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_CG_STATE_UNGATE); + AMD_CG_STATE_GATE); cgs_set_powergating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, @@ -218,7 +218,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) cgs_set_clockgating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_PG_STATE_GATE); + AMD_PG_STATE_UNGATE); cz_dpm_update_vce_dpm(hwmgr); cz_enable_disable_vce_dpm(hwmgr, true); return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 960424913496d671d70fa220600fab6874dbd67d..189ec94c6ff970a6c793e1ebc239283c6db685dc 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -1402,14 +1402,22 @@ int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr) cz_hwmgr->vce_dpm.hard_min_clk, PPSMC_MSG_SetEclkHardMin)); } else { - /*EPR# 419220 -HW limitation to to */ - cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk; - smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, - PPSMC_MSG_SetEclkHardMin, - cz_get_eclk_level(hwmgr, - cz_hwmgr->vce_dpm.hard_min_clk, - PPSMC_MSG_SetEclkHardMin)); - + /*Program HardMin based on the vce_arbiter.ecclk */ + if (hwmgr->vce_arbiter.ecclk == 0) { + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetEclkHardMin, 0); + /* disable ECLK DPM 0. Otherwise VCE could hang if + * switching SCLK from DPM 0 to 6/7 */ + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetEclkSoftMin, 1); + } else { + cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk; + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetEclkHardMin, + cz_get_eclk_level(hwmgr, + cz_hwmgr->vce_dpm.hard_min_clk, + PPSMC_MSG_SetEclkHardMin)); + } } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index 4477c55a58e32f903d33005cf9f2cc13a07215ba..a8b59b3decd8b9f66df71c5674919b1169e15f09 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -850,9 +850,9 @@ static int init_over_drive_limits( const ATOM_Tonga_POWERPLAYTABLE *powerplay_table) { hwmgr->platform_descriptor.overdriveLimit.engineClock = - le16_to_cpu(powerplay_table->ulMaxODEngineClock); + le32_to_cpu(powerplay_table->ulMaxODEngineClock); hwmgr->platform_descriptor.overdriveLimit.memoryClock = - le16_to_cpu(powerplay_table->ulMaxODMemoryClock); + le32_to_cpu(powerplay_table->ulMaxODMemoryClock); hwmgr->platform_descriptor.minOverdriveVDDC = 0; hwmgr->platform_descriptor.maxOverdriveVDDC = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 08cd0bd3ebe5b1e34b14940a4cff4805027518e1..3907439417e76c024910e69609ec7cf2f8aff96d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -825,7 +825,7 @@ uint32_t smu7_get_xclk(struct pp_hwmgr *hwmgr) { uint32_t reference_clock, tmp; struct cgs_display_info info = {0}; - struct cgs_mode_info mode_info; + struct cgs_mode_info mode_info = {0}; info.mode_info = &mode_info; @@ -3718,10 +3718,9 @@ int smu7_program_display_gap(struct pp_hwmgr *hwmgr) uint32_t ref_clock; uint32_t refresh_rate = 0; struct cgs_display_info info = {0}; - struct cgs_mode_info mode_info; + struct cgs_mode_info mode_info = {0}; info.mode_info = &mode_info; - cgs_get_active_displays_info(hwmgr->device, &info); num_active_displays = info.display_count; @@ -3737,6 +3736,7 @@ int smu7_program_display_gap(struct pp_hwmgr *hwmgr) frame_time_in_us = 1000000 / refresh_rate; pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us; + data->frame_time_x2 = frame_time_in_us * 2 / 100; display_gap2 = pre_vbi_time_in_us * (ref_clock / 100); diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 82c193e5e0d61654f5e28fcc961d0b74a31863a2..8b009b549e45bf2f741a980ddf2a6b8f517052f2 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -150,13 +150,8 @@ static void malidp_de_plane_update(struct drm_plane *plane, /* convert src values from Q16 fixed point to integer */ src_w = plane->state->src_w >> 16; src_h = plane->state->src_h >> 16; - if (plane->state->rotation & MALIDP_ROTATED_MASK) { - dest_w = plane->state->crtc_h; - dest_h = plane->state->crtc_w; - } else { - dest_w = plane->state->crtc_w; - dest_h = plane->state->crtc_h; - } + dest_w = plane->state->crtc_w; + dest_h = plane->state->crtc_h; malidp_hw_write(mp->hwdev, format_id, mp->layer->base); @@ -187,11 +182,12 @@ static void malidp_de_plane_update(struct drm_plane *plane, /* setup the rotation and axis flip bits */ if (plane->state->rotation & DRM_ROTATE_MASK) - val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET; + val |= ilog2(plane->state->rotation & DRM_ROTATE_MASK) << + LAYER_ROT_OFFSET; if (plane->state->rotation & DRM_REFLECT_X) - val |= LAYER_V_FLIP; - if (plane->state->rotation & DRM_REFLECT_Y) val |= LAYER_H_FLIP; + if (plane->state->rotation & DRM_REFLECT_Y) + val |= LAYER_V_FLIP; /* set the 'enable layer' bit */ val |= LAYER_ENABLE; diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 908011d2c8f5200e92cc8db772b85315d5c16343..3bedcf7ddd2a96367885afe36be1fd64d33442a5 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -113,6 +113,11 @@ struct ast_private { struct ttm_bo_kmap_obj cache_kmap; int next_cursor; bool support_wide_screen; + enum { + ast_use_p2a, + ast_use_dt, + ast_use_defaults + } config_mode; enum ast_tx_chip tx_chip_type; u8 dp501_maxclk; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f75c6421db6239c9435ed39dc7d6244d13894920..fb9976254224151601d87f9caed081e6401e14b5 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -62,13 +62,84 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast, return ret; } +static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev) +{ + struct device_node *np = dev->pdev->dev.of_node; + struct ast_private *ast = dev->dev_private; + uint32_t data, jregd0, jregd1; + + /* Defaults */ + ast->config_mode = ast_use_defaults; + *scu_rev = 0xffffffff; + + /* Check if we have device-tree properties */ + if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", + scu_rev)) { + /* We do, disable P2A access */ + ast->config_mode = ast_use_dt; + DRM_INFO("Using device-tree for configuration\n"); + return; + } + + /* Not all families have a P2A bridge */ + if (dev->pdev->device != PCI_CHIP_AST2000) + return; + + /* + * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge + * is disabled. We force using P2A if VGA only mode bit + * is set D[7] + */ + jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); + jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); + if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { + /* Double check it's actually working */ + data = ast_read32(ast, 0xf004); + if (data != 0xFFFFFFFF) { + /* P2A works, grab silicon revision */ + ast->config_mode = ast_use_p2a; + + DRM_INFO("Using P2A bridge for configuration\n"); + + /* Read SCU7c (silicon revision register) */ + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + *scu_rev = ast_read32(ast, 0x1207c); + return; + } + } + + /* We have a P2A bridge but it's disabled */ + DRM_INFO("P2A bridge disabled, using default configuration\n"); +} static int ast_detect_chip(struct drm_device *dev, bool *need_post) { struct ast_private *ast = dev->dev_private; - uint32_t data, jreg; + uint32_t jreg, scu_rev; + + /* + * If VGA isn't enabled, we need to enable now or subsequent + * access to the scratch registers will fail. We also inform + * our caller that it needs to POST the chip + * (Assumption: VGA not enabled -> need to POST) + */ + if (!ast_is_vga_enabled(dev)) { + ast_enable_vga(dev); + DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); + *need_post = true; + } else + *need_post = false; + + + /* Enable extended register access */ + ast_enable_mmio(dev); ast_open_key(ast); + /* Find out whether P2A works or whether to use device-tree */ + ast_detect_config_mode(dev, &scu_rev); + + /* Identify chipset */ if (dev->pdev->device == PCI_CHIP_AST1180) { ast->chip = AST1100; DRM_INFO("AST 1180 detected\n"); @@ -80,12 +151,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->chip = AST2300; DRM_INFO("AST 2300 detected\n"); } else if (dev->pdev->revision >= 0x10) { - uint32_t data; - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - - data = ast_read32(ast, 0x1207c); - switch (data & 0x0300) { + switch (scu_rev & 0x0300) { case 0x0200: ast->chip = AST1100; DRM_INFO("AST 1100 detected\n"); @@ -110,20 +176,6 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) } } - /* - * If VGA isn't enabled, we need to enable now or subsequent - * access to the scratch registers will fail. We also inform - * our caller that it needs to POST the chip - * (Assumption: VGA not enabled -> need to POST) - */ - if (!ast_is_vga_enabled(dev)) { - ast_enable_vga(dev); - ast_enable_mmio(dev); - DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); - *need_post = true; - } else - *need_post = false; - /* Check if we support wide screen */ switch (ast->chip) { case AST1180: @@ -140,14 +192,11 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->support_wide_screen = true; else { ast->support_wide_screen = false; - /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - data = ast_read32(ast, 0x1207c); - data &= 0x300; - if (ast->chip == AST2300 && data == 0x0) /* ast1300 */ + if (ast->chip == AST2300 && + (scu_rev & 0x300) == 0x0) /* ast1300 */ ast->support_wide_screen = true; - if (ast->chip == AST2400 && data == 0x100) /* ast1400 */ + if (ast->chip == AST2400 && + (scu_rev & 0x300) == 0x100) /* ast1400 */ ast->support_wide_screen = true; } break; @@ -212,29 +261,49 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) static int ast_get_dram_info(struct drm_device *dev) { + struct device_node *np = dev->pdev->dev.of_node; struct ast_private *ast = dev->dev_private; - uint32_t data, data2; - uint32_t denum, num, div, ref_pll; - - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - - - ast_write32(ast, 0x10000, 0xfc600309); + uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap; + uint32_t denum, num, div, ref_pll, dsel; - do { - if (pci_channel_offline(dev->pdev)) - return -EIO; - } while (ast_read32(ast, 0x10000) != 0x01); - data = ast_read32(ast, 0x10004); + switch (ast->config_mode) { + case ast_use_dt: + /* + * If some properties are missing, use reasonable + * defaults for AST2400 + */ + if (of_property_read_u32(np, "aspeed,mcr-configuration", + &mcr_cfg)) + mcr_cfg = 0x00000577; + if (of_property_read_u32(np, "aspeed,mcr-scu-mpll", + &mcr_scu_mpll)) + mcr_scu_mpll = 0x000050C0; + if (of_property_read_u32(np, "aspeed,mcr-scu-strap", + &mcr_scu_strap)) + mcr_scu_strap = 0; + break; + case ast_use_p2a: + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + mcr_cfg = ast_read32(ast, 0x10004); + mcr_scu_mpll = ast_read32(ast, 0x10120); + mcr_scu_strap = ast_read32(ast, 0x10170); + break; + case ast_use_defaults: + default: + ast->dram_bus_width = 16; + ast->dram_type = AST_DRAM_1Gx16; + ast->mclk = 396; + return 0; + } - if (data & 0x40) + if (mcr_cfg & 0x40) ast->dram_bus_width = 16; else ast->dram_bus_width = 32; if (ast->chip == AST2300 || ast->chip == AST2400) { - switch (data & 0x03) { + switch (mcr_cfg & 0x03) { case 0: ast->dram_type = AST_DRAM_512Mx16; break; @@ -250,13 +319,13 @@ static int ast_get_dram_info(struct drm_device *dev) break; } } else { - switch (data & 0x0c) { + switch (mcr_cfg & 0x0c) { case 0: case 4: ast->dram_type = AST_DRAM_512Mx16; break; case 8: - if (data & 0x40) + if (mcr_cfg & 0x40) ast->dram_type = AST_DRAM_1Gx16; else ast->dram_type = AST_DRAM_512Mx32; @@ -267,17 +336,15 @@ static int ast_get_dram_info(struct drm_device *dev) } } - data = ast_read32(ast, 0x10120); - data2 = ast_read32(ast, 0x10170); - if (data2 & 0x2000) + if (mcr_scu_strap & 0x2000) ref_pll = 14318; else ref_pll = 12000; - denum = data & 0x1f; - num = (data & 0x3fe0) >> 5; - data = (data & 0xc000) >> 14; - switch (data) { + denum = mcr_scu_mpll & 0x1f; + num = (mcr_scu_mpll & 0x3fe0) >> 5; + dsel = (mcr_scu_mpll & 0xc000) >> 14; + switch (dsel) { case 3: div = 0x4; break; diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 30672a3df8a9b73e8434af6acdac52050a59c0c5..c7c58becb25d70169c26b5dfcd5f6f45b3d20574 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -375,12 +375,17 @@ void ast_post_gpu(struct drm_device *dev) ast_enable_mmio(dev); ast_set_def_ext_reg(dev); - if (ast->chip == AST2300 || ast->chip == AST2400) - ast_init_dram_2300(dev); - else - ast_init_dram_reg(dev); + if (ast->config_mode == ast_use_p2a) { + if (ast->chip == AST2300 || ast->chip == AST2400) + ast_init_dram_2300(dev); + else + ast_init_dram_reg(dev); - ast_init_3rdtx(dev); + ast_init_3rdtx(dev); + } else { + if (ast->tx_chip_type != AST_TX_NONE) + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); /* Enable DVO */ + } } /* AST 2300 DRAM settings */ diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 161c923d6162cfe65b70a8f41ac46b963237be1c..3e74e1a6584c00e733017808ea62bdbd00989a09 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -315,6 +315,8 @@ struct adv7511 { bool edid_read; wait_queue_head_t wq; + struct work_struct hpd_work; + struct drm_bridge bridge; struct drm_connector connector; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 8ed3906dd411ecedc49b9010eeaa8ac9fa9914fc..a68f94daf9b626eb6928cd9d5fb64cbf4d361964 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -325,7 +325,7 @@ static void adv7511_set_link_config(struct adv7511 *adv7511, adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; } -static void adv7511_power_on(struct adv7511 *adv7511) +static void __adv7511_power_on(struct adv7511 *adv7511) { adv7511->current_edid_segment = -1; @@ -354,6 +354,11 @@ static void adv7511_power_on(struct adv7511 *adv7511) regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, ADV7511_REG_POWER2_HPD_SRC_MASK, ADV7511_REG_POWER2_HPD_SRC_NONE); +} + +static void adv7511_power_on(struct adv7511 *adv7511) +{ + __adv7511_power_on(adv7511); /* * Most of the registers are reset during power down or when HPD is low. @@ -362,21 +367,23 @@ static void adv7511_power_on(struct adv7511 *adv7511) if (adv7511->type == ADV7533) adv7533_dsi_power_on(adv7511); - adv7511->powered = true; } -static void adv7511_power_off(struct adv7511 *adv7511) +static void __adv7511_power_off(struct adv7511 *adv7511) { /* TODO: setup additional power down modes */ regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); regcache_mark_dirty(adv7511->regmap); +} +static void adv7511_power_off(struct adv7511 *adv7511) +{ + __adv7511_power_off(adv7511); if (adv7511->type == ADV7533) adv7533_dsi_power_off(adv7511); - adv7511->powered = false; } @@ -402,6 +409,27 @@ static bool adv7511_hpd(struct adv7511 *adv7511) return false; } +static void adv7511_hpd_work(struct work_struct *work) +{ + struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work); + enum drm_connector_status status; + unsigned int val; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); + if (ret < 0) + status = connector_status_disconnected; + else if (val & ADV7511_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + + if (adv7511->connector.status != status) { + adv7511->connector.status = status; + drm_kms_helper_hotplug_event(adv7511->connector.dev); + } +} + static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) { unsigned int irq0, irq1; @@ -419,7 +447,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) - drm_helper_hpd_irq_event(adv7511->connector.dev); + schedule_work(&adv7511->hpd_work); if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { adv7511->edid_read = true; @@ -546,23 +574,20 @@ static int adv7511_get_modes(struct adv7511 *adv7511, /* Reading the EDID only works if the device is powered */ if (!adv7511->powered) { - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, 0); - if (adv7511->i2c_main->irq) { - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), - ADV7511_INT0_EDID_READY); - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), - ADV7511_INT1_DDC_ERROR); - } - adv7511->current_edid_segment = -1; + unsigned int edid_i2c_addr = + (adv7511->i2c_main->addr << 1) + 4; + + __adv7511_power_on(adv7511); + + /* Reset the EDID_I2C_ADDR register as it might be cleared */ + regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, + edid_i2c_addr); } edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); if (!adv7511->powered) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, - ADV7511_POWER_POWER_DOWN); + __adv7511_power_off(adv7511); kfree(adv7511->edid); adv7511->edid = edid; @@ -1006,6 +1031,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) goto err_i2c_unregister_edid; } + INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); + if (i2c->irq) { init_waitqueue_head(&adv7511->wq); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 4e19bde4bbffac08e700460b69db882f42d5463b..33778bf535909b34ce980fd64fcf401e3003cbd2 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" @@ -292,6 +293,23 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_crtc_state); +static void set_out_fence_for_crtc(struct drm_atomic_state *state, + struct drm_crtc *crtc, s32 __user *fence_ptr) +{ + state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr; +} + +static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, + struct drm_crtc *crtc) +{ + s32 __user *fence_ptr; + + fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr; + state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL; + + return fence_ptr; +} + /** * drm_atomic_set_mode_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update @@ -496,6 +514,16 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, &replaced); state->color_mgmt_changed |= replaced; return ret; + } else if (property == config->prop_out_fence_ptr) { + s32 __user *fence_ptr = u64_to_user_ptr(val); + + if (!fence_ptr) + return 0; + + if (put_user(-1, fence_ptr)) + return -EFAULT; + + set_out_fence_for_crtc(state->state, crtc, fence_ptr); } else if (crtc->funcs->atomic_set_property) return crtc->funcs->atomic_set_property(crtc, state, property, val); else @@ -538,6 +566,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = (state->ctm) ? state->ctm->base.id : 0; else if (property == config->gamma_lut_property) *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; + else if (property == config->prop_out_fence_ptr) + *val = 0; else if (crtc->funcs->atomic_get_property) return crtc->funcs->atomic_get_property(crtc, state, property, val); else @@ -693,6 +723,17 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, drm_atomic_set_fb_for_plane(state, fb); if (fb) drm_framebuffer_unreference(fb); + } else if (property == config->prop_in_fence_fd) { + if (state->fence) + return -EINVAL; + + if (U642I64(val) == -1) + return 0; + + state->fence = sync_file_get_fence(val); + if (!state->fence) + return -EINVAL; + } else if (property == config->prop_crtc_id) { struct drm_crtc *crtc = drm_crtc_find(dev, val); return drm_atomic_set_crtc_for_plane(state, crtc); @@ -752,6 +793,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane, if (property == config->prop_fb_id) { *val = (state->fb) ? state->fb->base.id : 0; + } else if (property == config->prop_in_fence_fd) { + *val = -1; } else if (property == config->prop_crtc_id) { *val = (state->crtc) ? state->crtc->base.id : 0; } else if (property == config->prop_crtc_x) { @@ -1151,6 +1194,36 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, } EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); +/** + * drm_atomic_set_fence_for_plane - set fence for plane + * @plane_state: atomic state object for the plane + * @fence: fence to use for the plane + * + * Helper to setup the plane_state fence in case it is not set yet. + * By using this drivers doesn't need to worry if the user choose + * implicit or explicit fencing. + * + * This function will not set the fence to the state if it was set + * via explicit fencing interfaces on the atomic ioctl. It will + * all drope the reference to the fence as we not storing it + * anywhere. + * + * Otherwise, if plane_state->fence is not set this function we + * just set it with the received implict fence. + */ +void +drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, + struct fence *fence) +{ + if (plane_state->fence) { + fence_put(fence); + return; + } + + plane_state->fence = fence; +} +EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); + /** * drm_atomic_set_crtc_for_connector - set crtc for connector * @conn_state: atomic state object for the connector @@ -1386,6 +1459,9 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (config->funcs->atomic_check) ret = config->funcs->atomic_check(state->dev, state); + if (ret) + return ret; + if (!state->allow_modeset) { for_each_crtc_in_state(state, crtc, crtc_state, i) { if (drm_atomic_crtc_needs_modeset(crtc_state)) { @@ -1396,7 +1472,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } - return ret; + return 0; } EXPORT_SYMBOL(drm_atomic_check_only); @@ -1467,11 +1543,9 @@ EXPORT_SYMBOL(drm_atomic_nonblocking_commit); */ static struct drm_pending_vblank_event *create_vblank_event( - struct drm_device *dev, struct drm_file *file_priv, - struct fence *fence, uint64_t user_data) + struct drm_device *dev, uint64_t user_data) { struct drm_pending_vblank_event *e = NULL; - int ret; e = kzalloc(sizeof *e, GFP_KERNEL); if (!e) @@ -1481,17 +1555,6 @@ static struct drm_pending_vblank_event *create_vblank_event( e->event.base.length = sizeof(e->event); e->event.user_data = user_data; - if (file_priv) { - ret = drm_event_reserve_init(dev, file_priv, &e->base, - &e->event.base); - if (ret) { - kfree(e); - return NULL; - } - } - - e->base.fence = fence; - return e; } @@ -1596,6 +1659,206 @@ void drm_atomic_clean_old_fb(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_clean_old_fb); +/** + * DOC: explicit fencing properties + * + * Explicit fencing allows userspace to control the buffer synchronization + * between devices. A Fence or a group of fences are transfered to/from + * userspace using Sync File fds and there are two DRM properties for that. + * IN_FENCE_FD on each DRM Plane to send fences to the kernel and + * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel. + * + * As a contrast, with implicit fencing the kernel keeps track of any + * ongoing rendering, and automatically ensures that the atomic update waits + * for any pending rendering to complete. For shared buffers represented with + * a struct &dma_buf this is tracked in &reservation_object structures. + * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org), + * whereas explicit fencing is what Android wants. + * + * "IN_FENCE_FDâ€: + * Use this property to pass a fence that DRM should wait on before + * proceeding with the Atomic Commit request and show the framebuffer for + * the plane on the screen. The fence can be either a normal fence or a + * merged one, the sync_file framework will handle both cases and use a + * fence_array if a merged fence is received. Passing -1 here means no + * fences to wait on. + * + * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag + * it will only check if the Sync File is a valid one. + * + * On the driver side the fence is stored on the @fence parameter of + * struct &drm_plane_state. Drivers which also support implicit fencing + * should set the implicit fence using drm_atomic_set_fence_for_plane(), + * to make sure there's consistent behaviour between drivers in precedence + * of implicit vs. explicit fencing. + * + * "OUT_FENCE_PTRâ€: + * Use this property to pass a file descriptor pointer to DRM. Once the + * Atomic Commit request call returns OUT_FENCE_PTR will be filled with + * the file descriptor number of a Sync File. This Sync File contains the + * CRTC fence that will be signaled when all framebuffers present on the + * Atomic Commit * request for that given CRTC are scanned out on the + * screen. + * + * The Atomic Commit request fails if a invalid pointer is passed. If the + * Atomic Commit request fails for any other reason the out fence fd + * returned will be -1. On a Atomic Commit with the + * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1. + * + * Note that out-fences don't have a special interface to drivers and are + * internally represented by a struct &drm_pending_vblank_event in struct + * &drm_crtc_state, which is also used by the nonblocking atomic commit + * helpers and for the DRM event handling for existing userspace. + */ + +struct drm_out_fence_state { + s32 __user *out_fence_ptr; + struct sync_file *sync_file; + int fd; +}; + +static int setup_out_fence(struct drm_out_fence_state *fence_state, + struct fence *fence) +{ + fence_state->fd = get_unused_fd_flags(O_CLOEXEC); + if (fence_state->fd < 0) + return fence_state->fd; + + if (put_user(fence_state->fd, fence_state->out_fence_ptr)) + return -EFAULT; + + fence_state->sync_file = sync_file_create(fence); + if (!fence_state->sync_file) + return -ENOMEM; + + return 0; +} + +static int prepare_crtc_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_mode_atomic *arg, + struct drm_file *file_priv, + struct drm_out_fence_state **fence_state, + unsigned int *num_fences) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, ret; + + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) + return 0; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + s32 __user *fence_ptr; + + fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) { + struct drm_pending_vblank_event *e; + + e = create_vblank_event(dev, arg->user_data); + if (!e) + return -ENOMEM; + + crtc_state->event = e; + } + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + struct drm_pending_vblank_event *e = crtc_state->event; + + if (!file_priv) + continue; + + ret = drm_event_reserve_init(dev, file_priv, &e->base, + &e->event.base); + if (ret) { + kfree(e); + crtc_state->event = NULL; + return ret; + } + } + + if (fence_ptr) { + struct fence *fence; + struct drm_out_fence_state *f; + + f = krealloc(*fence_state, sizeof(**fence_state) * + (*num_fences + 1), GFP_KERNEL); + if (!f) + return -ENOMEM; + + memset(&f[*num_fences], 0, sizeof(*f)); + + f[*num_fences].out_fence_ptr = fence_ptr; + *fence_state = f; + + fence = drm_crtc_create_fence(crtc); + if (!fence) + return -ENOMEM; + + ret = setup_out_fence(&f[(*num_fences)++], fence); + if (ret) { + fence_put(fence); + return ret; + } + + crtc_state->event->base.fence = fence; + } + } + + return 0; +} + +static void complete_crtc_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_out_fence_state *fence_state, + unsigned int num_fences, + bool install_fds) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + if (install_fds) { + for (i = 0; i < num_fences; i++) + fd_install(fence_state[i].fd, + fence_state[i].sync_file->file); + + kfree(fence_state); + return; + } + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct drm_pending_vblank_event *event = crtc_state->event; + /* + * Free the allocated event. drm_atomic_helper_setup_commit + * can allocate an event too, so only free it if it's ours + * to prevent a double free in drm_atomic_state_clear. + */ + if (event && (event->base.fence || event->base.file_priv)) { + drm_event_cancel_free(dev, &event->base); + crtc_state->event = NULL; + } + } + + if (!fence_state) + return; + + for (i = 0; i < num_fences; i++) { + if (fence_state[i].sync_file) + fput(fence_state[i].sync_file->file); + if (fence_state[i].fd >= 0) + put_unused_fd(fence_state[i].fd); + + /* If this fails log error to the user */ + if (fence_state[i].out_fence_ptr && + put_user(-1, fence_state[i].out_fence_ptr)) + DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n"); + } + + kfree(fence_state); +} + int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1608,11 +1871,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_atomic_state *state; struct drm_modeset_acquire_ctx ctx; struct drm_plane *plane; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; + struct drm_out_fence_state *fence_state; unsigned plane_mask; int ret = 0; - unsigned int i, j; + unsigned int i, j, num_fences; /* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) @@ -1653,6 +1915,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, plane_mask = 0; copied_objs = 0; copied_props = 0; + fence_state = NULL; + num_fences = 0; for (i = 0; i < arg->count_objs; i++) { uint32_t obj_id, count_props; @@ -1727,20 +1991,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, drm_mode_object_unreference(obj); } - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - for_each_crtc_in_state(state, crtc, crtc_state, i) { - struct drm_pending_vblank_event *e; - - e = create_vblank_event(dev, file_priv, NULL, - arg->user_data); - if (!e) { - ret = -ENOMEM; - goto out; - } - - crtc_state->event = e; - } - } + ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state, + &num_fences); + if (ret) + goto out; if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { /* @@ -1757,20 +2011,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, out: drm_atomic_clean_old_fb(dev, plane_mask, ret); - if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - /* - * Free the allocated event. drm_atomic_helper_setup_commit - * can allocate an event too, so only free it if it's ours - * to prevent a double free in drm_atomic_state_clear. - */ - for_each_crtc_in_state(state, crtc, crtc_state, i) { - struct drm_pending_vblank_event *event = crtc_state->event; - if (event && (event->base.fence || event->base.file_priv)) { - drm_event_cancel_free(dev, &event->base); - crtc_state->event = NULL; - } - } - } + complete_crtc_signaling(dev, state, fence_state, num_fences, !ret); if (ret == -EDEADLK) { drm_atomic_state_clear(state); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 50acd799babe1824e47e4bba6b9f03875429c17a..f34b4e8455a6570f3abe4d1c1959da8e2764fe09 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3166,6 +3166,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) { if (state->fb) drm_framebuffer_unreference(state->fb); + + if (state->fence) + fence_put(state->fence); } EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 2db7fb510b6c941c2f252dc29591e4c51cd981c5..0e934a9ac63cbe034f67691ca1848db7907ac90a 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -225,6 +225,7 @@ int drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); + mutex_init(&connector->mutex); connector->edid_blob_ptr = NULL; connector->status = connector_status_unknown; @@ -359,6 +360,8 @@ void drm_connector_cleanup(struct drm_connector *connector) connector->funcs->atomic_destroy_state(connector, connector->state); + mutex_destroy(&connector->mutex); + memset(connector, 0, sizeof(*connector)); } EXPORT_SYMBOL(drm_connector_cleanup); @@ -374,14 +377,18 @@ EXPORT_SYMBOL(drm_connector_cleanup); */ int drm_connector_register(struct drm_connector *connector) { - int ret; + int ret = 0; - if (connector->registered) + if (!connector->dev->registered) return 0; + mutex_lock(&connector->mutex); + if (connector->registered) + goto unlock; + ret = drm_sysfs_connector_add(connector); if (ret) - return ret; + goto unlock; ret = drm_debugfs_connector_add(connector); if (ret) { @@ -397,12 +404,14 @@ int drm_connector_register(struct drm_connector *connector) drm_mode_object_register(connector->dev, &connector->base); connector->registered = true; - return 0; + goto unlock; err_debugfs: drm_debugfs_connector_remove(connector); err_sysfs: drm_sysfs_connector_remove(connector); +unlock: + mutex_unlock(&connector->mutex); return ret; } EXPORT_SYMBOL(drm_connector_register); @@ -415,8 +424,11 @@ EXPORT_SYMBOL(drm_connector_register); */ void drm_connector_unregister(struct drm_connector *connector) { - if (!connector->registered) + mutex_lock(&connector->mutex); + if (!connector->registered) { + mutex_unlock(&connector->mutex); return; + } if (connector->funcs->early_unregister) connector->funcs->early_unregister(connector); @@ -425,6 +437,7 @@ void drm_connector_unregister(struct drm_connector *connector) drm_debugfs_connector_remove(connector); connector->registered = false; + mutex_unlock(&connector->mutex); } EXPORT_SYMBOL(drm_connector_unregister); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2d7bedf286473c20b0da3ba7bd5a3c945f0c7be6..79b3d521c3885e4f13ea7153d742e8343a0ea4e7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,54 @@ static void drm_crtc_unregister_all(struct drm_device *dev) } } +static const struct fence_ops drm_crtc_fence_ops; + +static struct drm_crtc *fence_to_crtc(struct fence *fence) +{ + BUG_ON(fence->ops != &drm_crtc_fence_ops); + return container_of(fence->lock, struct drm_crtc, fence_lock); +} + +static const char *drm_crtc_fence_get_driver_name(struct fence *fence) +{ + struct drm_crtc *crtc = fence_to_crtc(fence); + + return crtc->dev->driver->name; +} + +static const char *drm_crtc_fence_get_timeline_name(struct fence *fence) +{ + struct drm_crtc *crtc = fence_to_crtc(fence); + + return crtc->timeline_name; +} + +static bool drm_crtc_fence_enable_signaling(struct fence *fence) +{ + return true; +} + +static const struct fence_ops drm_crtc_fence_ops = { + .get_driver_name = drm_crtc_fence_get_driver_name, + .get_timeline_name = drm_crtc_fence_get_timeline_name, + .enable_signaling = drm_crtc_fence_enable_signaling, + .wait = fence_default_wait, +}; + +struct fence *drm_crtc_create_fence(struct drm_crtc *crtc) +{ + struct fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return NULL; + + fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock, + crtc->fence_context, ++crtc->fence_seqno); + + return fence; +} + /** * drm_crtc_init_with_planes - Initialise a new CRTC object with * specified primary and cursor planes. @@ -198,6 +247,11 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, return -ENOMEM; } + crtc->fence_context = fence_context_alloc(1); + spin_lock_init(&crtc->fence_lock); + snprintf(crtc->timeline_name, sizeof(crtc->timeline_name), + "CRTC:%d-%s", crtc->base.id, crtc->name); + crtc->base.properties = &crtc->properties; list_add_tail(&crtc->head, &config->crtc_list); @@ -213,6 +267,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&crtc->base, config->prop_active, 0); drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); + drm_object_attach_property(&crtc->base, + config->prop_out_fence_ptr, 0); } return 0; @@ -365,6 +421,18 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_fb_id = prop; + prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, + "IN_FENCE_FD", -1, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_in_fence_fd = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "OUT_FENCE_PTR", 0, U64_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_out_fence_ptr = prop; + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, "CRTC_ID", DRM_MODE_OBJECT_CRTC); if (!prop) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index c48ba02c5365d6a49e8d0915d35b1d23cdd00c90..df2b51a4f75ef6bdc55cb2dacb4ba98bf4505f5f 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -41,6 +41,8 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, const struct drm_display_mode *mode, const struct drm_framebuffer *fb); +struct fence *drm_crtc_create_fence(struct drm_crtc *crtc); + void drm_fb_release(struct drm_file *file_priv); /* dumb buffer support IOCTLs */ diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 3e6fe82c6d64bb5bd3b444f1aaafb503a9aa2ffd..639410926cadaccda947ae877b0fc8b8815c4427 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -144,6 +144,8 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate) return DP_LINK_BW_2_7; case 540000: return DP_LINK_BW_5_4; + case 810000: + return DP_LINK_BW_8_1; } } EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); @@ -158,6 +160,8 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) return 270000; case DP_LINK_BW_5_4: return 540000; + case DP_LINK_BW_8_1: + return 810000; } } EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); @@ -354,20 +358,13 @@ EXPORT_SYMBOL(drm_dp_link_probe); */ int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) { - u8 value; + u8 value = DP_SET_POWER_D0; int err; /* DP_SET_POWER register is only available on DPCD v1.1 and later */ if (link->revision < 0x11) return 0; - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; - - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D0; - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); if (err < 0) return err; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index f59771da52eec030270d1d3e2d2038dc64e0d9f1..db7890cb254ed93df1412d3ebd9a1735ff213d30 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -330,6 +330,13 @@ static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg, return false; } + /* + * ignore out-of-order messages or messages that are part of a + * failed transaction + */ + if (!recv_hdr.somt && !msg->have_somt) + return false; + /* get length contained in this portion */ msg->curchunk_len = recv_hdr.msg_len; msg->curchunk_hdrlen = hdrlen; @@ -2168,7 +2175,7 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) } EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume); -static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up) +static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up) { int len; u8 replyblock[32]; @@ -2183,12 +2190,12 @@ static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up) replyblock, len); if (ret != len) { DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret); - return; + return false; } ret = drm_dp_sideband_msg_build(msg, replyblock, len, true); if (!ret) { DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]); - return; + return false; } replylen = msg->curchunk_len + msg->curchunk_hdrlen; @@ -2200,21 +2207,32 @@ static void drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up) ret = drm_dp_dpcd_read(mgr->aux, basereg + curreply, replyblock, len); if (ret != len) { - DRM_DEBUG_KMS("failed to read a chunk\n"); + DRM_DEBUG_KMS("failed to read a chunk (len %d, ret %d)\n", + len, ret); + return false; } + ret = drm_dp_sideband_msg_build(msg, replyblock, len, false); - if (ret == false) + if (!ret) { DRM_DEBUG_KMS("failed to build sideband msg\n"); + return false; + } + curreply += len; replylen -= len; } + return true; } static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) { int ret = 0; - drm_dp_get_one_sb_msg(mgr, false); + if (!drm_dp_get_one_sb_msg(mgr, false)) { + memset(&mgr->down_rep_recv, 0, + sizeof(struct drm_dp_sideband_msg_rx)); + return 0; + } if (mgr->down_rep_recv.have_eomt) { struct drm_dp_sideband_msg_tx *txmsg; @@ -2270,7 +2288,12 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) { int ret = 0; - drm_dp_get_one_sb_msg(mgr, true); + + if (!drm_dp_get_one_sb_msg(mgr, true)) { + memset(&mgr->up_req_recv, 0, + sizeof(struct drm_dp_sideband_msg_rx)); + return 0; + } if (mgr->up_req_recv.have_eomt) { struct drm_dp_sideband_msg_req_body msg; @@ -2322,7 +2345,9 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn); } - drm_dp_put_mst_branch_device(mstb); + if (mstb) + drm_dp_put_mst_branch_device(mstb); + memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); } return ret; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 6efdba4993fc8c5f1a0f15c0de163bd89d1eaccc..80a903bd317df027cec2b153250a38cbdd43a5ca 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -218,7 +218,7 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); - return ret; + goto err_debugfs; } ret = device_add(minor->kdev); @@ -379,7 +379,12 @@ EXPORT_SYMBOL(drm_put_dev); void drm_unplug_dev(struct drm_device *dev) { /* for a USB device */ - drm_dev_unregister(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_modeset_unregister_all(dev); + + drm_minor_unregister(dev, DRM_MINOR_PRIMARY); + drm_minor_unregister(dev, DRM_MINOR_RENDER); + drm_minor_unregister(dev, DRM_MINOR_CONTROL); mutex_lock(&drm_global_mutex); @@ -705,6 +710,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (ret) goto err_minors; + dev->registered = true; + if (dev->driver->load) { ret = dev->driver->load(dev, flags); if (ret) @@ -744,6 +751,8 @@ void drm_dev_unregister(struct drm_device *dev) drm_lastclose(dev); + dev->registered = false; + if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_modeset_unregister_all(dev); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0bc0afb6321e8469131cf893addd8bddca01e87f..4e5ba7eed5421274b9c90ec0908119861626fff7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -76,6 +76,8 @@ #define EDID_QUIRK_FORCE_12BPC (1 << 9) /* Force 6bpc */ #define EDID_QUIRK_FORCE_6BPC (1 << 10) +/* Force 10bpc */ +#define EDID_QUIRK_FORCE_10BPC (1 << 11) struct detailed_mode_closure { struct drm_connector *connector; @@ -90,6 +92,14 @@ struct detailed_mode_closure { #define LEVEL_GTF2 2 #define LEVEL_CVT 3 +/*Enum storing luminance types for HDR blocks in EDID*/ +enum luminance_value { + NO_LUMINANCE_DATA = 3, + MAXIMUM_LUMINANCE = 4, + FRAME_AVERAGE_LUMINANCE = 5, + MINIMUM_LUMINANCE = 6 +}; + static const struct edid_quirk { char vendor[4]; int product_id; @@ -118,6 +128,9 @@ static const struct edid_quirk { { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 | EDID_QUIRK_DETAILED_IN_CM }, + /* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */ + { "LGD", 764, EDID_QUIRK_FORCE_10BPC }, + /* LG Philips LCD LP154W01-A5 */ { "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, { "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, @@ -997,6 +1010,221 @@ static const struct drm_display_mode edid_cea_modes[] = { 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 65 - 1280x720@24Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 66 - 1280x720@25Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, + 3740, 3960, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 67 - 1280x720@30Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 68 - 1280x720@50Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 69 - 1280x720@60Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 70 - 1280x720@100Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 71 - 1280x720@120Hz */ + { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 72 - 1920x1080@24Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, + 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 73 - 1920x1080@25Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 74 - 1920x1080@30Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 75 - 1920x1080@50Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 76 - 1920x1080@60Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 77 - 1920x1080@100Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 78 - 1920x1080@120Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 79 - 1680x720@24Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 3040, + 3080, 3300, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 80 - 1680x720@25Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2908, + 2948, 3168, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 81 - 1680x720@30Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2380, + 2420, 2640, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 82 - 1680x720@50Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 82500, 1680, 1940, + 1980, 2200, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 83 - 1680x720@60Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 99000, 1680, 1940, + 1980, 2200, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 84 - 1680x720@100Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 165000, 1680, 1740, + 1780, 2000, 0, 720, 725, 730, 825, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 85 - 1680x720@120Hz */ + { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 198000, 1680, 1740, + 1780, 2000, 0, 720, 725, 730, 825, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 86 - 2560x1080@24Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 99000, 2560, 3558, + 3602, 3750, 0, 1080, 1084, 1089, 1100, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 87 - 2560x1080@25Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 90000, 2560, 3008, + 3052, 3200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 88 - 2560x1080@30Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 118800, 2560, 3328, + 3372, 3520, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 89 - 2560x1080@50Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 185625, 2560, 3108, + 3152, 3300, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 90 - 2560x1080@60Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 198000, 2560, 2808, + 2852, 3000, 0, 1080, 1084, 1089, 1100, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 91 - 2560x1080@100Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 371250, 2560, 2778, + 2822, 2970, 0, 1080, 1084, 1089, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 92 - 2560x1080@120Hz */ + { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 495000, 2560, 3108, + 3152, 3300, 0, 1080, 1084, 1089, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 93 - 3840x2160p@24Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116, + 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9,}, + /* 94 - 3840x2160p@25Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896, + 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9}, + /* 95 - 3840x2160p@30Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9}, + /* 96 - 3840x2160p@50Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896, + 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9}, + /* 97 - 3840x2160p@60Hz 16:9 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9}, + /* 98 - 4096x2160p@24Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5116, + 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135}, + /* 99 - 4096x2160p@25Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064, + 5152, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135}, + /* 100 - 4096x2160p@30Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 4184, + 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135}, + /* 101 - 4096x2160p@50Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064, + 5152, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135}, + /* 102 - 4096x2160p@60Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184, + 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135}, + /* 103 - 3840x2160p@24Hz 64:27 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116, + 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27}, + /* 104 - 3840x2160p@25Hz 64:27 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27}, + /* 105 - 3840x2160p@30Hz 64:27 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27}, + /* 106 - 3840x2160p@50Hz 64:27 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896, + 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27}, + /* 107 - 3840x2160p@60Hz 64:27 */ + { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, + 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27}, }; /* @@ -2514,12 +2742,15 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, return closure.modes; } - +#define VIDEO_CAPABILITY_EXTENDED_DATA_BLOCK 0x0 #define AUDIO_BLOCK 0x01 #define VIDEO_BLOCK 0x02 #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 +#define HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK 0x06 +#define EXTENDED_TAG 0x07 #define VIDEO_CAPABILITY_BLOCK 0x07 +#define Y420_VIDEO_DATA_BLOCK 0x0E #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) @@ -3168,6 +3399,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) return hdmi_id == HDMI_IEEE_OUI; } +static bool cea_db_is_hdmi_hf_vsdb(const u8 *db) +{ + int hdmi_id; + + if (cea_db_tag(db) != VENDOR_BLOCK) + return false; + + if (cea_db_payload_len(db) < 7) + return false; + + hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16); + + return hdmi_id == HDMI_IEEE_OUI_HF; +} + #define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) @@ -3286,6 +3532,227 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) connector->audio_latency[1]); } +static void +parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db) +{ + u8 len = cea_db_payload_len(db); + + if (len < 7) + return; + + if (db[4] != 1) + return; /* invalid version */ + + connector->max_tmds_char = db[5] * 5; + connector->scdc_present = db[6] & (1 << 7); + connector->rr_capable = db[6] & (1 << 6); + connector->flags_3d = db[6] & 0x7; + connector->supports_scramble = connector->scdc_present && + (db[6] & (1 << 3)); + + DRM_DEBUG_KMS("HDMI v2: max TMDS char %d, " + "scdc %s, " + "rr %s, " + "3D flags 0x%x, " + "scramble %s\n", + connector->max_tmds_char, + connector->scdc_present ? "available" : "not available", + connector->rr_capable ? "capable" : "not capable", + connector->flags_3d, + connector->supports_scramble ? + "supported" : "not supported"); +} + +/* + * drm_extract_vcdb_info - Parse the HDMI Video Capability Data Block + * @connector: connector corresponding to the HDMI sink + * @db: start of the CEA vendor specific block + * + * Parses the HDMI VCDB to extract sink info for @connector. + */ +static void +drm_extract_vcdb_info(struct drm_connector *connector, const u8 *db) +{ + /* + * Check if the sink specifies underscan + * support for: + * BIT 5: preferred video format + * BIT 3: IT video format + * BIT 1: CE video format + */ + + connector->pt_scan_info = + (db[2] & (BIT(4) | BIT(5))) >> 4; + connector->it_scan_info = + (db[2] & (BIT(3) | BIT(2))) >> 2; + connector->ce_scan_info = + db[2] & (BIT(1) | BIT(0)); + + DRM_DEBUG_KMS("Scan Info (pt|it|ce): (%d|%d|%d)", + (int) connector->pt_scan_info, + (int) connector->it_scan_info, + (int) connector->ce_scan_info); +} + +static bool drm_edid_is_luminance_value_present( +u32 block_length, enum luminance_value value) +{ + return block_length > NO_LUMINANCE_DATA && value <= block_length; +} + +/* + * drm_extract_hdr_db - Parse the HDMI HDR extended block + * @connector: connector corresponding to the HDMI sink + * @db: start of the HDMI HDR extended block + * + * Parses the HDMI HDR extended block to extract sink info for @connector. + */ +static void +drm_extract_hdr_db(struct drm_connector *connector, const u8 *db) +{ + + u8 len = 0; + + if (!db) + return; + + len = db[0] & 0x1f; + /* Byte 3: Electro-Optical Transfer Functions */ + connector->hdr_eotf = db[2] & 0x3F; + + /* Byte 4: Static Metadata Descriptor Type 1 */ + connector->hdr_metadata_type_one = (db[3] & BIT(0)); + + /* Byte 5: Desired Content Maximum Luminance */ + if (drm_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE)) + connector->hdr_max_luminance = + db[MAXIMUM_LUMINANCE]; + + /* Byte 6: Desired Content Max Frame-average Luminance */ + if (drm_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE)) + connector->hdr_avg_luminance = + db[FRAME_AVERAGE_LUMINANCE]; + + /* Byte 7: Desired Content Min Luminance */ + if (drm_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE)) + connector->hdr_min_luminance = + db[MINIMUM_LUMINANCE]; + + connector->hdr_supported = true; + + DRM_DEBUG_KMS("HDR electro-optical %d\n", connector->hdr_eotf); + DRM_DEBUG_KMS("metadata desc 1 %d\n", connector->hdr_metadata_type_one); + DRM_DEBUG_KMS("max luminance %d\n", connector->hdr_max_luminance); + DRM_DEBUG_KMS("avg luminance %d\n", connector->hdr_avg_luminance); + DRM_DEBUG_KMS("min luminance %d\n", connector->hdr_min_luminance); +} + +/* + * drm_hdmi_extract_extended_blk_info - Parse the HDMI extended tag blocks + * @connector: connector corresponding to the HDMI sink + * @edid: handle to the EDID structure + * Parses the all extended tag blocks extract sink info for @connector. + */ +static void +drm_hdmi_extract_extended_blk_info(struct drm_connector *connector, +struct edid *edid) +{ + const u8 *cea = drm_find_cea_extension(edid); + const u8 *db = NULL; + + if (cea && cea_revision(cea) >= 3) { + int i, start, end; + + if (cea_db_offsets(cea, &start, &end)) + return; + + for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + + if (cea_db_tag(db) == EXTENDED_TAG) { + DRM_DEBUG_KMS("found extended tag block = %d\n", + db[1]); + switch (db[1]) { + case VIDEO_CAPABILITY_EXTENDED_DATA_BLOCK: + drm_extract_vcdb_info(connector, db); + break; + case HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK: + drm_extract_hdr_db(connector, db); + break; + default: + break; + } + } + } + } +} + +static u8 * +drm_edid_find_extended_tag_block(struct edid *edid, int blk_id) +{ + u8 *db = NULL; + u8 *cea = NULL; + + if (!edid) + return NULL; + + cea = drm_find_cea_extension(edid); + + if (cea && cea_revision(cea) >= 3) { + int i, start, end; + + if (cea_db_offsets(cea, &start, &end)) + return NULL; + + for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + if ((cea_db_tag(db) == EXTENDED_TAG) && + (db[1] == blk_id)) + return db; + } + } + return NULL; +} + +/* + * add_YCbCr420VDB_modes - add the modes found in Ycbcr420 VDB block + * @connector: connector corresponding to the HDMI sink + * @edid: handle to the EDID structure + * Parses the YCbCr420 VDB block and adds the modes to @connector. + */ +static int +add_YCbCr420VDB_modes(struct drm_connector *connector, struct edid *edid) +{ + + const u8 *db = NULL; + u32 i = 0; + u32 modes = 0; + u32 video_format = 0; + u8 len = 0; + + /*Find the YCbCr420 VDB*/ + db = drm_edid_find_extended_tag_block(edid, Y420_VIDEO_DATA_BLOCK); + /* Offset to byte 3 */ + if (db) { + len = db[0] & 0x1F; + db += 2; + for (i = 0; i < len - 1; i++) { + struct drm_display_mode *mode; + + video_format = *(db + i) & 0x7F; + mode = drm_display_mode_from_vic_index(connector, + db, len-1, i); + if (mode) { + DRM_DEBUG_KMS("Adding mode for vic = %d\n", + video_format); + drm_mode_probed_add(connector, mode); + modes++; + } + } + } + return modes; +} + static void monitor_name(struct detailed_timing *t, void *data) { @@ -3410,6 +3877,9 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) /* HDMI Vendor-Specific Data Block */ if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_audio(connector, db); + /* HDMI Forum Vendor-Specific Data Block */ + else if (cea_db_is_hdmi_hf_vsdb(db)) + parse_hdmi_hf_vsdb(connector, db); break; default: break; @@ -3840,6 +4310,37 @@ static void drm_parse_cea_ext(struct drm_connector *connector, } } +static void +drm_hdmi_extract_vsdbs_info(struct drm_connector *connector, struct edid *edid) +{ + const u8 *cea = drm_find_cea_extension(edid); + const u8 *db = NULL; + + if (cea && cea_revision(cea) >= 3) { + int i, start, end; + + if (cea_db_offsets(cea, &start, &end)) + return; + + for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + + if (cea_db_tag(db) == VENDOR_BLOCK) { + /* HDMI Vendor-Specific Data Block */ + if (cea_db_is_hdmi_vsdb(db)) { + drm_parse_hdmi_vsdb_video( + connector, db); + drm_parse_hdmi_vsdb_audio( + connector, db); + } + /* HDMI Forum Vendor-Specific Data Block */ + else if (cea_db_is_hdmi_hf_vsdb(db)) + parse_hdmi_hf_vsdb(connector, db); + } + } + } +} + static void drm_add_display_info(struct drm_connector *connector, struct edid *edid) { @@ -3877,6 +4378,11 @@ static void drm_add_display_info(struct drm_connector *connector, connector->name, info->bpc); } + /* Extract audio and video latency fields for the sink */ + drm_hdmi_extract_vsdbs_info(connector, edid); + /* Extract info from extended tag blocks */ + drm_hdmi_extract_extended_blk_info(connector, edid); + /* Only defined for 1.4 with digital displays */ if (edid->revision < 4) return; @@ -4091,6 +4597,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) num_modes += add_cea_modes(connector, edid); num_modes += add_alternate_cea_modes(connector, edid); num_modes += add_displayid_detailed_modes(connector, edid); + num_modes += add_YCbCr420VDB_modes(connector, edid); if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) num_modes += add_inferred_modes(connector, edid); @@ -4105,6 +4612,9 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (quirks & EDID_QUIRK_FORCE_8BPC) connector->display_info.bpc = 8; + if (quirks & EDID_QUIRK_FORCE_10BPC) + connector->display_info.bpc = 10; + if (quirks & EDID_QUIRK_FORCE_12BPC) connector->display_info.bpc = 12; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 1fd6eac1400c1c92bae8edaac6a622a322d7ace0..52629b62b00291adcbab69763bcbca2e159dda92 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -18,13 +18,16 @@ */ #include +#include #include #include #include #include #include +#include #include #include +#include #define DEFAULT_FBDEFIO_DELAY_MS 50 @@ -265,6 +268,38 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); +/** + * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer + * @plane: Which plane + * @state: Plane state attach fence to + * + * This should be put into prepare_fb hook of struct &drm_plane_helper_funcs . + * + * This function checks if the plane FB has an dma-buf attached, extracts + * the exclusive fence and attaches it to plane state for the atomic helper + * to wait on. + * + * There is no need for cleanup_fb for CMA based framebuffer drivers. + */ +int drm_fb_cma_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct dma_buf *dma_buf; + struct fence *fence; + + if ((plane->state->fb == state->fb) || !state->fb) + return 0; + + dma_buf = drm_fb_cma_get_gem_obj(state->fb, 0)->base.dma_buf; + if (dma_buf) { + fence = reservation_object_get_excl_rcu(dma_buf->resv); + drm_atomic_set_fence_for_plane(state, fence); + } + + return 0; +} +EXPORT_SYMBOL_GPL(drm_fb_cma_prepare_fb); + #ifdef CONFIG_DEBUG_FS static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m) { diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index f5815e1a4390aef326a36dc4b8b0d8576fe04526..ca227e820a3069baf508be8268907300f3f0c49f 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -45,6 +45,8 @@ /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); +#define MAX_DRM_OPEN_COUNT 20 + /** * DOC: file operations * @@ -135,6 +137,11 @@ int drm_open(struct inode *inode, struct file *filp) if (!dev->open_count++) need_setup = 1; + if (dev->open_count >= MAX_DRM_OPEN_COUNT) { + retcode = -EPERM; + goto err_undo; + } + /* share address_space across all char-devs of a single device */ filp->f_mapping = dev->anon_inode->i_mapping; @@ -663,6 +670,10 @@ void drm_event_cancel_free(struct drm_device *dev, list_del(&p->pending_link); } spin_unlock_irqrestore(&dev->event_lock, flags); + + if (p->fence) + fence_put(p->fence); + kfree(p); } EXPORT_SYMBOL(drm_event_cancel_free); diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 465bacd0a630455e72c3127e12a000cad80ca4db..48e99ab525c363dbbf78f55b540d49d17bbd3769 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -255,13 +255,13 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) struct drm_gem_object *obj = ptr; struct drm_device *dev = obj->dev; + if (dev->driver->gem_close_object) + dev->driver->gem_close_object(obj, file_priv); + if (drm_core_check_feature(dev, DRIVER_PRIME)) drm_gem_remove_prime_handles(obj, file_priv); drm_vma_node_revoke(&obj->vma_node, file_priv); - if (dev->driver->gem_close_object) - dev->driver->gem_close_object(obj, file_priv); - drm_gem_object_handle_unreference_unlocked(obj); return 0; diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 76a1e4324cc6de676a3a580903b3271246a6f75b..d9a5762ad633f982d16c70b3c16aeccc5fd502ca 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -360,6 +360,7 @@ static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, if (dsi->mode_flags & MIPI_DSI_MODE_LPM) msg->flags |= MIPI_DSI_MSG_USE_LPM; + msg->flags |= MIPI_DSI_MSG_LASTCOMMAND; return ops->transfer(dsi->host, msg); } diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index ee07bb4a57b74eb093ecf2f819f61b628a4a8118..11f54df0c19bdc156d38f882e99f146459a9d3a5 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -348,14 +348,12 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, BUG_ON(!hole_node->hole_follows || node->allocated); - if (adj_start < start) - adj_start = start; - if (adj_end > end) - adj_end = end; - if (mm->color_adjust) mm->color_adjust(hole_node, color, &adj_start, &adj_end); + adj_start = max(adj_start, start); + adj_end = min(adj_end, end); + if (flags & DRM_MM_CREATE_TOP) adj_start = adj_end - size; @@ -566,17 +564,15 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ flags & DRM_MM_SEARCH_BELOW) { u64 hole_size = adj_end - adj_start; - if (adj_start < start) - adj_start = start; - if (adj_end > end) - adj_end = end; - if (mm->color_adjust) { mm->color_adjust(entry, color, &adj_start, &adj_end); if (adj_end <= adj_start) continue; } + adj_start = max(adj_start, start); + adj_end = min(adj_end, end); + if (!check_free_hole(adj_start, adj_end, size, alignment)) continue; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 249c0ae52c6d18be7cf8f14c34703f4601843b50..3957ef8f026b3189fa642ab4b304824ce6288494 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -137,6 +137,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&plane->base, config->prop_fb_id, 0); + drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1); drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index a4d81cf4ffa00f2ecef689f3815ea327b3396dac..174057ba82ca3d1e97b34063b80c9e34559259a0 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -26,6 +26,9 @@ #include "drm_crtc_internal.h" +#define MAX_BLOB_PROP_SIZE (PAGE_SIZE * 30) +#define MAX_BLOB_PROP_COUNT 250 + /** * DOC: overview * @@ -530,7 +533,7 @@ static void drm_property_free_blob(struct kref *kref) drm_mode_object_unregister(blob->dev, &blob->base); - kfree(blob); + vfree(blob); } /** @@ -554,10 +557,11 @@ drm_property_create_blob(struct drm_device *dev, size_t length, struct drm_property_blob *blob; int ret; - if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) + if (!length || length > MAX_BLOB_PROP_SIZE - + sizeof(struct drm_property_blob)) return ERR_PTR(-EINVAL); - blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); + blob = vzalloc(sizeof(struct drm_property_blob)+length); if (!blob) return ERR_PTR(-ENOMEM); @@ -573,7 +577,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length, ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, true, drm_property_free_blob); if (ret) { - kfree(blob); + vfree(blob); return ERR_PTR(-EINVAL); } @@ -756,13 +760,20 @@ int drm_mode_createblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_create_blob *out_resp = data; - struct drm_property_blob *blob; + struct drm_property_blob *blob, *bt; void __user *blob_ptr; int ret = 0; + u32 count = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; + list_for_each_entry(bt, &file_priv->blobs, head_file) + count++; + + if (count == MAX_BLOB_PROP_COUNT) + return -EINVAL; + blob = drm_property_create_blob(dev, out_resp->length, NULL); if (IS_ERR(blob)) return PTR_ERR(blob); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 0370b842d9cc20c2fdae37406c82a9546106e69b..82dd57d4843c45fef28906d7682879810c223d53 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -549,12 +549,15 @@ static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = { void etnaviv_gem_free_object(struct drm_gem_object *obj) { struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); + struct etnaviv_drm_private *priv = obj->dev->dev_private; struct etnaviv_vram_mapping *mapping, *tmp; /* object should not be active */ WARN_ON(is_active(etnaviv_obj)); + mutex_lock(&priv->gem_lock); list_del(&etnaviv_obj->gem_node); + mutex_unlock(&priv->gem_lock); list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list, obj_node) { diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index afdd55ddf821c55c70f2bdb893abaa508d1497b0..1ac9a95e1d78c22930427a9c574ec913592f00c6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -264,8 +264,8 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, if (ret) return ret; - if (r->reloc_offset >= bo->obj->base.size - sizeof(*ptr)) { - DRM_ERROR("relocation %u outside object", i); + if (r->reloc_offset > bo->obj->base.size - sizeof(*ptr)) { + DRM_ERROR("relocation %u outside object\n", i); return -EINVAL; } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index 169ac96e8f0861f9648e0e3ca3292ca1da61556c..fe0e85b41310a8fa24ba0f6caaa598edc669a99c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -116,9 +116,14 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, struct list_head list; bool found; + /* + * XXX: The DRM_MM_SEARCH_BELOW is really a hack to trick + * drm_mm into giving out a low IOVA after address space + * rollover. This needs a proper fix. + */ ret = drm_mm_insert_node_in_range(&mmu->mm, node, size, 0, mmu->last_iova, ~0UL, - DRM_MM_SEARCH_DEFAULT); + mmu->last_iova ? DRM_MM_SEARCH_DEFAULT : DRM_MM_SEARCH_BELOW); if (ret != -ENOSPC) break; diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 6ca1f3117fe8d524fbb4dfed89692c527c5bd41c..6dd09c306bc1a8d76e33910a63b798df2fa6803b 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -46,7 +46,8 @@ enum decon_flag_bits { BIT_CLKS_ENABLED, BIT_IRQS_ENABLED, BIT_WIN_UPDATED, - BIT_SUSPENDED + BIT_SUSPENDED, + BIT_REQUEST_UPDATE }; struct decon_context { @@ -315,6 +316,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, /* window enable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); + set_bit(BIT_REQUEST_UPDATE, &ctx->flags); } static void decon_disable_plane(struct exynos_drm_crtc *crtc, @@ -327,6 +329,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, return; decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); + set_bit(BIT_REQUEST_UPDATE, &ctx->flags); } static void decon_atomic_flush(struct exynos_drm_crtc *crtc) @@ -340,8 +343,8 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc) for (i = ctx->first_win; i < WINDOWS_NR; i++) decon_shadow_protect_win(ctx, i, false); - /* standalone update */ - decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); + if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags)) + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); if (ctx->out_type & IFTYPE_I80) set_bit(BIT_WIN_UPDATED, &ctx->flags); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index fbd13fabdf2daf93aeb79cb976c47e467fae6971..603d8425cca6cf015b1eca170f5d9d5540021535 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1193,6 +1193,17 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, if (!node) return -ENOMEM; + /* + * To avoid an integer overflow for the later size computations, we + * enforce a maximum number of submitted commands here. This limit is + * sufficient for all conceivable usage cases of the G2D. + */ + if (req->cmd_nr > G2D_CMDLIST_DATA_NUM || + req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) { + dev_err(dev, "number of submitted G2D commands exceeds limit\n"); + return -EINVAL; + } + node->event = NULL; if (req->event_type != G2D_EVENT_NOT) { @@ -1250,7 +1261,11 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF; } - /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ + /* + * Check the size of cmdlist. The 2 that is added last comes from + * the implicit G2D_BITBLT_START that is appended once we have + * checked all the submitted commands. + */ size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2; if (size > G2D_CMDLIST_DATA_NUM) { dev_err(dev, "cmdlist size is too big\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index f2ae72ba7d5ac87e9d3d399fca5453b2799215e0..2abc47b554ab8456f866be5ef5de3d11f85577bc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -246,6 +246,15 @@ struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev, if (IS_ERR(exynos_gem)) return exynos_gem; + if (!is_drm_iommu_supported(dev) && (flags & EXYNOS_BO_NONCONTIG)) { + /* + * when no IOMMU is available, all allocated buffers are + * contiguous anyway, so drop EXYNOS_BO_NONCONTIG flag + */ + flags &= ~EXYNOS_BO_NONCONTIG; + DRM_WARN("Non-contiguous allocation is not supported without IOMMU, falling back to contiguous buffer\n"); + } + /* set memory type and cache attribute from user side. */ exynos_gem->flags = flags; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index cc2fde2ae5eff272c8f5e15548b61b525a54c6cc..c9eef0f51d31a2126e4f7238e0c86f077ffdebbb 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -243,7 +243,6 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev) return PTR_ERR(fsl_dev->state); } - clk_disable_unprepare(fsl_dev->pix_clk); clk_disable_unprepare(fsl_dev->clk); return 0; @@ -266,6 +265,7 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) if (fsl_dev->tcon) fsl_tcon_bypass_enable(fsl_dev->tcon); fsl_dcu_drm_init_planes(fsl_dev->drm); + enable_irq(fsl_dev->irq); drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state); console_lock(); @@ -273,7 +273,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) console_unlock(); drm_kms_helper_poll_enable(fsl_dev->drm); - enable_irq(fsl_dev->irq); return 0; } diff --git a/drivers/gpu/drm/fsl-dcu/fsl_tcon.c b/drivers/gpu/drm/fsl-dcu/fsl_tcon.c index 3194e544ee27b902c4a300d2972781a832d54997..faacc813254c0e3863756cd084fef6c8fb5e3784 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_tcon.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_tcon.c @@ -89,9 +89,13 @@ struct fsl_tcon *fsl_tcon_init(struct device *dev) goto err_node_put; } - of_node_put(np); - clk_prepare_enable(tcon->ipg_clk); + ret = clk_prepare_enable(tcon->ipg_clk); + if (ret) { + dev_err(dev, "Couldn't enable the TCON clock\n"); + goto err_node_put; + } + of_node_put(np); dev_info(dev, "Using TCON in bypass mode\n"); return tcon; diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index fd7c912548415f7b8b8996520e90422da5e03d74..79e9d3690667e94d1b74ef938c80401af992e6ae 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -774,20 +774,23 @@ void psb_intel_lvds_init(struct drm_device *dev, if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, scan); + DRM_DEBUG_KMS("Using mode from DDC\n"); goto out; /* FIXME: check for quirks */ } } /* Failed to get EDID, what about VBT? do we need this? */ - if (mode_dev->vbt_mode) + if (dev_priv->lfp_lvds_vbt_mode) { mode_dev->panel_fixed_mode = - drm_mode_duplicate(dev, mode_dev->vbt_mode); + drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (!mode_dev->panel_fixed_mode) - if (dev_priv->lfp_lvds_vbt_mode) - mode_dev->panel_fixed_mode = - drm_mode_duplicate(dev, - dev_priv->lfp_lvds_vbt_mode); + if (mode_dev->panel_fixed_mode) { + mode_dev->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; + DRM_DEBUG_KMS("Using mode from VBT\n"); + goto out; + } + } /* * If we didn't get EDID, try checking if the panel is already turned @@ -804,6 +807,7 @@ void psb_intel_lvds_init(struct drm_device *dev, if (mode_dev->panel_fixed_mode) { mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + DRM_DEBUG_KMS("Using pre-programmed mode\n"); goto out; /* FIXME: check for quirks */ } } diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 7e7a4d43d6b698f2326e0e8d2765b0c27bb80164..0f563c95452069a27529e9249037b00e913c9ce0 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -521,9 +521,12 @@ static void ade_crtc_atomic_begin(struct drm_crtc *crtc, { struct ade_crtc *acrtc = to_ade_crtc(crtc); struct ade_hw_ctx *ctx = acrtc->ctx; + struct drm_display_mode *mode = &crtc->state->mode; + struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; if (!ctx->power_on) (void)ade_power_up(ctx); + ade_ldi_set_mode(acrtc, mode, adj_mode); } static void ade_crtc_atomic_flush(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 923150de46cb910959612eeb4f947686648707ea..7513e7678263c182bc85293acf71421632aadcde 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -573,9 +573,7 @@ static int i915_load_modeset_init(struct drm_device *dev) if (i915_inject_load_failure()) return -ENODEV; - ret = intel_bios_init(dev_priv); - if (ret) - DRM_INFO("failed to find VBIOS tables\n"); + intel_bios_init(dev_priv); /* If we have > 1 VGA cards, then we need to arbitrate access * to the common VGA resources. @@ -1201,6 +1199,15 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_free_priv; pci_set_drvdata(pdev, &dev_priv->drm); + /* + * Disable the system suspend direct complete optimization, which can + * leave the device suspended skipping the driver's suspend handlers + * if the device was already runtime suspended. This is needed due to + * the difference in our runtime and system suspend sequence and + * becaue the HDA driver may require us to enable the audio power + * domain during system suspend. + */ + pdev->dev_flags |= PCI_DEV_FLAGS_NEEDS_RESUME; ret = i915_driver_init_early(dev_priv, ent); if (ret < 0) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e0d72457b23c1e30b3ffbf87a090a506dd25a5a7..36a665f0e5c9fac5dda5c519a82bb192cdf62df5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3584,7 +3584,7 @@ static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) extern void intel_i2c_reset(struct drm_device *dev); /* intel_bios.c */ -int intel_bios_init(struct drm_i915_private *dev_priv); +void intel_bios_init(struct drm_i915_private *dev_priv); bool intel_bios_is_valid_vbt(const void *buf, size_t size); bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f46aac1e85fb49f53db1821fb61abb18a48732ef..c75f4bb6a4bd46bf3cd9ad0f523ec89628d47ab0 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -420,6 +420,11 @@ int i915_gem_init_stolen(struct drm_device *dev) return 0; } + if (intel_vgpu_active(dev_priv)) { + DRM_INFO("iGVT-g active, disabling use of stolen memory\n"); + return 0; + } + #ifdef CONFIG_INTEL_IOMMU if (intel_iommu_gfx_mapped && INTEL_INFO(dev)->gen < 8) { DRM_INFO("DMAR active, disabling use of stolen memory\n"); diff --git a/drivers/gpu/drm/i915/i915_pvinfo.h b/drivers/gpu/drm/i915/i915_pvinfo.h index c0cb2974caacdb0357b8fcde1a585da51ead7b43..2cfe96d3e5d13e0dd1f6cc689a9af78608007617 100644 --- a/drivers/gpu/drm/i915/i915_pvinfo.h +++ b/drivers/gpu/drm/i915/i915_pvinfo.h @@ -36,10 +36,6 @@ #define VGT_VERSION_MAJOR 1 #define VGT_VERSION_MINOR 0 -#define INTEL_VGT_IF_VERSION_ENCODE(major, minor) ((major) << 16 | (minor)) -#define INTEL_VGT_IF_VERSION \ - INTEL_VGT_IF_VERSION_ENCODE(VGT_VERSION_MAJOR, VGT_VERSION_MINOR) - /* * notifications from guest to vgpu device model */ @@ -55,8 +51,8 @@ enum vgt_g2v_type { struct vgt_if { u64 magic; /* VGT_MAGIC */ - uint16_t version_major; - uint16_t version_minor; + u16 version_major; + u16 version_minor; u32 vgt_id; /* ID of vGT instance */ u32 rsv1[12]; /* pad to offset 0x40 */ /* diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c index dae340cfc6c76f617795e248b74550fcc54bb0ae..125adcc6d6cab51f658ffcc2861dc48d4322bb82 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.c +++ b/drivers/gpu/drm/i915/i915_vgpu.c @@ -60,8 +60,8 @@ */ void i915_check_vgpu(struct drm_i915_private *dev_priv) { - uint64_t magic; - uint32_t version; + u64 magic; + u16 version_major; BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE); @@ -69,10 +69,8 @@ void i915_check_vgpu(struct drm_i915_private *dev_priv) if (magic != VGT_MAGIC) return; - version = INTEL_VGT_IF_VERSION_ENCODE( - __raw_i915_read16(dev_priv, vgtif_reg(version_major)), - __raw_i915_read16(dev_priv, vgtif_reg(version_minor))); - if (version != INTEL_VGT_IF_VERSION) { + version_major = __raw_i915_read16(dev_priv, vgtif_reg(version_major)); + if (version_major < VGT_VERSION_MAJOR) { DRM_INFO("VGT interface version mismatch!\n"); return; } diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index cf2560708e031d5957442e60783377ebe4106e11..80c5cc5640c141fab75802e336748dc9a75f0cff 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1152,6 +1152,13 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); + if (port == PORT_A && is_dvi) { + DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n", + is_hdmi ? "/HDMI" : ""); + is_dvi = false; + is_hdmi = false; + } + info->supports_dvi = is_dvi; info->supports_hdmi = is_hdmi; info->supports_dp = is_dp; @@ -1212,7 +1219,7 @@ static void parse_ddi_ports(struct drm_i915_private *dev_priv, { enum port port; - if (!HAS_DDI(dev_priv)) + if (!HAS_DDI(dev_priv) && !IS_CHERRYVIEW(dev_priv)) return; if (!dev_priv->vbt.child_dev_num) @@ -1332,6 +1339,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, return; } +/* Common defaults which may be overridden by VBT. */ static void init_vbt_defaults(struct drm_i915_private *dev_priv) { @@ -1368,6 +1376,18 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) &dev_priv->vbt.ddi_port_info[port]; info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN; + } +} + +/* Defaults to initialize only if there is no VBT. */ +static void +init_vbt_missing_defaults(struct drm_i915_private *dev_priv) +{ + enum port port; + + for (port = PORT_A; port < I915_MAX_PORTS; port++) { + struct ddi_vbt_port_info *info = + &dev_priv->vbt.ddi_port_info[port]; info->supports_dvi = (port != PORT_A && port != PORT_E); info->supports_hdmi = info->supports_dvi; @@ -1450,36 +1470,35 @@ static const struct vbt_header *find_vbt(void __iomem *bios, size_t size) * intel_bios_init - find VBT and initialize settings from the BIOS * @dev_priv: i915 device instance * - * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers - * to appropriate values. - * - * Returns 0 on success, nonzero on failure. + * Parse and initialize settings from the Video BIOS Tables (VBT). If the VBT + * was not found in ACPI OpRegion, try to find it in PCI ROM first. Also + * initialize some defaults if the VBT is not present at all. */ -int -intel_bios_init(struct drm_i915_private *dev_priv) +void intel_bios_init(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = dev_priv->drm.pdev; const struct vbt_header *vbt = dev_priv->opregion.vbt; const struct bdb_header *bdb; u8 __iomem *bios = NULL; - if (HAS_PCH_NOP(dev_priv)) - return -ENODEV; + if (HAS_PCH_NOP(dev_priv)) { + DRM_DEBUG_KMS("Skipping VBT init due to disabled display.\n"); + return; + } init_vbt_defaults(dev_priv); + /* If the OpRegion does not have VBT, look in PCI ROM. */ if (!vbt) { size_t size; bios = pci_map_rom(pdev, &size); if (!bios) - return -1; + goto out; vbt = find_vbt(bios, size); - if (!vbt) { - pci_unmap_rom(pdev, bios); - return -1; - } + if (!vbt) + goto out; DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n"); } @@ -1504,10 +1523,14 @@ intel_bios_init(struct drm_i915_private *dev_priv) parse_mipi_sequence(dev_priv, bdb); parse_ddi_ports(dev_priv, bdb); +out: + if (!vbt) { + DRM_INFO("Failed to find VBIOS tables (VBT)\n"); + init_vbt_missing_defaults(dev_priv); + } + if (bios) pci_unmap_rom(pdev, bios); - - return 0; } /** diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c index 95a72771eea61a2d49d1ab403a92392810bb6b18..89a77743ab2946578128d9bfece9c2e8a7089329 100644 --- a/drivers/gpu/drm/i915/intel_color.c +++ b/drivers/gpu/drm/i915/intel_color.c @@ -394,6 +394,7 @@ static void broadwell_load_luts(struct drm_crtc_state *state) } /* Program the max register to clamp values > 1.0. */ + i = lut_size - 1; I915_WRITE(PREC_PAL_GC_MAX(pipe, 0), drm_color_lut_extract(lut[i].red, 16)); I915_WRITE(PREC_PAL_GC_MAX(pipe, 1), diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5dc6082639db34254cd91ec2d8479edf2aac375a..ce32303b3013a5a7632a22ed73d8155b3661a5c0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2253,6 +2253,9 @@ void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation) intel_fill_fb_ggtt_view(&view, fb, rotation); vma = i915_gem_object_to_ggtt(obj, &view); + if (WARN_ON_ONCE(!vma)) + return; + i915_vma_unpin_fence(vma); i915_gem_object_unpin_from_display_plane(vma); } @@ -11468,13 +11471,10 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, { struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; + enum transcoder cpu_transcoder; struct drm_display_mode *mode; struct intel_crtc_state *pipe_config; - int htot = I915_READ(HTOTAL(cpu_transcoder)); - int hsync = I915_READ(HSYNC(cpu_transcoder)); - int vtot = I915_READ(VTOTAL(cpu_transcoder)); - int vsync = I915_READ(VSYNC(cpu_transcoder)); + u32 htot, hsync, vtot, vsync; enum pipe pipe = intel_crtc->pipe; mode = kzalloc(sizeof(*mode), GFP_KERNEL); @@ -11502,6 +11502,13 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, i9xx_crtc_clock_get(intel_crtc, pipe_config); mode->clock = pipe_config->port_clock / pipe_config->pixel_multiplier; + + cpu_transcoder = pipe_config->cpu_transcoder; + htot = I915_READ(HTOTAL(cpu_transcoder)); + hsync = I915_READ(HSYNC(cpu_transcoder)); + vtot = I915_READ(VTOTAL(cpu_transcoder)); + vsync = I915_READ(VSYNC(cpu_transcoder)); + mode->hdisplay = (htot & 0xffff) + 1; mode->htotal = ((htot & 0xffff0000) >> 16) + 1; mode->hsync_start = (hsync & 0xffff) + 1; @@ -13764,6 +13771,15 @@ static void update_scanline_offset(struct intel_crtc *crtc) * type. For DP ports it behaves like most other platforms, but on HDMI * there's an extra 1 line difference. So we need to add two instead of * one to the value. + * + * On VLV/CHV DSI the scanline counter would appear to increment + * approx. 1/3 of a scanline before start of vblank. Unfortunately + * that means we can't tell whether we're in vblank or not while + * we're on that particular line. We must still set scanline_offset + * to 1 so that the vblank timestamps come out correct when we query + * the scanline counter from within the vblank interrupt handler. + * However if queried just before the start of vblank we'll get an + * answer that's slightly in the future. */ if (IS_GEN2(dev)) { const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7b06280b23aa3d69628ae86dbcc0d2c0d506df14..7fdc42e5aac82dfa1080e04f7d7420ff90b39ec3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2193,8 +2193,8 @@ static void edp_panel_off(struct intel_dp *intel_dp) I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - intel_dp->panel_power_off_time = ktime_get_boottime(); wait_panel_off(intel_dp); + intel_dp->panel_power_off_time = ktime_get_boottime(); /* We got a reference when we enabled the VDD. */ power_domain = intel_display_port_aux_power_domain(intel_encoder); @@ -3558,9 +3558,16 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) dev_priv->psr.psr2_support ? "supported" : "not supported"); } - /* Read the eDP Display control capabilities registers */ - if ((intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) && - drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV, + /* + * Read the eDP display control registers. + * + * Do this independent of DP_DPCD_DISPLAY_CONTROL_CAPABLE bit in + * DP_EDP_CONFIGURATION_CAP, because some buggy displays do not have it + * set, but require eDP 1.4+ detection (e.g. for supported link rates + * method). The display control registers should read zero if they're + * not supported anyway. + */ + if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV, intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) == sizeof(intel_dp->edp_dpcd)) DRM_DEBUG_KMS("EDP DPCD : %*ph\n", (int) sizeof(intel_dp->edp_dpcd), diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 79aab9ad6faa826416abd8004f35ce78d9f62c2c..6769aa1b6922407123663e8f88666aee9c4daeda 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -430,7 +430,9 @@ static bool gmbus_is_index_read(struct i2c_msg *msgs, int i, int num) { return (i + 1 < num && - !(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 && + msgs[i].addr == msgs[i + 1].addr && + !(msgs[i].flags & I2C_M_RD) && + (msgs[i].len == 1 || msgs[i].len == 2) && (msgs[i + 1].flags & I2C_M_RD)); } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index a2655cd5a84e2c4599a5527cd9f8f42eec77e0f5..8ab6f30dc23c362d8653215530d1ec0e00c16418 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -272,8 +272,30 @@ static int intel_overlay_on(struct intel_overlay *overlay) return intel_overlay_do_wait_request(overlay, req, NULL); } +static void intel_overlay_flip_prepare(struct intel_overlay *overlay, + struct i915_vma *vma) +{ + enum pipe pipe = overlay->crtc->pipe; + + WARN_ON(overlay->old_vma); + + i915_gem_track_fb(overlay->vma ? overlay->vma->obj : NULL, + vma ? vma->obj : NULL, + INTEL_FRONTBUFFER_OVERLAY(pipe)); + + intel_frontbuffer_flip_prepare(overlay->i915, + INTEL_FRONTBUFFER_OVERLAY(pipe)); + + overlay->old_vma = overlay->vma; + if (vma) + overlay->vma = i915_vma_get(vma); + else + overlay->vma = NULL; +} + /* overlay needs to be enabled in OCMD reg */ static int intel_overlay_continue(struct intel_overlay *overlay, + struct i915_vma *vma, bool load_polyphase_filter) { struct drm_i915_private *dev_priv = overlay->i915; @@ -308,43 +330,44 @@ static int intel_overlay_continue(struct intel_overlay *overlay, intel_ring_emit(ring, flip_addr); intel_ring_advance(ring); + intel_overlay_flip_prepare(overlay, vma); + intel_overlay_submit_request(overlay, req, NULL); return 0; } -static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active, - struct drm_i915_gem_request *req) +static void intel_overlay_release_old_vma(struct intel_overlay *overlay) { - struct intel_overlay *overlay = - container_of(active, typeof(*overlay), last_flip); struct i915_vma *vma; vma = fetch_and_zero(&overlay->old_vma); if (WARN_ON(!vma)) return; - i915_gem_track_fb(vma->obj, NULL, - INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe)); + intel_frontbuffer_flip_complete(overlay->i915, + INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe)); i915_gem_object_unpin_from_display_plane(vma); i915_vma_put(vma); } +static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active, + struct drm_i915_gem_request *req) +{ + struct intel_overlay *overlay = + container_of(active, typeof(*overlay), last_flip); + + intel_overlay_release_old_vma(overlay); +} + static void intel_overlay_off_tail(struct i915_gem_active *active, struct drm_i915_gem_request *req) { struct intel_overlay *overlay = container_of(active, typeof(*overlay), last_flip); - struct i915_vma *vma; - - /* never have the overlay hw on without showing a frame */ - vma = fetch_and_zero(&overlay->vma); - if (WARN_ON(!vma)) - return; - i915_gem_object_unpin_from_display_plane(vma); - i915_vma_put(vma); + intel_overlay_release_old_vma(overlay); overlay->crtc->overlay = NULL; overlay->crtc = NULL; @@ -398,6 +421,8 @@ static int intel_overlay_off(struct intel_overlay *overlay) } intel_ring_advance(ring); + intel_overlay_flip_prepare(overlay, NULL); + return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail); } @@ -836,18 +861,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, intel_overlay_unmap_regs(overlay, regs); - ret = intel_overlay_continue(overlay, scale_changed); + ret = intel_overlay_continue(overlay, vma, scale_changed); if (ret) goto out_unpin; - i915_gem_track_fb(overlay->vma ? overlay->vma->obj : NULL, - vma->obj, INTEL_FRONTBUFFER_OVERLAY(pipe)); - - overlay->old_vma = overlay->vma; - overlay->vma = vma; - - intel_frontbuffer_flip(dev_priv, INTEL_FRONTBUFFER_OVERLAY(pipe)); - return 0; out_unpin: @@ -1215,6 +1232,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, mutex_unlock(&dev->struct_mutex); drm_modeset_unlock_all(dev); + i915_gem_object_put(new_bo); kfree(params); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2c6d59d4b6d32c6984296ec02f664719f3eb9383..49de4760cc165a5e27ff5b999bc4b4c8199a5b56 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4114,10 +4114,18 @@ skl_compute_wm(struct drm_atomic_state *state) struct drm_crtc_state *cstate; struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct skl_wm_values *results = &intel_state->wm_results; + struct drm_device *dev = state->dev; struct skl_pipe_wm *pipe_wm; bool changed = false; int ret, i; + /* + * When we distrust bios wm we always need to recompute to set the + * expected DDB allocations for each CRTC. + */ + if (to_i915(dev)->wm.distrust_bios_wm) + changed = true; + /* * If this transaction isn't actually touching any CRTC's, don't * bother with watermark calculation. Note that if we pass this @@ -4128,6 +4136,7 @@ skl_compute_wm(struct drm_atomic_state *state) */ for_each_crtc_in_state(state, crtc, cstate, i) changed = true; + if (!changed) return 0; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 9b307cee3008680aca877ee6bcd2ca8b5285d886..dff478498f05e40a1cfb5f3638dd8351c0411c24 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -387,6 +387,13 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) return false; } + /* PSR2 is restricted to work with panel resolutions upto 3200x2000 */ + if (intel_crtc->config->pipe_src_w > 3200 || + intel_crtc->config->pipe_src_h > 2000) { + dev_priv->psr.psr2_support = false; + return false; + } + dev_priv->psr.source_ok = true; return true; } @@ -425,7 +432,6 @@ void intel_psr_enable(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc); if (!HAS_PSR(dev)) { DRM_DEBUG_KMS("PSR not supported on this platform\n"); @@ -452,12 +458,7 @@ void intel_psr_enable(struct intel_dp *intel_dp) hsw_psr_setup_vsc(intel_dp); if (dev_priv->psr.psr2_support) { - /* PSR2 is restricted to work with panel resolutions upto 3200x2000 */ - if (crtc->config->pipe_src_w > 3200 || - crtc->config->pipe_src_h > 2000) - dev_priv->psr.psr2_support = false; - else - skl_psr_setup_su_vsc(intel_dp); + skl_psr_setup_su_vsc(intel_dp); } /* diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index dbed12c484c9d5d5f3af0529caa4746737f4b007..64f4e2e185944951a085bb19f1d5a36d07da7322 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -81,10 +81,13 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, */ void intel_pipe_update_start(struct intel_crtc *crtc) { + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; long timeout = msecs_to_jiffies_timeout(1); int scanline, min, max, vblank_start; wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); + bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && + intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI); DEFINE_WAIT(wait); vblank_start = adjusted_mode->crtc_vblank_start; @@ -136,6 +139,24 @@ void intel_pipe_update_start(struct intel_crtc *crtc) drm_crtc_vblank_put(&crtc->base); + /* + * On VLV/CHV DSI the scanline counter would appear to + * increment approx. 1/3 of a scanline before start of vblank. + * The registers still get latched at start of vblank however. + * This means we must not write any registers on the first + * line of vblank (since not the whole line is actually in + * vblank). And unfortunately we can't use the interrupt to + * wait here since it will fire too soon. We could use the + * frame start interrupt instead since it will fire after the + * critical scanline, but that would require more changes + * in the interrupt code. So for now we'll just do the nasty + * thing and poll for the bad scanline to pass us by. + * + * FIXME figure out if BXT+ DSI suffers from this as well + */ + while (need_vlv_dsi_wa && scanline == vblank_start) + scanline = intel_get_crtc_scanline(crtc); + crtc->debug.scanline_start = scanline; crtc->debug.start_vbl_time = ktime_get(); crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index cf83f6507ec8211566f87cbf4878e5d76c3eff0b..48dfc163233ec516a93118b80541759db92f7062 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -321,7 +321,8 @@ static void mtk_drm_unbind(struct device *dev) { struct mtk_drm_private *private = dev_get_drvdata(dev); - drm_put_dev(private->drm); + drm_dev_unregister(private->drm); + drm_dev_unref(private->drm); private->drm = NULL; } diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 0e8c4d9af34069f55e8784d8e43b6e4e56251cfa..e097780752f6fe0995835728cdc107f2ed500acc 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1061,7 +1061,7 @@ static int mtk_hdmi_setup_vendor_specific_infoframe(struct mtk_hdmi *hdmi, } err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err) { + if (err < 0) { dev_err(hdmi->dev, "Failed to pack vendor infoframe: %zd\n", err); return err; diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index e79cbc25ae3c54048b21c6293ea340b91b0750fc..fb03e3057485d426dd1feae5cb4b7ff01d471aac 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -145,6 +145,8 @@ static int mga_vram_init(struct mga_device *mdev) } mem = pci_iomap(mdev->dev->pdev, 0, 0); + if (!mem) + return -ENOMEM; mdev->mc.vram_size = mga_probe_vram(mdev, mem); diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 70b47caa1b398261c7b5bfe41e25abc4ecbadbb9..ba71ce8466a6f7199b90dd443a8e58ef9eeb0152 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -3,7 +3,7 @@ config DRM_MSM tristate "MSM DRM" depends on DRM depends on ARCH_QCOM || (ARM && COMPILE_TEST) - depends on OF && COMMON_CLK + depends on OF select REGULATOR select DRM_KMS_HELPER select DRM_PANEL @@ -12,6 +12,8 @@ config DRM_MSM select QCOM_SCM select SND_SOC_HDMI_CODEC if SND_SOC select SYNC_FILE + select HDCP_QSEECOM + select MSM_EXT_DISPLAY default y help DRM/KMS driver for MSM/snapdragon. @@ -28,16 +30,29 @@ config DRM_MSM_REGISTER_LOGGING config DRM_MSM_HDMI_HDCP bool "Enable HDMI HDCP support in MSM DRM driver" depends on DRM_MSM && QCOM_SCM - default y + default n + help + Compile in support for logging register reads/writes in a format + that can be parsed by envytools demsm tool. If enabled, register + logging can be switched on via msm.reglog=y module param. + +config DRM_MSM_HDMI + bool "Enable HDMI support in MSM DRM driver" + depends on DRM_MSM + depends on COMMON_CLK + default n help - Choose this option to enable HDCP state machine + Compile in support for HDMI driver in msm drm + driver. HDMI external display support is enabled + through this config option. It can be primary or + secondary display on device. config DRM_MSM_DSI bool "Enable DSI support in MSM DRM driver" depends on DRM_MSM select DRM_PANEL select DRM_MIPI_DSI - default y + default n help Choose this option if you have a need for MIPI DSI connector support. @@ -83,6 +98,17 @@ config DRM_MSM_DSI_28NM_8960_PHY help Choose this option if the 28nm DSI PHY 8960 variant is used on the platform. + +config DRM_MSM_MDP5 + tristate "MSM MDP5 DRM driver" + depends on DRM_MSM + default n + help + Choose this option if MSM MDP5 revision support is + needed in DRM/KMS. This is not required if sde/mdp4 + only target enabled. MDP5 supports DSI and HDMI + displays. + config DRM_MSM_MDP4 tristate "MSM MDP4 DRM driver" depends on DRM_MSM diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 4112bef611ad27ef1e3fda96fea84820d9c39799..c81832ac9bd93f39311d282ef6727dd91990d046 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -1,11 +1,48 @@ -ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm -Idrivers/gpu/drm/msm/dsi-staging +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm -Idrivers/gpu/drm/msm/dsi-staging -Idrivers/gpu/drm/msm/dp ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi ccflags-y += -Idrivers/gpu/drm/msm/sde ccflags-y += -Idrivers/media/platform/msm/sde/rotator +ccflags-y += -Idrivers/gpu/drm/msm/hdmi msm_drm-y := \ - hdmi/hdmi.o \ + dp/dp_usbpd.o \ + dp/dp_parser.o \ + dp/dp_power.o \ + dp/dp_catalog.o \ + dp/dp_aux.o \ + dp/dp_panel.o \ + dp/dp_link.o \ + dp/dp_ctrl.o \ + dp/dp_audio.o \ + dp/dp_debug.o \ + dp/dp_display.o \ + dp/dp_drm.o \ + dp/dp_hdcp2p2.o \ + sde/sde_crtc.o \ + sde/sde_encoder.o \ + sde/sde_encoder_phys_vid.o \ + sde/sde_encoder_phys_cmd.o \ + sde/sde_irq.o \ + sde/sde_core_irq.o \ + sde/sde_core_perf.o \ + sde/sde_rm.o \ + sde/sde_kms_utils.o \ + sde/sde_kms.o \ + sde/sde_plane.o \ + sde/sde_connector.o \ + sde/sde_color_processing.o \ + sde/sde_vbif.o \ + sde_dbg.o \ + sde_dbg_evtlog.o \ + sde_io_util.o \ + sde/sde_hw_reg_dma_v1_color_proc.o \ + sde/sde_hw_color_proc_v4.o \ + sde/sde_hw_ad4.o \ + sde_edid_parser.o \ + sde_hdcp_1x.o + +msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi.o \ hdmi/hdmi_audio.o \ hdmi/hdmi_bridge.o \ hdmi/hdmi_connector.o \ @@ -14,13 +51,15 @@ msm_drm-y := \ hdmi/hdmi_phy_8960.o \ hdmi/hdmi_phy_8x60.o \ hdmi/hdmi_phy_8x74.o \ - edp/edp.o \ + +msm_drm-$(CONFIG_DRM_MSM_EDP) += edp/edp.o \ edp/edp_aux.o \ edp/edp_bridge.o \ edp/edp_connector.o \ edp/edp_ctrl.o \ edp/edp_phy.o \ - mdp/mdp_format.o \ + +msm_drm-$(CONFIG_DRM_MSM_MDP5) += mdp/mdp_format.o \ mdp/mdp_kms.o \ mdp/mdp5/mdp5_cfg.o \ mdp/mdp5/mdp5_ctl.o \ @@ -31,26 +70,6 @@ msm_drm-y := \ mdp/mdp5/mdp5_kms.o \ mdp/mdp5/mdp5_plane.o \ mdp/mdp5/mdp5_smp.o \ - sde/sde_crtc.o \ - sde/sde_encoder.o \ - sde/sde_encoder_phys_vid.o \ - sde/sde_encoder_phys_cmd.o \ - sde/sde_irq.o \ - sde/sde_core_irq.o \ - sde/sde_core_perf.o \ - sde/sde_rm.o \ - sde/sde_kms_utils.o \ - sde/sde_kms.o \ - sde/sde_plane.o \ - sde/sde_connector.o \ - sde/sde_color_processing.o \ - sde/sde_vbif.o \ - sde_dbg.o \ - sde_dbg_evtlog.o \ - sde_io_util.o \ - sde/sde_hw_reg_dma_v1_color_proc.o \ - sde/sde_hw_color_proc_v4.o \ - sde/sde_hw_ad4.o \ msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \ sde_rsc_hw.o \ @@ -74,9 +93,9 @@ msm_drm-$(CONFIG_DRM_MSM_MDP4) += mdp/mdp4/mdp4_crtc.o \ msm_drm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o msm_drm-$(CONFIG_SYNC_FILE) += sde/sde_fence.o -msm_drm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o -msm_drm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o -msm_drm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_phy_8996.o +msm_drm-$(CONFIG_DRM_MSM_MDP4) += mdp/mdp4/mdp4_lvds_pll.o +msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi_pll_8960.o +msm_drm-$(CONFIG_DRM_MSM_HDMI) += hdmi/hdmi_phy_8996.o msm_drm-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o @@ -142,7 +161,8 @@ msm_drm-$(CONFIG_DRM_MSM) += \ sde/sde_hw_color_processing_v1_7.o \ sde/sde_reg_dma.o \ sde/sde_hw_reg_dma_v1.o \ - sde/sde_hw_dsc.o + sde/sde_hw_dsc.o \ + sde/sde_hw_ds.o msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o @@ -155,6 +175,7 @@ msm_drm-$(CONFIG_DRM_MSM) += \ msm_gem_prime.o \ msm_gem_submit.o \ msm_gem_shrinker.o \ + msm_gem_vma.o \ msm_gpu.o \ msm_iommu.o \ msm_smmu.o \ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index fd266ed963b6cf2b4f412533a98624af2b9742dc..156abf00c0e2a5fdc00d34d16ba81c36184e6507 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -583,7 +583,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) #endif } - if (!gpu->mmu) { + if (!gpu->aspace) { /* TODO we think it is possible to configure the GPU to * restrict access to VRAM carveout. But the required * registers are unknown. For now just bail out and diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index d0d3c7baa8fe2f57b4c98be2d13d6b1ffc410f9c..2dc94122a95976fff5e5c58ced382186927c9b1a 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -672,7 +672,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) #endif } - if (!gpu->mmu) { + if (!gpu->aspace) { /* TODO we think it is possible to configure the GPU to * restrict access to VRAM carveout. But the required * registers are unknown. For now just bail out and diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index f386f463278d15e865f699f0cc563c37f5de8c9d..8214127498bc62bc24031da84c60ece844db70b1 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -64,7 +64,7 @@ int adreno_hw_init(struct msm_gpu *gpu) DBG("%s", gpu->name); - ret = msm_gem_get_iova(gpu->rb->bo, gpu->id, &gpu->rb_iova); + ret = msm_gem_get_iova(gpu->rb->bo, gpu->aspace, &gpu->rb_iova); if (ret) { gpu->rb_iova = 0; dev_err(gpu->dev->dev, "could not map ringbuffer: %d\n", ret); @@ -210,7 +210,14 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, void adreno_flush(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t wptr = get_wptr(gpu->rb); + uint32_t wptr; + + /* + * Mask wptr value that we calculate to fit in the HW range. This is + * to account for the possibility that the last command fit exactly into + * the ringbuffer and rb->next hasn't wrapped to zero yet + */ + wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1); /* ensure writes to ringbuffer have hit system memory: */ mb(); @@ -381,7 +388,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return ret; } - mmu = gpu->mmu; + mmu = gpu->aspace->mmu; if (mmu) { ret = mmu->funcs->attach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); @@ -406,7 +413,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return -ENOMEM; } - ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->id, + ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->aspace, &adreno_gpu->memptrs_iova); if (ret) { dev_err(drm->dev, "could not map memptrs: %d\n", ret); @@ -423,8 +430,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu) msm_gem_put_vaddr(gpu->memptrs_bo); if (gpu->memptrs_iova) - msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id); - + msm_gem_put_iova(gpu->memptrs_bo, gpu->base.aspace); drm_gem_object_unreference_unlocked(gpu->memptrs_bo); } release_firmware(gpu->pm4); diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c new file mode 100644 index 0000000000000000000000000000000000000000..ea2e72ae817ae857fe3626fe6b1bb03a1c123d98 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_audio.c @@ -0,0 +1,804 @@ +/* + * Copyright (c) 2016-2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include +#include + +#include + +#include "dp_catalog.h" +#include "dp_audio.h" +#include "dp_panel.h" + +struct dp_audio_private { + struct platform_device *ext_pdev; + struct platform_device *pdev; + struct dp_catalog_audio *catalog; + struct msm_ext_disp_init_data ext_audio_data; + struct dp_panel *panel; + + bool ack_enabled; + bool session_on; + bool engine_on; + + u32 channels; + + struct completion hpd_comp; + struct workqueue_struct *notify_workqueue; + struct delayed_work notify_delayed_work; + + struct dp_audio dp_audio; +}; + +static u32 dp_audio_get_header(struct dp_catalog_audio *catalog, + enum dp_catalog_audio_sdp_type sdp, + enum dp_catalog_audio_header_type header) +{ + catalog->sdp_type = sdp; + catalog->sdp_header = header; + catalog->get_header(catalog); + + return catalog->data; +} + +static void dp_audio_set_header(struct dp_catalog_audio *catalog, + u32 data, + enum dp_catalog_audio_sdp_type sdp, + enum dp_catalog_audio_header_type header) +{ + catalog->sdp_type = sdp; + catalog->sdp_header = header; + catalog->data = data; + catalog->set_header(catalog); +} + +static void dp_audio_stream_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x02; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + new_value = 0x0; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = audio->channels - 1; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x1; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x17; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = (0x0 | (0x11 << 2)); + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x84; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x1b; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = (0x0 | (0x11 << 2)); + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + new_value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x05; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x0F; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = 0x0; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_isrc_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x06; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x0F; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); +} + +static void dp_audio_setup_sdp(struct dp_audio_private *audio) +{ + audio->catalog->config_sdp(audio->catalog); + + dp_audio_stream_sdp(audio); + dp_audio_timestamp_sdp(audio); + dp_audio_infoframe_sdp(audio); + dp_audio_copy_management_sdp(audio); + dp_audio_isrc_sdp(audio); +} + +static void dp_audio_setup_acr(struct dp_audio_private *audio) +{ + u32 select = 0; + struct dp_catalog_audio *catalog = audio->catalog; + + switch (audio->dp_audio.bw_code) { + case DP_LINK_BW_1_62: + select = 0; + break; + case DP_LINK_BW_2_7: + select = 1; + break; + case DP_LINK_BW_5_4: + select = 2; + break; + case DP_LINK_BW_8_1: + select = 3; + break; + default: + pr_debug("Unknown link rate\n"); + select = 0; + break; + } + + catalog->data = select; + catalog->config_acr(catalog); +} + +static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 safe_to_exit_level = 0; + + switch (audio->dp_audio.lane_count) { + case 1: + safe_to_exit_level = 14; + break; + case 2: + safe_to_exit_level = 8; + break; + case 4: + safe_to_exit_level = 5; + break; + default: + pr_debug("setting the default safe_to_exit_level = %u\n", + safe_to_exit_level); + safe_to_exit_level = 14; + break; + } + + catalog->data = safe_to_exit_level; + catalog->safe_to_exit_level(catalog); +} + +static void dp_audio_enable(struct dp_audio_private *audio, bool enable) +{ + struct dp_catalog_audio *catalog = audio->catalog; + + catalog->data = enable; + catalog->enable(catalog); + + audio->engine_on = enable; +} + +static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev) +{ + struct msm_ext_disp_data *ext_data; + struct dp_audio *dp_audio; + + if (!pdev) { + pr_err("invalid input\n"); + return ERR_PTR(-ENODEV); + } + + ext_data = platform_get_drvdata(pdev); + if (!ext_data) { + pr_err("invalid ext disp data\n"); + return ERR_PTR(-EINVAL); + } + + dp_audio = ext_data->intf_data; + if (!ext_data) { + pr_err("invalid intf data\n"); + return ERR_PTR(-EINVAL); + } + + return container_of(dp_audio, struct dp_audio_private, dp_audio); +} + +static int dp_audio_info_setup(struct platform_device *pdev, + struct msm_ext_disp_audio_setup_params *params) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + mutex_lock(&audio->dp_audio.ops_lock); + + audio->channels = params->num_of_channels; + + dp_audio_setup_sdp(audio); + dp_audio_setup_acr(audio); + dp_audio_safe_to_exit_level(audio); + dp_audio_enable(audio, true); + + mutex_unlock(&audio->dp_audio.ops_lock); +end: + return rc; +} + +static int dp_audio_get_edid_blk(struct platform_device *pdev, + struct msm_ext_disp_audio_edid_blk *blk) +{ + int rc = 0; + struct dp_audio_private *audio; + struct sde_edid_ctrl *edid; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + if (!audio->panel || !audio->panel->edid_ctrl) { + pr_err("invalid panel data\n"); + rc = -EINVAL; + goto end; + } + + edid = audio->panel->edid_ctrl; + + blk->audio_data_blk = edid->audio_data_block; + blk->audio_data_blk_size = edid->adb_size; + + blk->spk_alloc_data_blk = edid->spkr_alloc_data_block; + blk->spk_alloc_data_blk_size = edid->sadb_size; +end: + return rc; +} + +static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + return audio->session_on; +end: + return rc; +} + +static int dp_audio_get_intf_id(struct platform_device *pdev) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + return EXT_DISPLAY_TYPE_DP; +end: + return rc; +} + +static void dp_audio_teardown_done(struct platform_device *pdev) +{ + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) + return; + + mutex_lock(&audio->dp_audio.ops_lock); + dp_audio_enable(audio, false); + mutex_unlock(&audio->dp_audio.ops_lock); + + complete_all(&audio->hpd_comp); + + pr_debug("audio engine disabled\n"); +} + +static int dp_audio_ack_done(struct platform_device *pdev, u32 ack) +{ + int rc = 0, ack_hpd; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + if (ack & AUDIO_ACK_SET_ENABLE) { + audio->ack_enabled = ack & AUDIO_ACK_ENABLE ? + true : false; + + pr_debug("audio ack feature %s\n", + audio->ack_enabled ? "enabled" : "disabled"); + goto end; + } + + if (!audio->ack_enabled) + goto end; + + ack_hpd = ack & AUDIO_ACK_CONNECT; + + pr_debug("acknowledging audio (%d)\n", ack_hpd); + + if (!audio->engine_on) + complete_all(&audio->hpd_comp); +end: + return rc; +} + +static int dp_audio_codec_ready(struct platform_device *pdev) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + pr_err("invalid input\n"); + rc = PTR_ERR(audio); + goto end; + } + + queue_delayed_work(audio->notify_workqueue, + &audio->notify_delayed_work, HZ/4); +end: + return rc; +} + +static int dp_audio_init_ext_disp(struct dp_audio_private *audio) +{ + int rc = 0; + struct device_node *pd = NULL; + const char *phandle = "qcom,ext-disp"; + struct msm_ext_disp_init_data *ext; + struct msm_ext_disp_audio_codec_ops *ops; + + ext = &audio->ext_audio_data; + ops = &ext->codec_ops; + + ext->type = EXT_DISPLAY_TYPE_DP; + ext->pdev = audio->pdev; + ext->intf_data = &audio->dp_audio; + + ops->audio_info_setup = dp_audio_info_setup; + ops->get_audio_edid_blk = dp_audio_get_edid_blk; + ops->cable_status = dp_audio_get_cable_status; + ops->get_intf_id = dp_audio_get_intf_id; + ops->teardown_done = dp_audio_teardown_done; + ops->acknowledge = dp_audio_ack_done; + ops->ready = dp_audio_codec_ready; + + if (!audio->pdev->dev.of_node) { + pr_err("cannot find audio dev.of_node\n"); + rc = -ENODEV; + goto end; + } + + pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0); + if (!pd) { + pr_err("cannot parse %s handle\n", phandle); + rc = -ENODEV; + goto end; + } + + audio->ext_pdev = of_find_device_by_node(pd); + if (!audio->ext_pdev) { + pr_err("cannot find %s pdev\n", phandle); + rc = -ENODEV; + goto end; + } + + rc = msm_ext_disp_register_intf(audio->ext_pdev, ext); + if (rc) + pr_err("failed to register disp\n"); +end: + if (pd) + of_node_put(pd); + + return rc; +} + +static int dp_audio_notify(struct dp_audio_private *audio, u32 state) +{ + int rc = 0; + struct msm_ext_disp_init_data *ext = &audio->ext_audio_data; + + rc = ext->intf_ops.audio_notify(audio->ext_pdev, + EXT_DISPLAY_TYPE_DP, state); + if (rc) { + pr_err("failed to notify audio. state=%d err=%d\n", state, rc); + goto end; + } + + reinit_completion(&audio->hpd_comp); + rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5); + if (!rc) { + pr_err("timeout. state=%d err=%d\n", state, rc); + rc = -ETIMEDOUT; + goto end; + } + + pr_debug("success\n"); +end: + return rc; +} + +static int dp_audio_on(struct dp_audio *dp_audio) +{ + int rc = 0; + struct dp_audio_private *audio; + struct msm_ext_disp_init_data *ext; + + if (!dp_audio) { + pr_err("invalid input\n"); + return -EINVAL; + } + + audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + if (IS_ERR(audio)) { + pr_err("invalid input\n"); + return -EINVAL; + } + + ext = &audio->ext_audio_data; + + audio->session_on = true; + + rc = ext->intf_ops.audio_config(audio->ext_pdev, + EXT_DISPLAY_TYPE_DP, + EXT_DISPLAY_CABLE_CONNECT); + if (rc) { + pr_err("failed to config audio, err=%d\n", rc); + goto end; + } + + rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT); + if (rc) + goto end; + + pr_debug("success\n"); +end: + return rc; +} + +static int dp_audio_off(struct dp_audio *dp_audio) +{ + int rc = 0; + struct dp_audio_private *audio; + struct msm_ext_disp_init_data *ext; + bool work_pending = false; + + if (!dp_audio) { + pr_err("invalid input\n"); + return -EINVAL; + } + + audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + ext = &audio->ext_audio_data; + + work_pending = cancel_delayed_work_sync(&audio->notify_delayed_work); + if (work_pending) + pr_debug("pending notification work completed\n"); + + rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT); + if (rc) + goto end; + + pr_debug("success\n"); +end: + rc = ext->intf_ops.audio_config(audio->ext_pdev, + EXT_DISPLAY_TYPE_DP, + EXT_DISPLAY_CABLE_DISCONNECT); + if (rc) + pr_err("failed to config audio, err=%d\n", rc); + + audio->session_on = false; + audio->engine_on = false; + + return rc; +} + +static void dp_audio_notify_work_fn(struct work_struct *work) +{ + struct dp_audio_private *audio; + struct delayed_work *dw = to_delayed_work(work); + + audio = container_of(dw, struct dp_audio_private, notify_delayed_work); + + dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT); +} + +static int dp_audio_create_notify_workqueue(struct dp_audio_private *audio) +{ + audio->notify_workqueue = create_workqueue("sdm_dp_audio_notify"); + if (IS_ERR_OR_NULL(audio->notify_workqueue)) { + pr_err("Error creating notify_workqueue\n"); + return -EPERM; + } + + INIT_DELAYED_WORK(&audio->notify_delayed_work, dp_audio_notify_work_fn); + + return 0; +} + +static void dp_audio_destroy_notify_workqueue(struct dp_audio_private *audio) +{ + if (audio->notify_workqueue) + destroy_workqueue(audio->notify_workqueue); +} + +struct dp_audio *dp_audio_get(struct platform_device *pdev, + struct dp_panel *panel, + struct dp_catalog_audio *catalog) +{ + int rc = 0; + struct dp_audio_private *audio; + struct dp_audio *dp_audio; + + if (!pdev || !panel || !catalog) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL); + if (!audio) { + rc = -ENOMEM; + goto error; + } + + rc = dp_audio_create_notify_workqueue(audio); + if (rc) + goto error_notify_workqueue; + + init_completion(&audio->hpd_comp); + + audio->pdev = pdev; + audio->panel = panel; + audio->catalog = catalog; + + dp_audio = &audio->dp_audio; + + mutex_init(&dp_audio->ops_lock); + + dp_audio->on = dp_audio_on; + dp_audio->off = dp_audio_off; + + rc = dp_audio_init_ext_disp(audio); + if (rc) { + goto error_ext_disp; + } + + catalog->init(catalog); + + return dp_audio; +error_ext_disp: + dp_audio_destroy_notify_workqueue(audio); +error_notify_workqueue: + devm_kfree(&pdev->dev, audio); +error: + return ERR_PTR(rc); +} + +void dp_audio_put(struct dp_audio *dp_audio) +{ + struct dp_audio_private *audio; + + if (!dp_audio) + return; + + audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + mutex_destroy(&dp_audio->ops_lock); + + dp_audio_destroy_notify_workqueue(audio); + + devm_kfree(&audio->pdev->dev, audio); +} diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h new file mode 100644 index 0000000000000000000000000000000000000000..807444b7c7dbfa9de3bad01484d3b5dca90a6deb --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_audio.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016-2017, 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 _DP_AUDIO_H_ +#define _DP_AUDIO_H_ + +#include + +#include "dp_panel.h" +#include "dp_catalog.h" + +/** + * struct dp_audio + * @lane_count: number of lanes configured in current session + * @bw_code: link rate's bandwidth code for current session + */ +struct dp_audio { + u32 lane_count; + u32 bw_code; + + struct mutex ops_lock; + + /** + * on() + * + * Enables the audio by notifying the user module. + * + * @dp_audio: an instance of struct dp_audio. + * + * Returns the error code in case of failure, 0 in success case. + */ + int (*on)(struct dp_audio *dp_audio); + + /** + * off() + * + * Disables the audio by notifying the user module. + * + * @dp_audio: an instance of struct dp_audio. + * + * Returns the error code in case of failure, 0 in success case. + */ + int (*off)(struct dp_audio *dp_audio); +}; + +/** + * dp_audio_get() + * + * Creates and instance of dp audio. + * + * @pdev: caller's platform device instance. + * @panel: an instance of dp_panel module. + * @catalog: an instance of dp_catalog_audio module. + * + * Returns the error code in case of failure, otherwize + * an instance of newly created dp_module. + */ +struct dp_audio *dp_audio_get(struct platform_device *pdev, + struct dp_panel *panel, + struct dp_catalog_audio *catalog); + +/** + * dp_audio_put() + * + * Cleans the dp_audio instance. + * + * @dp_audio: an instance of dp_audio. + */ +void dp_audio_put(struct dp_audio *dp_audio); +#endif /* _DP_AUDIO_H_ */ + + diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c new file mode 100644 index 0000000000000000000000000000000000000000..79f2ec91c96ba1e0fa26551d6ba00daed11b6047 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2012-2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include + +#include "dp_aux.h" + +#define DP_AUX_ENUM_STR(x) #x + +enum { + DP_AUX_DATA_INDEX_WRITE = BIT(31), +}; + +struct dp_aux_private { + struct device *dev; + struct dp_aux dp_aux; + struct dp_catalog_aux *catalog; + struct dp_aux_cfg *cfg; + + struct mutex mutex; + struct completion comp; + + u32 aux_error_num; + u32 retry_cnt; + bool cmd_busy; + bool native; + bool read; + bool no_send_addr; + bool no_send_stop; + u32 offset; + u32 segment; + atomic_t aborted; + + struct drm_dp_aux drm_aux; +}; + +static char *dp_aux_get_error(u32 aux_error) +{ + switch (aux_error) { + case DP_AUX_ERR_NONE: + return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE); + case DP_AUX_ERR_ADDR: + return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR); + case DP_AUX_ERR_TOUT: + return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT); + case DP_AUX_ERR_NACK: + return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK); + case DP_AUX_ERR_DEFER: + return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER); + case DP_AUX_ERR_NACK_DEFER: + return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER); + default: + return "unknown"; + } +} + +static u32 dp_aux_write(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg) +{ + u32 data[4], reg, len; + u8 *msgdata = msg->buffer; + int const aux_cmd_fifo_len = 128; + int i = 0; + + if (aux->read) + len = 4; + else + len = msg->size + 4; + + /* + * cmd fifo only has depth of 144 bytes + * limit buf length to 128 bytes here + */ + if (len > aux_cmd_fifo_len) { + pr_err("buf len error\n"); + return 0; + } + + /* Pack cmd and write to HW */ + data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */ + if (aux->read) + data[0] |= BIT(4); /* R/W */ + + data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */ + data[2] = msg->address & 0xff; /* addr[7:0] */ + data[3] = (msg->size - 1) & 0xff; /* len[7:0] */ + + for (i = 0; i < len; i++) { + reg = (i < 4) ? data[i] : msgdata[i - 4]; + reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */ + if (i == 0) + reg |= DP_AUX_DATA_INDEX_WRITE; + aux->catalog->data = reg; + aux->catalog->write_data(aux->catalog); + } + + aux->catalog->clear_trans(aux->catalog, false); + aux->catalog->clear_hw_interrupts(aux->catalog); + + reg = 0; /* Transaction number == 1 */ + if (!aux->native) { /* i2c */ + reg |= BIT(8); + + if (aux->no_send_addr) + reg |= BIT(10); + + if (aux->no_send_stop) + reg |= BIT(11); + } + + reg |= BIT(9); + aux->catalog->data = reg; + aux->catalog->write_trans(aux->catalog); + + return len; +} + +static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg) +{ + u32 ret = 0, len = 0, timeout; + int const aux_timeout_ms = HZ/4; + + reinit_completion(&aux->comp); + + len = dp_aux_write(aux, msg); + if (len == 0) { + pr_err("DP AUX write failed\n"); + return -EINVAL; + } + + timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms); + if (!timeout) { + pr_err("aux %s timeout\n", (aux->read ? "read" : "write")); + return -ETIMEDOUT; + } + + if (aux->aux_error_num == DP_AUX_ERR_NONE) { + ret = len; + } else { + pr_err_ratelimited("aux err: %s\n", + dp_aux_get_error(aux->aux_error_num)); + + ret = -EINVAL; + } + + return ret; +} + +static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg) +{ + u32 data; + u8 *dp; + u32 i, actual_i; + u32 len = msg->size; + + aux->catalog->clear_trans(aux->catalog, true); + + data = 0; + data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */ + data |= BIT(0); /* read */ + + aux->catalog->data = data; + aux->catalog->write_data(aux->catalog); + + dp = msg->buffer; + + /* discard first byte */ + data = aux->catalog->read_data(aux->catalog); + + for (i = 0; i < len; i++) { + data = aux->catalog->read_data(aux->catalog); + *dp++ = (u8)((data >> 8) & 0xff); + + actual_i = (data >> 16) & 0xFF; + if (i != actual_i) + pr_warn("Index mismatch: expected %d, found %d\n", + i, actual_i); + } +} + +static void dp_aux_native_handler(struct dp_aux_private *aux) +{ + u32 isr = aux->catalog->isr; + + if (isr & DP_INTR_AUX_I2C_DONE) + aux->aux_error_num = DP_AUX_ERR_NONE; + else if (isr & DP_INTR_WRONG_ADDR) + aux->aux_error_num = DP_AUX_ERR_ADDR; + else if (isr & DP_INTR_TIMEOUT) + aux->aux_error_num = DP_AUX_ERR_TOUT; + if (isr & DP_INTR_NACK_DEFER) + aux->aux_error_num = DP_AUX_ERR_NACK; + if (isr & DP_INTR_AUX_ERROR) { + aux->aux_error_num = DP_AUX_ERR_PHY; + aux->catalog->clear_hw_interrupts(aux->catalog); + } + + complete(&aux->comp); +} + +static void dp_aux_i2c_handler(struct dp_aux_private *aux) +{ + u32 isr = aux->catalog->isr; + + if (isr & DP_INTR_AUX_I2C_DONE) { + if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER)) + aux->aux_error_num = DP_AUX_ERR_NACK; + else + aux->aux_error_num = DP_AUX_ERR_NONE; + } else { + if (isr & DP_INTR_WRONG_ADDR) + aux->aux_error_num = DP_AUX_ERR_ADDR; + else if (isr & DP_INTR_TIMEOUT) + aux->aux_error_num = DP_AUX_ERR_TOUT; + if (isr & DP_INTR_NACK_DEFER) + aux->aux_error_num = DP_AUX_ERR_NACK_DEFER; + if (isr & DP_INTR_I2C_NACK) + aux->aux_error_num = DP_AUX_ERR_NACK; + if (isr & DP_INTR_I2C_DEFER) + aux->aux_error_num = DP_AUX_ERR_DEFER; + if (isr & DP_INTR_AUX_ERROR) { + aux->aux_error_num = DP_AUX_ERR_PHY; + aux->catalog->clear_hw_interrupts(aux->catalog); + } + } + + complete(&aux->comp); +} + +static void dp_aux_isr(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + pr_err("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->catalog->get_irq(aux->catalog, aux->cmd_busy); + + if (!aux->cmd_busy) + return; + + if (aux->native) + dp_aux_native_handler(aux); + else + dp_aux_i2c_handler(aux); +} + +static void dp_aux_reconfig(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + pr_err("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->catalog->update_aux_cfg(aux->catalog, + aux->cfg, PHY_AUX_CFG1); + aux->catalog->reset(aux->catalog); +} + +static void dp_aux_abort_transaction(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + pr_err("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + atomic_set(&aux->aborted, 1); +} + +static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, + struct drm_dp_aux_msg *input_msg) +{ + u32 const edid_address = 0x50; + u32 const segment_address = 0x30; + bool i2c_read = input_msg->request & + (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + u8 *data = NULL; + + if (aux->native || i2c_read || ((input_msg->address != edid_address) && + (input_msg->address != segment_address))) + return; + + + data = input_msg->buffer; + if (input_msg->address == segment_address) + aux->segment = *data; + else + aux->offset = *data; +} + +/** + * dp_aux_transfer_helper() - helper function for EDID read transactions + * + * @aux: DP AUX private structure + * @input_msg: input message from DRM upstream APIs + * + * return: void + * + * This helper function is used to fix EDID reads for non-compliant + * sinks that do not handle the i2c middle-of-transaction flag correctly. + */ +static void dp_aux_transfer_helper(struct dp_aux_private *aux, + struct drm_dp_aux_msg *input_msg) +{ + struct drm_dp_aux_msg helper_msg; + u32 const message_size = 0x10; + u32 const segment_address = 0x30; + u32 const edid_block_length = 0x80; + bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT; + bool i2c_read = input_msg->request & + (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + + if (!i2c_mot || !i2c_read || (input_msg->size == 0)) + return; + + /* + * Sending the segment value and EDID offset will be performed + * from the DRM upstream EDID driver for each block. Avoid + * duplicate AUX transactions related to this while reading the + * first 16 bytes of each block. + */ + if (!(aux->offset % edid_block_length)) + goto end; + + aux->read = false; + aux->cmd_busy = true; + aux->no_send_addr = true; + aux->no_send_stop = true; + + /* + * Send the segment address for i2c reads for segment > 0 and for which + * the middle-of-transaction flag is set. This is required to support + * EDID reads of more than 2 blocks as the segment address is reset to 0 + * since we are overriding the middle-of-transaction flag for read + * transactions. + */ + if (aux->segment) { + memset(&helper_msg, 0, sizeof(helper_msg)); + helper_msg.address = segment_address; + helper_msg.buffer = &aux->segment; + helper_msg.size = 1; + dp_aux_cmd_fifo_tx(aux, &helper_msg); + } + + /* + * Send the offset address for every i2c read in which the + * middle-of-transaction flag is set. This will ensure that the sink + * will update its read pointer and return the correct portion of the + * EDID buffer in the subsequent i2c read trasntion triggered in the + * native AUX transfer function. + */ + memset(&helper_msg, 0, sizeof(helper_msg)); + helper_msg.address = input_msg->address; + helper_msg.buffer = &aux->offset; + helper_msg.size = 1; + dp_aux_cmd_fifo_tx(aux, &helper_msg); +end: + aux->offset += message_size; + + if (aux->offset == 0x80 || aux->offset == 0x100) + aux->segment = 0x0; /* reset segment at end of block */ +} + +/* + * This function does the real job to process an AUX transaction. + * It will call aux_reset() function to reset the AUX channel, + * if the waiting is timeout. + */ +static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) +{ + ssize_t ret; + int const aux_cmd_native_max = 16; + int const aux_cmd_i2c_max = 128; + int const retry_count = 5; + struct dp_aux_private *aux = container_of(drm_aux, + struct dp_aux_private, drm_aux); + + mutex_lock(&aux->mutex); + + if (atomic_read(&aux->aborted)) { + ret = -ETIMEDOUT; + goto unlock_exit; + } + + aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); + + /* Ignore address only message */ + if ((msg->size == 0) || (msg->buffer == NULL)) { + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + ret = msg->size; + goto unlock_exit; + } + + /* msg sanity check */ + if ((aux->native && (msg->size > aux_cmd_native_max)) || + (msg->size > aux_cmd_i2c_max)) { + pr_err("%s: invalid msg: size(%zu), request(%x)\n", + __func__, msg->size, msg->request); + ret = -EINVAL; + goto unlock_exit; + } + + dp_aux_update_offset_and_segment(aux, msg); + dp_aux_transfer_helper(aux, msg); + + aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + aux->cmd_busy = true; + + if (aux->read) { + aux->no_send_addr = true; + aux->no_send_stop = false; + } else { + aux->no_send_addr = true; + aux->no_send_stop = true; + } + + ret = dp_aux_cmd_fifo_tx(aux, msg); + if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) { + aux->retry_cnt++; + if (!(aux->retry_cnt % retry_count)) + aux->catalog->update_aux_cfg(aux->catalog, + aux->cfg, PHY_AUX_CFG1); + aux->catalog->reset(aux->catalog); + goto unlock_exit; + } else if (ret < 0) { + goto unlock_exit; + } + + if (aux->aux_error_num == DP_AUX_ERR_NONE) { + if (aux->read) + dp_aux_cmd_fifo_rx(aux, msg); + + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + } else { + /* Reply defer to retry */ + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; + } + + /* Return requested size for success or retry */ + ret = msg->size; + aux->retry_cnt = 0; + +unlock_exit: + aux->cmd_busy = false; + mutex_unlock(&aux->mutex); + return ret; +} + +static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg) +{ + int i = 0; + + for (i = 0; i < PHY_AUX_CFG_MAX; i++) + aux_cfg[i].current_index = 0; +} + +static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) +{ + struct dp_aux_private *aux; + + if (!dp_aux || !aux_cfg) { + pr_err("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + dp_aux_reset_phy_config_indices(aux_cfg); + aux->catalog->setup(aux->catalog, aux_cfg); + aux->catalog->reset(aux->catalog); + aux->catalog->enable(aux->catalog, true); + atomic_set(&aux->aborted, 0); + aux->retry_cnt = 0; +} + +static void dp_aux_deinit(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + pr_err("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + atomic_set(&aux->aborted, 1); + aux->catalog->enable(aux->catalog, false); +} + +static int dp_aux_register(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + int ret = 0; + + if (!dp_aux) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto exit; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->drm_aux.name = "sde_dp_aux"; + aux->drm_aux.dev = aux->dev; + aux->drm_aux.transfer = dp_aux_transfer; + ret = drm_dp_aux_register(&aux->drm_aux); + if (ret) { + pr_err("%s: failed to register drm aux: %d\n", __func__, ret); + goto exit; + } + dp_aux->drm_aux = &aux->drm_aux; +exit: + return ret; +} + +static void dp_aux_deregister(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + pr_err("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + drm_dp_aux_unregister(&aux->drm_aux); +} + +struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, + struct dp_aux_cfg *aux_cfg) +{ + int rc = 0; + struct dp_aux_private *aux; + struct dp_aux *dp_aux; + + if (!catalog || !aux_cfg) { + pr_err("invalid input\n"); + rc = -ENODEV; + goto error; + } + + aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL); + if (!aux) { + rc = -ENOMEM; + goto error; + } + + init_completion(&aux->comp); + aux->cmd_busy = false; + mutex_init(&aux->mutex); + + aux->dev = dev; + aux->catalog = catalog; + aux->cfg = aux_cfg; + dp_aux = &aux->dp_aux; + aux->retry_cnt = 0; + + dp_aux->isr = dp_aux_isr; + dp_aux->init = dp_aux_init; + dp_aux->deinit = dp_aux_deinit; + dp_aux->drm_aux_register = dp_aux_register; + dp_aux->drm_aux_deregister = dp_aux_deregister; + dp_aux->reconfig = dp_aux_reconfig; + dp_aux->abort = dp_aux_abort_transaction; + + return dp_aux; +error: + return ERR_PTR(rc); +} + +void dp_aux_put(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) + return; + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + mutex_destroy(&aux->mutex); + + devm_kfree(aux->dev, aux); +} diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h new file mode 100644 index 0000000000000000000000000000000000000000..e8cb1cc0ca7fb2457b70c0aa1467bec0059d212c --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_aux.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_AUX_H_ +#define _DP_AUX_H_ + +#include "dp_catalog.h" +#include "drm_dp_helper.h" + +enum dp_aux_error { + DP_AUX_ERR_NONE = 0, + DP_AUX_ERR_ADDR = -1, + DP_AUX_ERR_TOUT = -2, + DP_AUX_ERR_NACK = -3, + DP_AUX_ERR_DEFER = -4, + DP_AUX_ERR_NACK_DEFER = -5, + DP_AUX_ERR_PHY = -6, +}; + +struct dp_aux { + struct drm_dp_aux *drm_aux; + int (*drm_aux_register)(struct dp_aux *aux); + void (*drm_aux_deregister)(struct dp_aux *aux); + void (*isr)(struct dp_aux *aux); + void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg); + void (*deinit)(struct dp_aux *aux); + void (*reconfig)(struct dp_aux *aux); + void (*abort)(struct dp_aux *aux); +}; + +struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, + struct dp_aux_cfg *aux_cfg); +void dp_aux_put(struct dp_aux *aux); + +#endif /*__DP_AUX_H_*/ diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c new file mode 100644 index 0000000000000000000000000000000000000000..cfb443672723d3e721f486f545a98def21a62591 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -0,0 +1,1624 @@ +/* + * Copyright (c) 2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include +#include + +#include "dp_catalog.h" +#include "dp_reg.h" + +#define DP_GET_MSB(x) (x >> 8) +#define DP_GET_LSB(x) (x & 0xff) + +#define dp_read(offset) readl_relaxed((offset)) +#define dp_write(offset, data) writel_relaxed((data), (offset)) + +#define dp_catalog_get_priv(x) { \ + struct dp_catalog *dp_catalog; \ + dp_catalog = container_of(x, struct dp_catalog, x); \ + catalog = container_of(dp_catalog, struct dp_catalog_private, \ + dp_catalog); \ +} + +#define DP_INTERRUPT_STATUS1 \ + (DP_INTR_AUX_I2C_DONE| \ + DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \ + DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \ + DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \ + DP_INTR_PLL_UNLOCKED | DP_INTR_AUX_ERROR) + +#define DP_INTR_MASK1 (DP_INTERRUPT_STATUS1 << 2) + +#define DP_INTERRUPT_STATUS2 \ + (DP_INTR_READY_FOR_VIDEO | DP_INTR_IDLE_PATTERN_SENT | \ + DP_INTR_FRAME_END | DP_INTR_CRC_UPDATED) + +#define DP_INTR_MASK2 (DP_INTERRUPT_STATUS2 << 2) + +static u8 const vm_pre_emphasis[4][4] = { + {0x00, 0x0B, 0x12, 0xFF}, /* pe0, 0 db */ + {0x00, 0x0A, 0x12, 0xFF}, /* pe1, 3.5 db */ + {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ +}; + +/* voltage swing, 0.2v and 1.0v are not support */ +static u8 const vm_voltage_swing[4][4] = { + {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v */ + {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */ + {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ + {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ +}; + +/* audio related catalog functions */ +struct dp_catalog_private { + struct device *dev; + struct dp_io *io; + + u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX]; + struct dp_catalog dp_catalog; +}; + +/* aux related catalog functions */ +static u32 dp_catalog_aux_read_data(struct dp_catalog_aux *aux) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!aux) { + pr_err("invalid input\n"); + goto end; + } + + dp_catalog_get_priv(aux); + base = catalog->io->dp_aux.base; + + return dp_read(base + DP_AUX_DATA); +end: + return 0; +} + +static int dp_catalog_aux_write_data(struct dp_catalog_aux *aux) +{ + int rc = 0; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!aux) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dp_catalog_get_priv(aux); + base = catalog->io->dp_aux.base; + + dp_write(base + DP_AUX_DATA, aux->data); +end: + return rc; +} + +static int dp_catalog_aux_write_trans(struct dp_catalog_aux *aux) +{ + int rc = 0; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!aux) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dp_catalog_get_priv(aux); + base = catalog->io->dp_aux.base; + + dp_write(base + DP_AUX_TRANS_CTRL, aux->data); +end: + return rc; +} + +static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read) +{ + int rc = 0; + u32 data = 0; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!aux) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dp_catalog_get_priv(aux); + base = catalog->io->dp_aux.base; + + if (read) { + data = dp_read(base + DP_AUX_TRANS_CTRL); + data &= ~BIT(9); + dp_write(base + DP_AUX_TRANS_CTRL, data); + } else { + dp_write(base + DP_AUX_TRANS_CTRL, 0); + } +end: + return rc; +} + +static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux) +{ + struct dp_catalog_private *catalog; + void __iomem *phy_base; + u32 data = 0; + + if (!aux) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(aux); + phy_base = catalog->io->phy_io.base; + + data = dp_read(phy_base + DP_PHY_AUX_INTERRUPT_STATUS); + pr_debug("PHY_AUX_INTERRUPT_STATUS=0x%08x\n", data); + + dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f); + wmb(); /* make sure 0x1f is written before next write */ + dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f); + wmb(); /* make sure 0x9f is written before next write */ + dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0); + wmb(); /* make sure register is cleared */ +} + +static void dp_catalog_aux_reset(struct dp_catalog_aux *aux) +{ + u32 aux_ctrl; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!aux) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(aux); + base = catalog->io->dp_aux.base; + + aux_ctrl = dp_read(base + DP_AUX_CTRL); + + aux_ctrl |= BIT(1); + dp_write(base + DP_AUX_CTRL, aux_ctrl); + usleep_range(1000, 1010); /* h/w recommended delay */ + + aux_ctrl &= ~BIT(1); + dp_write(base + DP_AUX_CTRL, aux_ctrl); + wmb(); /* make sure AUX reset is done here */ +} + +static void dp_catalog_aux_enable(struct dp_catalog_aux *aux, bool enable) +{ + u32 aux_ctrl; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!aux) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(aux); + base = catalog->io->dp_aux.base; + + aux_ctrl = dp_read(base + DP_AUX_CTRL); + + if (enable) { + aux_ctrl |= BIT(0); + dp_write(base + DP_AUX_CTRL, aux_ctrl); + wmb(); /* make sure AUX module is enabled */ + dp_write(base + DP_TIMEOUT_COUNT, 0xffff); + dp_write(base + DP_AUX_LIMITS, 0xffff); + } else { + aux_ctrl &= ~BIT(0); + dp_write(base + DP_AUX_CTRL, aux_ctrl); + } +} + +static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type) +{ + struct dp_catalog_private *catalog; + u32 new_index = 0, current_index = 0; + + if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(aux); + + current_index = cfg[type].current_index; + new_index = (current_index + 1) % cfg[type].cfg_cnt; + pr_debug("Updating %s from 0x%08x to 0x%08x\n", + dp_phy_aux_config_type_to_string(type), + cfg[type].lut[current_index], cfg[type].lut[new_index]); + + dp_write(catalog->io->phy_io.base + cfg[type].offset, + cfg[type].lut[new_index]); + cfg[type].current_index = new_index; +} + +static void dp_catalog_aux_setup(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg) +{ + struct dp_catalog_private *catalog; + int i = 0; + + if (!aux || !cfg) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(aux); + + dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x65); + wmb(); /* make sure PD programming happened */ + + /* Turn on BIAS current for PHY/PLL */ + dp_write(catalog->io->dp_pll_io.base + + QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b); + + /* DP AUX CFG register programming */ + for (i = 0; i < PHY_AUX_CFG_MAX; i++) { + pr_debug("%s: offset=0x%08x, value=0x%08x\n", + dp_phy_aux_config_type_to_string(i), + cfg[i].offset, cfg[i].lut[cfg[i].current_index]); + dp_write(catalog->io->phy_io.base + cfg[i].offset, + cfg[i].lut[cfg[i].current_index]); + } + + dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F); + wmb(); /* make sure AUX configuration is done before enabling it */ +} + +static void dp_catalog_aux_get_irq(struct dp_catalog_aux *aux, bool cmd_busy) +{ + u32 ack; + struct dp_catalog_private *catalog; + void __iomem *ahb_base; + + if (!aux) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(aux); + ahb_base = catalog->io->dp_ahb.base; + + aux->isr = dp_read(ahb_base + DP_INTR_STATUS); + aux->isr &= ~DP_INTR_MASK1; + ack = aux->isr & DP_INTERRUPT_STATUS1; + ack <<= 1; + ack |= DP_INTR_MASK1; + dp_write(ahb_base + DP_INTR_STATUS, ack); +} + +/* controller related catalog functions */ +static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_ahb.base; + + return dp_read(base + DP_HDCP_STATUS); +} + +static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct drm_msm_ext_hdr_metadata *hdr; + void __iomem *base; + u32 header, parity, data; + u8 buf[SZ_128], off = 0; + + if (!panel) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(panel); + hdr = &panel->hdr_data.hdr_meta; + base = catalog->io->dp_link.base; + + /* HEADER BYTE 1 */ + header = panel->hdr_data.vscext_header_byte1; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_1_BIT) + | (parity << PARITY_BYTE_1_BIT)); + dp_write(base + MMSS_DP_VSCEXT_0, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + /* HEADER BYTE 2 */ + header = panel->hdr_data.vscext_header_byte2; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_2_BIT) + | (parity << PARITY_BYTE_2_BIT)); + dp_write(base + MMSS_DP_VSCEXT_1, data); + + /* HEADER BYTE 3 */ + header = panel->hdr_data.vscext_header_byte3; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_3_BIT) + | (parity << PARITY_BYTE_3_BIT)); + data |= dp_read(base + MMSS_DP_VSCEXT_1); + dp_write(base + MMSS_DP_VSCEXT_1, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = panel->hdr_data.version; + data |= panel->hdr_data.length << 8; + data |= hdr->eotf << 16; + dp_write(base + MMSS_DP_VSCEXT_2, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->display_primaries_x[0]) | + (DP_GET_MSB(hdr->display_primaries_x[0]) << 8) | + (DP_GET_LSB(hdr->display_primaries_y[0]) << 16) | + (DP_GET_MSB(hdr->display_primaries_y[0]) << 24)); + dp_write(base + MMSS_DP_VSCEXT_3, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->display_primaries_x[1]) | + (DP_GET_MSB(hdr->display_primaries_x[1]) << 8) | + (DP_GET_LSB(hdr->display_primaries_y[1]) << 16) | + (DP_GET_MSB(hdr->display_primaries_y[1]) << 24)); + dp_write(base + MMSS_DP_VSCEXT_4, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->display_primaries_x[2]) | + (DP_GET_MSB(hdr->display_primaries_x[2]) << 8) | + (DP_GET_LSB(hdr->display_primaries_y[2]) << 16) | + (DP_GET_MSB(hdr->display_primaries_y[2]) << 24)); + dp_write(base + MMSS_DP_VSCEXT_5, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->white_point_x) | + (DP_GET_MSB(hdr->white_point_x) << 8) | + (DP_GET_LSB(hdr->white_point_y) << 16) | + (DP_GET_MSB(hdr->white_point_y) << 24)); + dp_write(base + MMSS_DP_VSCEXT_6, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->max_luminance) | + (DP_GET_MSB(hdr->max_luminance) << 8) | + (DP_GET_LSB(hdr->min_luminance) << 16) | + (DP_GET_MSB(hdr->min_luminance) << 24)); + dp_write(base + MMSS_DP_VSCEXT_7, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->max_content_light_level) | + (DP_GET_MSB(hdr->max_content_light_level) << 8) | + (DP_GET_LSB(hdr->max_average_light_level) << 16) | + (DP_GET_MSB(hdr->max_average_light_level) << 24)); + dp_write(base + MMSS_DP_VSCEXT_8, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = 0; + dp_write(base + MMSS_DP_VSCEXT_9, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + print_hex_dump(KERN_DEBUG, "[drm-dp] VSCEXT: ", + DUMP_PREFIX_NONE, 16, 4, buf, off, false); +} + +static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 header, parity, data; + u8 bpc, off = 0; + u8 buf[SZ_128]; + + if (!panel) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(panel); + base = catalog->io->dp_link.base; + + /* HEADER BYTE 1 */ + header = panel->hdr_data.vsc_header_byte1; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_1_BIT) + | (parity << PARITY_BYTE_1_BIT)); + dp_write(base + MMSS_DP_GENERIC0_0, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + /* HEADER BYTE 2 */ + header = panel->hdr_data.vsc_header_byte2; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_2_BIT) + | (parity << PARITY_BYTE_2_BIT)); + dp_write(base + MMSS_DP_GENERIC0_1, data); + + /* HEADER BYTE 3 */ + header = panel->hdr_data.vsc_header_byte3; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_3_BIT) + | (parity << PARITY_BYTE_3_BIT)); + data |= dp_read(base + MMSS_DP_GENERIC0_1); + dp_write(base + MMSS_DP_GENERIC0_1, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = 0; + dp_write(base + MMSS_DP_GENERIC0_2, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(base + MMSS_DP_GENERIC0_3, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(base + MMSS_DP_GENERIC0_4, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(base + MMSS_DP_GENERIC0_5, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + switch (panel->hdr_data.bpc) { + default: + case 10: + bpc = BIT(1); + break; + case 8: + bpc = BIT(0); + break; + case 6: + bpc = 0; + break; + } + + data = (panel->hdr_data.colorimetry & 0xF) | + ((panel->hdr_data.pixel_encoding & 0xF) << 4) | + (bpc << 8) | + ((panel->hdr_data.dynamic_range & 0x1) << 15) | + ((panel->hdr_data.content_type & 0x7) << 16); + + dp_write(base + MMSS_DP_GENERIC0_6, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = 0; + dp_write(base + MMSS_DP_GENERIC0_7, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(base + MMSS_DP_GENERIC0_8, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(base + MMSS_DP_GENERIC0_9, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + print_hex_dump(KERN_DEBUG, "[drm-dp] VSC: ", + DUMP_PREFIX_NONE, 16, 4, buf, off, false); +} + +static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 cfg, cfg2, misc; + + if (!panel) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(panel); + base = catalog->io->dp_link.base; + + cfg = dp_read(base + MMSS_DP_SDP_CFG); + cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); + misc = dp_read(base + DP_MISC1_MISC0); + + if (en) { + /* VSCEXT_SDP_EN, GEN0_SDP_EN */ + cfg |= BIT(16) | BIT(17); + dp_write(base + MMSS_DP_SDP_CFG, cfg); + + /* EXTN_SDPSIZE GENERIC0_SDPSIZE */ + cfg2 |= BIT(15) | BIT(16); + dp_write(base + MMSS_DP_SDP_CFG2, cfg2); + + dp_catalog_panel_setup_vsc_sdp(panel); + dp_catalog_panel_setup_infoframe_sdp(panel); + + /* indicates presence of VSC (BIT(6) of MISC1) */ + misc |= BIT(14); + + if (panel->hdr_data.hdr_meta.eotf) + pr_debug("Enabled\n"); + else + pr_debug("Reset\n"); + } else { + /* VSCEXT_SDP_EN, GEN0_SDP_EN */ + cfg &= ~BIT(16) & ~BIT(17); + dp_write(base + MMSS_DP_SDP_CFG, cfg); + + /* EXTN_SDPSIZE GENERIC0_SDPSIZE */ + cfg2 &= ~BIT(15) & ~BIT(16); + dp_write(base + MMSS_DP_SDP_CFG2, cfg2); + + /* switch back to MSA */ + misc &= ~BIT(14); + + pr_debug("Disabled\n"); + } + + dp_write(base + DP_MISC1_MISC0, misc); + + dp_write(base + MMSS_DP_SDP_CFG3, 0x01); + dp_write(base + MMSS_DP_SDP_CFG3, 0x00); +} + +static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + dp_write(base + DP_VALID_BOUNDARY, ctrl->valid_boundary); + dp_write(base + DP_TU, ctrl->dp_tu); + dp_write(base + DP_VALID_BOUNDARY_2, ctrl->valid_boundary2); +} + +static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + dp_write(base + DP_STATE_CTRL, state); +} + +static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u32 cfg) +{ + struct dp_catalog_private *catalog; + void __iomem *link_base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + link_base = catalog->io->dp_link.base; + + pr_debug("DP_CONFIGURATION_CTRL=0x%x\n", cfg); + + dp_write(link_base + DP_CONFIGURATION_CTRL, cfg); +} + +static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + dp_write(base + DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4); +} + +static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl, + bool enable) +{ + u32 mainlink_ctrl; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + if (enable) { + dp_write(base + DP_MAINLINK_CTRL, 0x02000000); + wmb(); /* make sure mainlink is turned off before reset */ + dp_write(base + DP_MAINLINK_CTRL, 0x02000002); + wmb(); /* make sure mainlink entered reset */ + dp_write(base + DP_MAINLINK_CTRL, 0x02000000); + wmb(); /* make sure mainlink reset done */ + dp_write(base + DP_MAINLINK_CTRL, 0x02000001); + wmb(); /* make sure mainlink turned on */ + } else { + mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL); + mainlink_ctrl &= ~BIT(0); + dp_write(base + DP_MAINLINK_CTRL, mainlink_ctrl); + } +} + +static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl, + u32 cc, u32 tb) +{ + u32 misc_val = cc; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + misc_val |= (tb << 5); + misc_val |= BIT(0); /* Configure clock to synchronous mode */ + + pr_debug("misc settings = 0x%x\n", misc_val); + dp_write(base + DP_MISC1_MISC0, misc_val); +} + +static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl, + u32 rate, u32 stream_rate_khz, + bool fixed_nvid) +{ + u32 pixel_m, pixel_n; + u32 mvid, nvid; + u64 mvid_calc; + u32 const nvid_fixed = 0x8000; + u32 const link_rate_hbr2 = 540000; + u32 const link_rate_hbr3 = 810000; + struct dp_catalog_private *catalog; + void __iomem *base_cc, *base_ctrl; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + if (fixed_nvid) { + pr_debug("use fixed NVID=0x%x\n", nvid_fixed); + nvid = nvid_fixed; + + pr_debug("link rate=%dkbps, stream_rate_khz=%uKhz", + rate, stream_rate_khz); + + /* + * For intermediate results, use 64 bit arithmetic to avoid + * loss of precision. + */ + mvid_calc = (u64) stream_rate_khz * nvid; + mvid_calc = div_u64(mvid_calc, rate); + + /* + * truncate back to 32 bits as this final divided value will + * always be within the range of a 32 bit unsigned int. + */ + mvid = (u32) mvid_calc; + } else { + base_cc = catalog->io->dp_cc_io.base; + + pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M); + pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N); + pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); + + mvid = (pixel_m & 0xFFFF) * 5; + nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); + + pr_debug("rate = %d\n", rate); + + if (link_rate_hbr2 == rate) + nvid *= 2; + + if (link_rate_hbr3 == rate) + nvid *= 3; + } + + base_ctrl = catalog->io->dp_link.base; + pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid); + dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid); + dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid); +} + +static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl, + u32 pattern) +{ + int bit, cnt = 10; + u32 data; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + bit = 1; + bit <<= (pattern - 1); + pr_debug("hw: bit=%d train=%d\n", bit, pattern); + dp_write(base + DP_STATE_CTRL, bit); + + bit = 8; + bit <<= (pattern - 1); + + while (cnt--) { + data = dp_read(base + DP_MAINLINK_READY); + if (data & bit) + break; + } + + if (cnt == 0) + pr_err("set link_train=%d failed\n", pattern); +} + +static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + + base = catalog->io->usb3_dp_com.base; + + dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a); + dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02); + dp_write(base + USB3_DP_COM_SW_RESET, 0x01); + /* make sure usb3 com phy software reset is done */ + wmb(); + + if (!flip) /* CC1 */ + dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02); + else /* CC2 */ + dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03); + + dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00); + dp_write(base + USB3_DP_COM_SW_RESET, 0x00); + /* make sure the software reset is done */ + wmb(); + + dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01); + dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00); + /* make sure phy is brought out of reset */ + wmb(); +} + +static void dp_catalog_panel_tpg_cfg(struct dp_catalog_panel *panel, + bool enable) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!panel) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(panel); + base = catalog->io->dp_p0.base; + + if (!enable) { + dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x0); + dp_write(base + MMSS_DP_BIST_ENABLE, 0x0); + dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x0); + wmb(); /* ensure Timing generator is turned off */ + return; + } + + dp_write(base + MMSS_DP_INTF_CONFIG, 0x0); + dp_write(base + MMSS_DP_INTF_HSYNC_CTL, panel->hsync_ctl); + dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F0, panel->vsync_period * + panel->hsync_period); + dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, panel->v_sync_width * + panel->hsync_period); + dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F1, 0); + dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0); + dp_write(base + MMSS_DP_INTF_DISPLAY_HCTL, panel->display_hctl); + dp_write(base + MMSS_DP_INTF_ACTIVE_HCTL, 0); + dp_write(base + MMSS_INTF_DISPLAY_V_START_F0, panel->display_v_start); + dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F0, panel->display_v_end); + dp_write(base + MMSS_INTF_DISPLAY_V_START_F1, 0); + dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F1, 0); + dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F0, 0); + dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F0, 0); + dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F1, 0); + dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F1, 0); + dp_write(base + MMSS_DP_INTF_POLARITY_CTL, 0); + wmb(); /* ensure TPG registers are programmed */ + + dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x100); + dp_write(base + MMSS_DP_TPG_VIDEO_CONFIG, 0x5); + wmb(); /* ensure TPG config is programmed */ + dp_write(base + MMSS_DP_BIST_ENABLE, 0x1); + dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x1); + wmb(); /* ensure Timing generator is turned on */ +} + +static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl) +{ + u32 sw_reset; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_ahb.base; + + sw_reset = dp_read(base + DP_SW_RESET); + + sw_reset |= BIT(0); + dp_write(base + DP_SW_RESET, sw_reset); + usleep_range(1000, 1010); /* h/w recommended delay */ + + sw_reset &= ~BIT(0); + dp_write(base + DP_SW_RESET, sw_reset); +} + +static bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog_ctrl *ctrl) +{ + u32 data; + int cnt = 10; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + goto end; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_link.base; + + while (--cnt) { + /* DP_MAINLINK_READY */ + data = dp_read(base + DP_MAINLINK_READY); + if (data & BIT(0)) + return true; + + usleep_range(1000, 1010); /* 1ms wait before next reg read */ + } + pr_err("mainlink not ready\n"); +end: + return false; +} + +static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl, + bool enable) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_ahb.base; + + if (enable) { + dp_write(base + DP_INTR_STATUS, DP_INTR_MASK1); + dp_write(base + DP_INTR_STATUS2, DP_INTR_MASK2); + } else { + dp_write(base + DP_INTR_STATUS, 0x00); + dp_write(base + DP_INTR_STATUS2, 0x00); + } +} + +static void dp_catalog_ctrl_hpd_config(struct dp_catalog_ctrl *ctrl, bool en) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_aux.base; + + if (en) { + u32 reftimer = dp_read(base + DP_DP_HPD_REFTIMER); + + dp_write(base + DP_DP_HPD_INT_ACK, 0xF); + dp_write(base + DP_DP_HPD_INT_MASK, 0xF); + + /* Enabling REFTIMER */ + reftimer |= BIT(16); + dp_write(base + DP_DP_HPD_REFTIMER, 0xF); + /* Enable HPD */ + dp_write(base + DP_DP_HPD_CTRL, 0x1); + } else { + /*Disable HPD */ + dp_write(base + DP_DP_HPD_CTRL, 0x0); + } +} + +static void dp_catalog_ctrl_get_interrupt(struct dp_catalog_ctrl *ctrl) +{ + u32 ack = 0; + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_ahb.base; + + ctrl->isr = dp_read(base + DP_INTR_STATUS2); + ctrl->isr &= ~DP_INTR_MASK2; + ack = ctrl->isr & DP_INTERRUPT_STATUS2; + ack <<= 1; + ack |= DP_INTR_MASK2; + dp_write(base + DP_INTR_STATUS2, ack); +} + +static void dp_catalog_ctrl_phy_reset(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base = catalog->io->dp_ahb.base; + + dp_write(base + DP_PHY_CTRL, 0x5); /* bit 0 & 2 */ + usleep_range(1000, 1010); /* h/w recommended delay */ + dp_write(base + DP_PHY_CTRL, 0x0); + wmb(); /* make sure PHY reset done */ +} + +static void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog_ctrl *ctrl, + bool flipped, u8 ln_cnt) +{ + u32 info = 0x0; + struct dp_catalog_private *catalog; + u8 orientation = BIT(!!flipped); + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + + info |= (ln_cnt & 0x0F); + info |= ((orientation & 0x0F) << 4); + pr_debug("Shared Info = 0x%x\n", info); + + dp_write(catalog->io->phy_io.base + DP_PHY_SPARE0, info); +} + +static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl, + u8 v_level, u8 p_level) +{ + struct dp_catalog_private *catalog; + void __iomem *base0, *base1; + u8 value0, value1; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + base0 = catalog->io->ln_tx0_io.base; + base1 = catalog->io->ln_tx1_io.base; + + pr_debug("hw: v=%d p=%d\n", v_level, p_level); + + value0 = vm_voltage_swing[v_level][p_level]; + value1 = vm_pre_emphasis[v_level][p_level]; + + /* program default setting first */ + dp_write(base0 + TXn_TX_DRV_LVL, 0x2A); + dp_write(base1 + TXn_TX_DRV_LVL, 0x2A); + dp_write(base0 + TXn_TX_EMP_POST1_LVL, 0x20); + dp_write(base1 + TXn_TX_EMP_POST1_LVL, 0x20); + + /* Enable MUX to use Cursor values from these registers */ + value0 |= BIT(5); + value1 |= BIT(5); + + /* Configure host and panel only if both values are allowed */ + if (value0 != 0xFF && value1 != 0xFF) { + dp_write(base0 + TXn_TX_DRV_LVL, value0); + dp_write(base1 + TXn_TX_DRV_LVL, value0); + dp_write(base0 + TXn_TX_EMP_POST1_LVL, value1); + dp_write(base1 + TXn_TX_EMP_POST1_LVL, value1); + + pr_debug("hw: vx_value=0x%x px_value=0x%x\n", + value0, value1); + } else { + pr_err("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n", + v_level, value0, p_level, value1); + } +} + +static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl, + u32 pattern) +{ + struct dp_catalog_private *catalog; + u32 value = 0x0; + void __iomem *base = NULL; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_catalog_get_priv(ctrl); + + base = catalog->io->dp_link.base; + + dp_write(base + DP_STATE_CTRL, 0x0); + + switch (pattern) { + case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: + dp_write(base + DP_STATE_CTRL, 0x1); + break; + case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: + value &= ~(1 << 16); + dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + value |= 0xFC; + dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + dp_write(base + DP_MAINLINK_LEVELS, 0x2); + dp_write(base + DP_STATE_CTRL, 0x10); + break; + case DP_TEST_PHY_PATTERN_PRBS7: + dp_write(base + DP_STATE_CTRL, 0x20); + break; + case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: + dp_write(base + DP_STATE_CTRL, 0x40); + /* 00111110000011111000001111100000 */ + dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0); + /* 00001111100000111110000011111000 */ + dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8); + /* 1111100000111110 */ + dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E); + break; + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1: + value = BIT(16); + dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + value |= 0xFC; + dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + dp_write(base + DP_MAINLINK_LEVELS, 0x2); + dp_write(base + DP_STATE_CTRL, 0x10); + break; + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3: + dp_write(base + DP_MAINLINK_CTRL, 0x11); + dp_write(base + DP_STATE_CTRL, 0x8); + break; + default: + pr_debug("No valid test pattern requested: 0x%x\n", pattern); + return; + } + + /* Make sure the test pattern is programmed in the hardware */ + wmb(); +} + +static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + void __iomem *base = NULL; + + if (!ctrl) { + pr_err("invalid input\n"); + return 0; + } + + dp_catalog_get_priv(ctrl); + + base = catalog->io->dp_link.base; + + return dp_read(base + DP_MAINLINK_READY); +} + +/* panel related catalog functions */ +static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + + if (!panel) { + pr_err("invalid input\n"); + goto end; + } + + dp_catalog_get_priv(panel); + base = catalog->io->dp_link.base; + + dp_write(base + DP_TOTAL_HOR_VER, panel->total); + dp_write(base + DP_START_HOR_VER_FROM_SYNC, panel->sync_start); + dp_write(base + DP_HSYNC_VSYNC_WIDTH_POLARITY, panel->width_blanking); + dp_write(base + DP_ACTIVE_HOR_VER, panel->dp_active); +end: + return 0; +} + +static void dp_catalog_audio_init(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = { + { + MMSS_DP_AUDIO_STREAM_0, + MMSS_DP_AUDIO_STREAM_1, + MMSS_DP_AUDIO_STREAM_1, + }, + { + MMSS_DP_AUDIO_TIMESTAMP_0, + MMSS_DP_AUDIO_TIMESTAMP_1, + MMSS_DP_AUDIO_TIMESTAMP_1, + }, + { + MMSS_DP_AUDIO_INFOFRAME_0, + MMSS_DP_AUDIO_INFOFRAME_1, + MMSS_DP_AUDIO_INFOFRAME_1, + }, + { + MMSS_DP_AUDIO_COPYMANAGEMENT_0, + MMSS_DP_AUDIO_COPYMANAGEMENT_1, + MMSS_DP_AUDIO_COPYMANAGEMENT_1, + }, + { + MMSS_DP_AUDIO_ISRC_0, + MMSS_DP_AUDIO_ISRC_1, + MMSS_DP_AUDIO_ISRC_1, + }, + }; + + if (!audio) + return; + + dp_catalog_get_priv(audio); + + catalog->audio_map = sdp_map; +} + +static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 sdp_cfg = 0; + u32 sdp_cfg2 = 0; + + if (!audio) + return; + + dp_catalog_get_priv(audio); + base = catalog->io->dp_link.base; + + sdp_cfg = dp_read(base + MMSS_DP_SDP_CFG); + + /* AUDIO_TIMESTAMP_SDP_EN */ + sdp_cfg |= BIT(1); + /* AUDIO_STREAM_SDP_EN */ + sdp_cfg |= BIT(2); + /* AUDIO_COPY_MANAGEMENT_SDP_EN */ + sdp_cfg |= BIT(5); + /* AUDIO_ISRC_SDP_EN */ + sdp_cfg |= BIT(6); + /* AUDIO_INFOFRAME_SDP_EN */ + sdp_cfg |= BIT(20); + + pr_debug("sdp_cfg = 0x%x\n", sdp_cfg); + dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg); + + sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); + /* IFRM_REGSRC -> Do not use reg values */ + sdp_cfg2 &= ~BIT(0); + /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */ + sdp_cfg2 &= ~BIT(1); + + pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2); + dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2); +} + +static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; + void __iomem *base; + enum dp_catalog_audio_sdp_type sdp; + enum dp_catalog_audio_header_type header; + + if (!audio) + return; + + dp_catalog_get_priv(audio); + + base = catalog->io->dp_link.base; + sdp_map = catalog->audio_map; + sdp = audio->sdp_type; + header = audio->sdp_header; + + audio->data = dp_read(base + sdp_map[sdp][header]); +} + +static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; + void __iomem *base; + enum dp_catalog_audio_sdp_type sdp; + enum dp_catalog_audio_header_type header; + u32 data; + + if (!audio) + return; + + dp_catalog_get_priv(audio); + + base = catalog->io->dp_link.base; + sdp_map = catalog->audio_map; + sdp = audio->sdp_type; + header = audio->sdp_header; + data = audio->data; + + dp_write(base + sdp_map[sdp][header], data); +} + +static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 acr_ctrl, select; + + dp_catalog_get_priv(audio); + + select = audio->data; + base = catalog->io->dp_link.base; + + acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14); + + pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl); + + dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl); +} + +static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 mainlink_levels, safe_to_exit_level; + + dp_catalog_get_priv(audio); + + base = catalog->io->dp_link.base; + safe_to_exit_level = audio->data; + + mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS); + mainlink_levels &= 0xFE0; + mainlink_levels |= safe_to_exit_level; + + pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n", + mainlink_levels, safe_to_exit_level); + + dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels); +} + +static void dp_catalog_audio_enable(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + bool enable; + u32 audio_ctrl; + + dp_catalog_get_priv(audio); + + base = catalog->io->dp_link.base; + enable = !!audio->data; + + audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG); + + if (enable) + audio_ctrl |= BIT(0); + else + audio_ctrl &= ~BIT(0); + + pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl); + dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl); + + /* make sure audio engine is disabled */ + wmb(); +} + +static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 value, new_value; + u8 parity_byte; + + if (!panel) + return; + + dp_catalog_get_priv(panel); + base = catalog->io->dp_link.base; + + /* Config header and parity byte 1 */ + value = dp_read(base + MMSS_DP_GENERIC1_0); + + new_value = 0x83; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_write(base + MMSS_DP_GENERIC1_0, value); + + /* Config header and parity byte 2 */ + value = dp_read(base + MMSS_DP_GENERIC1_1); + + new_value = 0x1b; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_write(base + MMSS_DP_GENERIC1_1, value); + + /* Config header and parity byte 3 */ + value = dp_read(base + MMSS_DP_GENERIC1_1); + + new_value = (0x0 | (0x12 << 2)); + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + new_value, parity_byte); + dp_write(base + MMSS_DP_GENERIC1_1, value); +} + +static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + void __iomem *base; + u32 spd_cfg = 0, spd_cfg2 = 0; + u8 *vendor = NULL, *product = NULL; + /* + * Source Device Information + * 00h unknown + * 01h Digital STB + * 02h DVD + * 03h D-VHS + * 04h HDD Video + * 05h DVC + * 06h DSC + * 07h Video CD + * 08h Game + * 09h PC general + * 0ah Bluray-Disc + * 0bh Super Audio CD + * 0ch HD DVD + * 0dh PMP + * 0eh-ffh reserved + */ + u32 device_type = 0; + + if (!panel) + return; + + dp_catalog_get_priv(panel); + base = catalog->io->dp_link.base; + + dp_catalog_config_spd_header(panel); + + vendor = panel->spd_vendor_name; + product = panel->spd_product_description; + + dp_write(base + MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) | + ((vendor[1] & 0x7f) << 8) | + ((vendor[2] & 0x7f) << 16) | + ((vendor[3] & 0x7f) << 24))); + dp_write(base + MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) | + ((vendor[5] & 0x7f) << 8) | + ((vendor[6] & 0x7f) << 16) | + ((vendor[7] & 0x7f) << 24))); + dp_write(base + MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) | + ((product[1] & 0x7f) << 8) | + ((product[2] & 0x7f) << 16) | + ((product[3] & 0x7f) << 24))); + dp_write(base + MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) | + ((product[5] & 0x7f) << 8) | + ((product[6] & 0x7f) << 16) | + ((product[7] & 0x7f) << 24))); + dp_write(base + MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) | + ((product[9] & 0x7f) << 8) | + ((product[10] & 0x7f) << 16) | + ((product[11] & 0x7f) << 24))); + dp_write(base + MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) | + ((product[13] & 0x7f) << 8) | + ((product[14] & 0x7f) << 16) | + ((product[15] & 0x7f) << 24))); + dp_write(base + MMSS_DP_GENERIC1_8, device_type); + dp_write(base + MMSS_DP_GENERIC1_9, 0x00); + + spd_cfg = dp_read(base + MMSS_DP_SDP_CFG); + /* GENERIC1_SDP for SPD Infoframe */ + spd_cfg |= BIT(18); + dp_write(base + MMSS_DP_SDP_CFG, spd_cfg); + + spd_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); + /* 28 data bytes for SPD Infoframe with GENERIC1 set */ + spd_cfg2 |= BIT(17); + dp_write(base + MMSS_DP_SDP_CFG2, spd_cfg2); + + dp_write(base + MMSS_DP_SDP_CFG3, 0x1); + dp_write(base + MMSS_DP_SDP_CFG3, 0x0); +} + +struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) +{ + int rc = 0; + struct dp_catalog *dp_catalog; + struct dp_catalog_private *catalog; + struct dp_catalog_aux aux = { + .read_data = dp_catalog_aux_read_data, + .write_data = dp_catalog_aux_write_data, + .write_trans = dp_catalog_aux_write_trans, + .clear_trans = dp_catalog_aux_clear_trans, + .reset = dp_catalog_aux_reset, + .update_aux_cfg = dp_catalog_aux_update_cfg, + .enable = dp_catalog_aux_enable, + .setup = dp_catalog_aux_setup, + .get_irq = dp_catalog_aux_get_irq, + .clear_hw_interrupts = dp_catalog_aux_clear_hw_interrupts, + }; + struct dp_catalog_ctrl ctrl = { + .state_ctrl = dp_catalog_ctrl_state_ctrl, + .config_ctrl = dp_catalog_ctrl_config_ctrl, + .lane_mapping = dp_catalog_ctrl_lane_mapping, + .mainlink_ctrl = dp_catalog_ctrl_mainlink_ctrl, + .config_misc = dp_catalog_ctrl_config_misc, + .config_msa = dp_catalog_ctrl_config_msa, + .set_pattern = dp_catalog_ctrl_set_pattern, + .reset = dp_catalog_ctrl_reset, + .usb_reset = dp_catalog_ctrl_usb_reset, + .mainlink_ready = dp_catalog_ctrl_mainlink_ready, + .enable_irq = dp_catalog_ctrl_enable_irq, + .hpd_config = dp_catalog_ctrl_hpd_config, + .phy_reset = dp_catalog_ctrl_phy_reset, + .phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg, + .update_vx_px = dp_catalog_ctrl_update_vx_px, + .get_interrupt = dp_catalog_ctrl_get_interrupt, + .update_transfer_unit = dp_catalog_ctrl_update_transfer_unit, + .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status, + .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern, + .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern, + }; + struct dp_catalog_audio audio = { + .init = dp_catalog_audio_init, + .config_acr = dp_catalog_audio_config_acr, + .enable = dp_catalog_audio_enable, + .config_sdp = dp_catalog_audio_config_sdp, + .set_header = dp_catalog_audio_set_header, + .get_header = dp_catalog_audio_get_header, + .safe_to_exit_level = dp_catalog_audio_safe_to_exit_level, + }; + struct dp_catalog_panel panel = { + .timing_cfg = dp_catalog_panel_timing_cfg, + .config_hdr = dp_catalog_panel_config_hdr, + .tpg_config = dp_catalog_panel_tpg_cfg, + .config_spd = dp_catalog_panel_config_spd, + }; + + if (!io) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + catalog = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL); + if (!catalog) { + rc = -ENOMEM; + goto error; + } + + catalog->dev = dev; + catalog->io = io; + + dp_catalog = &catalog->dp_catalog; + + dp_catalog->aux = aux; + dp_catalog->ctrl = ctrl; + dp_catalog->audio = audio; + dp_catalog->panel = panel; + + return dp_catalog; +error: + return ERR_PTR(rc); +} + +void dp_catalog_put(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog; + + if (!dp_catalog) + return; + + catalog = container_of(dp_catalog, struct dp_catalog_private, + dp_catalog); + + devm_kfree(catalog->dev, catalog); +} diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h new file mode 100644 index 0000000000000000000000000000000000000000..d03be6a82d7cbfc5b921b3d06546ba8c4cb8fba1 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2017, 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 _DP_CATALOG_H_ +#define _DP_CATALOG_H_ + +#include + +#include "dp_parser.h" + +/* interrupts */ +#define DP_INTR_HPD BIT(0) +#define DP_INTR_AUX_I2C_DONE BIT(3) +#define DP_INTR_WRONG_ADDR BIT(6) +#define DP_INTR_TIMEOUT BIT(9) +#define DP_INTR_NACK_DEFER BIT(12) +#define DP_INTR_WRONG_DATA_CNT BIT(15) +#define DP_INTR_I2C_NACK BIT(18) +#define DP_INTR_I2C_DEFER BIT(21) +#define DP_INTR_PLL_UNLOCKED BIT(24) +#define DP_INTR_AUX_ERROR BIT(27) + +#define DP_INTR_READY_FOR_VIDEO BIT(0) +#define DP_INTR_IDLE_PATTERN_SENT BIT(3) +#define DP_INTR_FRAME_END BIT(6) +#define DP_INTR_CRC_UPDATED BIT(9) + +struct dp_catalog_hdr_data { + u32 ext_header_byte0; + u32 ext_header_byte1; + u32 ext_header_byte2; + u32 ext_header_byte3; + + u32 vsc_header_byte0; + u32 vsc_header_byte1; + u32 vsc_header_byte2; + u32 vsc_header_byte3; + + u32 vscext_header_byte0; + u32 vscext_header_byte1; + u32 vscext_header_byte2; + u32 vscext_header_byte3; + + u32 bpc; + + u32 version; + u32 length; + u32 pixel_encoding; + u32 colorimetry; + u32 dynamic_range; + u32 content_type; + + struct drm_msm_ext_hdr_metadata hdr_meta; +}; + +struct dp_catalog_aux { + u32 data; + u32 isr; + + u32 (*read_data)(struct dp_catalog_aux *aux); + int (*write_data)(struct dp_catalog_aux *aux); + int (*write_trans)(struct dp_catalog_aux *aux); + int (*clear_trans)(struct dp_catalog_aux *aux, bool read); + void (*reset)(struct dp_catalog_aux *aux); + void (*enable)(struct dp_catalog_aux *aux, bool enable); + void (*update_aux_cfg)(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type); + void (*setup)(struct dp_catalog_aux *aux, + struct dp_aux_cfg *aux_cfg); + void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy); + void (*clear_hw_interrupts)(struct dp_catalog_aux *aux); +}; + +struct dp_catalog_ctrl { + u32 dp_tu; + u32 valid_boundary; + u32 valid_boundary2; + u32 isr; + + void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state); + void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u32 config); + void (*lane_mapping)(struct dp_catalog_ctrl *ctrl); + void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*config_misc)(struct dp_catalog_ctrl *ctrl, u32 cc, u32 tb); + void (*config_msa)(struct dp_catalog_ctrl *ctrl, u32 rate, + u32 stream_rate_khz, bool fixed_nvid); + void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern); + void (*reset)(struct dp_catalog_ctrl *ctrl); + void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip); + bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl); + void (*enable_irq)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*hpd_config)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*phy_reset)(struct dp_catalog_ctrl *ctrl); + void (*phy_lane_cfg)(struct dp_catalog_ctrl *ctrl, bool flipped, + u8 lane_cnt); + void (*update_vx_px)(struct dp_catalog_ctrl *ctrl, u8 v_level, + u8 p_level); + void (*get_interrupt)(struct dp_catalog_ctrl *ctrl); + void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl); + u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl); + void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl, + u32 pattern); + u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); +}; + +#define HEADER_BYTE_2_BIT 0 +#define PARITY_BYTE_2_BIT 8 +#define HEADER_BYTE_1_BIT 16 +#define PARITY_BYTE_1_BIT 24 +#define HEADER_BYTE_3_BIT 16 +#define PARITY_BYTE_3_BIT 24 + +enum dp_catalog_audio_sdp_type { + DP_AUDIO_SDP_STREAM, + DP_AUDIO_SDP_TIMESTAMP, + DP_AUDIO_SDP_INFOFRAME, + DP_AUDIO_SDP_COPYMANAGEMENT, + DP_AUDIO_SDP_ISRC, + DP_AUDIO_SDP_MAX, +}; + +enum dp_catalog_audio_header_type { + DP_AUDIO_SDP_HEADER_1, + DP_AUDIO_SDP_HEADER_2, + DP_AUDIO_SDP_HEADER_3, + DP_AUDIO_SDP_HEADER_MAX, +}; + +struct dp_catalog_audio { + enum dp_catalog_audio_sdp_type sdp_type; + enum dp_catalog_audio_header_type sdp_header; + u32 data; + + void (*init)(struct dp_catalog_audio *audio); + void (*enable)(struct dp_catalog_audio *audio); + void (*config_acr)(struct dp_catalog_audio *audio); + void (*config_sdp)(struct dp_catalog_audio *audio); + void (*set_header)(struct dp_catalog_audio *audio); + void (*get_header)(struct dp_catalog_audio *audio); + void (*safe_to_exit_level)(struct dp_catalog_audio *audio); +}; + +struct dp_catalog_panel { + u32 total; + u32 sync_start; + u32 width_blanking; + u32 dp_active; + u8 *spd_vendor_name; + u8 *spd_product_description; + + struct dp_catalog_hdr_data hdr_data; + + /* TPG */ + u32 hsync_period; + u32 vsync_period; + u32 display_v_start; + u32 display_v_end; + u32 v_sync_width; + u32 hsync_ctl; + u32 display_hctl; + + int (*timing_cfg)(struct dp_catalog_panel *panel); + void (*config_hdr)(struct dp_catalog_panel *panel, bool en); + void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); + void (*config_spd)(struct dp_catalog_panel *panel); +}; + +struct dp_catalog { + struct dp_catalog_aux aux; + struct dp_catalog_ctrl ctrl; + struct dp_catalog_audio audio; + struct dp_catalog_panel panel; +}; + +static inline u8 dp_ecc_get_g0_value(u8 data) +{ + u8 c[4]; + u8 g[4]; + u8 ret_data = 0; + u8 i; + + for (i = 0; i < 4; i++) + c[i] = (data >> i) & 0x01; + + g[0] = c[3]; + g[1] = c[0] ^ c[3]; + g[2] = c[1]; + g[3] = c[2]; + + for (i = 0; i < 4; i++) + ret_data = ((g[i] & 0x01) << i) | ret_data; + + return ret_data; +} + +static inline u8 dp_ecc_get_g1_value(u8 data) +{ + u8 c[4]; + u8 g[4]; + u8 ret_data = 0; + u8 i; + + for (i = 0; i < 4; i++) + c[i] = (data >> i) & 0x01; + + g[0] = c[0] ^ c[3]; + g[1] = c[0] ^ c[1] ^ c[3]; + g[2] = c[1] ^ c[2]; + g[3] = c[2] ^ c[3]; + + for (i = 0; i < 4; i++) + ret_data = ((g[i] & 0x01) << i) | ret_data; + + return ret_data; +} + +static inline u8 dp_header_get_parity(u32 data) +{ + u8 x0 = 0; + u8 x1 = 0; + u8 ci = 0; + u8 iData = 0; + u8 i = 0; + u8 parity_byte; + u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2; + + for (i = 0; i < num_byte; i++) { + iData = (data >> i*4) & 0xF; + + ci = iData ^ x1; + x1 = x0 ^ dp_ecc_get_g1_value(ci); + x0 = dp_ecc_get_g0_value(ci); + } + + parity_byte = x1 | (x0 << 4); + + return parity_byte; +} + +struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io); +void dp_catalog_put(struct dp_catalog *catalog); + +#endif /* _DP_CATALOG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c new file mode 100644 index 0000000000000000000000000000000000000000..cb54b5ff338f1a02c61ac056b4ea963daf99a0f8 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -0,0 +1,1516 @@ +/* + * Copyright (c) 2012-2018, 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) "[drm-dp] %s: " fmt, __func__ + +#include +#include +#include + +#include "dp_ctrl.h" + +#define DP_KHZ_TO_HZ 1000 + +#define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0) +#define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3) + +/* dp state ctrl */ +#define ST_TRAIN_PATTERN_1 BIT(0) +#define ST_TRAIN_PATTERN_2 BIT(1) +#define ST_TRAIN_PATTERN_3 BIT(2) +#define ST_TRAIN_PATTERN_4 BIT(3) +#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(4) +#define ST_PRBS7 BIT(5) +#define ST_CUSTOM_80_BIT_PATTERN BIT(6) +#define ST_SEND_VIDEO BIT(7) +#define ST_PUSH_IDLE BIT(8) + +#define MR_LINK_TRAINING1 0x8 +#define MR_LINK_SYMBOL_ERM 0x80 +#define MR_LINK_PRBS7 0x100 +#define MR_LINK_CUSTOM80 0x200 +#define MR_LINK_TRAINING4 0x40 + +struct dp_vc_tu_mapping_table { + u32 vic; + u8 lanes; + u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */ + u8 bpp; + u8 valid_boundary_link; + u16 delay_start_link; + bool boundary_moderation_en; + u8 valid_lower_boundary_link; + u8 upper_boundary_count; + u8 lower_boundary_count; + u8 tu_size_minus1; +}; + +struct dp_ctrl_private { + struct dp_ctrl dp_ctrl; + + struct device *dev; + struct dp_aux *aux; + struct dp_panel *panel; + struct dp_link *link; + struct dp_power *power; + struct dp_parser *parser; + struct dp_catalog_ctrl *catalog; + + struct completion idle_comp; + struct completion video_comp; + + bool orientation; + bool power_on; + + atomic_t aborted; + + u32 pixel_rate; + u32 vic; +}; + +enum notification_status { + NOTIFY_UNKNOWN, + NOTIFY_CONNECT, + NOTIFY_DISCONNECT, + NOTIFY_CONNECT_IRQ_HPD, + NOTIFY_DISCONNECT_IRQ_HPD, +}; + +static void dp_ctrl_idle_patterns_sent(struct dp_ctrl_private *ctrl) +{ + pr_debug("idle_patterns_sent\n"); + complete(&ctrl->idle_comp); +} + +static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl) +{ + pr_debug("dp_video_ready\n"); + complete(&ctrl->video_comp); +} + +static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + pr_err("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + atomic_set(&ctrl->aborted, 1); +} + +static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state) +{ + ctrl->catalog->state_ctrl(ctrl->catalog, state); +} + +static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) +{ + int const idle_pattern_completion_timeout_ms = 3 * HZ / 100; + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + pr_err("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->power_on || atomic_read(&ctrl->aborted)) { + pr_err("CTRL off, return\n"); + return; + } + + reinit_completion(&ctrl->idle_comp); + dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE); + + if (!wait_for_completion_timeout(&ctrl->idle_comp, + idle_pattern_completion_timeout_ms)) + pr_warn("PUSH_IDLE pattern timedout\n"); + + pr_debug("mainlink off done\n"); +} + +static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) +{ + u32 config = 0, tbd; + u8 *dpcd = ctrl->panel->dpcd; + + config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ + config |= (0 << 11); /* RGB */ + + /* Scrambler reset enable */ + if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP) + config |= (1 << 10); + + tbd = ctrl->link->get_test_bits_depth(ctrl->link, + ctrl->panel->pinfo.bpp); + + if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) + tbd = DP_TEST_BIT_DEPTH_8; + + config |= tbd << 8; + + /* Num of Lanes */ + config |= ((ctrl->link->link_params.lane_count - 1) << 4); + + if (drm_dp_enhanced_frame_cap(dpcd)) + config |= 0x40; + + config |= 0x04; /* progressive video */ + + config |= 0x03; /* sycn clock & static Mvid */ + + ctrl->catalog->config_ctrl(ctrl->catalog, config); +} + +/** + * dp_ctrl_configure_source_params() - configures DP transmitter source params + * @ctrl: Display Port Driver data + * + * Configures the DP transmitter source params including details such as lane + * configuration, output format and sink/panel timing information. + */ +static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl) +{ + u32 cc, tb; + + ctrl->catalog->lane_mapping(ctrl->catalog); + ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); + + dp_ctrl_config_ctrl(ctrl); + + tb = ctrl->link->get_test_bits_depth(ctrl->link, + ctrl->panel->pinfo.bpp); + cc = ctrl->link->get_colorimetry_config(ctrl->link); + ctrl->catalog->config_misc(ctrl->catalog, cc, tb); + ctrl->panel->timing_cfg(ctrl->panel); +} + +static void dp_ctrl_get_extra_req_bytes(u64 result_valid, + int valid_bdary_link, + u64 value1, u64 value2, + bool *negative, u64 *result, + u64 compare) +{ + *negative = false; + if (result_valid >= compare) { + if (valid_bdary_link + >= compare) + *result = value1 + value2; + else { + if (value1 < value2) + *negative = true; + *result = (value1 >= value2) ? + (value1 - value2) : (value2 - value1); + } + } else { + if (valid_bdary_link + >= compare) { + if (value1 >= value2) + *negative = true; + *result = (value1 >= value2) ? + (value1 - value2) : (value2 - value1); + } else { + *result = value1 + value2; + *negative = true; + } + } +} + +static u64 roundup_u64(u64 x, u64 y) +{ + x += (y - 1); + return (div64_ul(x, y) * y); +} + +static u64 rounddown_u64(u64 x, u64 y) +{ + u64 rem; + + div64_u64_rem(x, y, &rem); + return (x - rem); +} + +static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, + struct dp_vc_tu_mapping_table *tu_table) +{ + u32 const multiplier = 1000000; + u64 pclk, lclk; + u8 bpp, ln_cnt; + int run_idx = 0; + u32 lwidth, h_blank; + u32 fifo_empty = 0; + u32 ratio_scale = 1001; + u64 temp, ratio, original_ratio; + u64 temp2, reminder; + u64 temp3, temp4, result = 0; + + u64 err = multiplier; + u64 n_err = 0, n_n_err = 0; + bool n_err_neg, nn_err_neg; + u8 hblank_margin = 16; + + u8 tu_size, tu_size_desired = 0, tu_size_minus1; + int valid_boundary_link; + u64 resulting_valid; + u64 total_valid; + u64 effective_valid; + u64 effective_valid_recorded; + int n_tus; + int n_tus_per_lane; + int paired_tus; + int remainder_tus; + int remainder_tus_upper, remainder_tus_lower; + int extra_bytes; + int filler_size; + int delay_start_link; + int boundary_moderation_en = 0; + int upper_bdry_cnt = 0; + int lower_bdry_cnt = 0; + int i_upper_bdry_cnt = 0; + int i_lower_bdry_cnt = 0; + int valid_lower_boundary_link = 0; + int even_distribution_bf = 0; + int even_distribution_legacy = 0; + int even_distribution = 0; + int min_hblank = 0; + int extra_pclk_cycles; + u8 extra_pclk_cycle_delay = 4; + int extra_pclk_cycles_in_link_clk; + u64 ratio_by_tu; + u64 average_valid2; + u64 extra_buffer_margin; + int new_valid_boundary_link; + + u64 resulting_valid_tmp; + u64 ratio_by_tu_tmp; + int n_tus_tmp; + int extra_pclk_cycles_tmp; + int extra_pclk_cycles_in_lclk_tmp; + int extra_req_bytes_new_tmp; + int filler_size_tmp; + int lower_filler_size_tmp; + int delay_start_link_tmp; + int min_hblank_tmp = 0; + bool extra_req_bytes_is_neg = false; + struct dp_panel_info *pinfo = &ctrl->panel->pinfo; + + u8 dp_brute_force = 1; + u64 brute_force_threshold = 10; + u64 diff_abs; + + ln_cnt = ctrl->link->link_params.lane_count; + + bpp = pinfo->bpp; + lwidth = pinfo->h_active; + h_blank = pinfo->h_back_porch + pinfo->h_front_porch + + pinfo->h_sync_width; + pclk = pinfo->pixel_clk_khz * 1000; + + boundary_moderation_en = 0; + upper_bdry_cnt = 0; + lower_bdry_cnt = 0; + i_upper_bdry_cnt = 0; + i_lower_bdry_cnt = 0; + valid_lower_boundary_link = 0; + even_distribution_bf = 0; + even_distribution_legacy = 0; + even_distribution = 0; + min_hblank = 0; + + lclk = drm_dp_bw_code_to_link_rate( + ctrl->link->link_params.bw_code) * DP_KHZ_TO_HZ; + + pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n", + pclk, lwidth, h_blank); + pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt); + ratio = div64_u64_rem(pclk * bpp * multiplier, + 8 * ln_cnt * lclk, &reminder); + ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk)); + original_ratio = ratio; + + extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay + * lclk * multiplier, pclk), multiplier); + extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier); + + /* To deal with cases where lines are not distributable */ + if (((lwidth % ln_cnt) != 0) && ratio < multiplier) { + ratio = ratio * ratio_scale; + ratio = ratio < (1000 * multiplier) + ? ratio : (1000 * multiplier); + } + pr_debug("ratio = %lld\n", ratio); + + for (tu_size = 32; tu_size <= 64; tu_size++) { + temp = ratio * tu_size; + temp2 = ((temp / multiplier) + 1) * multiplier; + n_err = roundup_u64(temp, multiplier) - temp; + + if (n_err < err) { + err = n_err; + tu_size_desired = tu_size; + } + } + pr_debug("Info: tu_size_desired = %d\n", tu_size_desired); + + tu_size_minus1 = tu_size_desired - 1; + + valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier); + valid_boundary_link /= multiplier; + n_tus = rounddown((lwidth * bpp * multiplier) + / (8 * valid_boundary_link), multiplier) / multiplier; + even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0; + pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n", + valid_boundary_link, n_tus); + + extra_bytes = roundup_u64((n_tus + 1) + * ((valid_boundary_link * multiplier) + - (original_ratio * tu_size_desired)), multiplier); + extra_bytes /= multiplier; + extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp, + multiplier); + extra_pclk_cycles /= multiplier; + extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles + * lclk * multiplier, pclk), multiplier); + extra_pclk_cycles_in_link_clk /= multiplier; + filler_size = roundup_u64((tu_size_desired - valid_boundary_link) + * multiplier, multiplier); + filler_size /= multiplier; + ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier); + + pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n", + extra_pclk_cycles_in_link_clk, extra_bytes); + pr_debug("extra_pclk_cycles_in_link_clk=%d\n", + extra_pclk_cycles_in_link_clk); + pr_debug("filler_size=%d, extra_buffer_margin=%lld\n", + filler_size, extra_buffer_margin); + + delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk) + ? extra_bytes + : extra_pclk_cycles_in_link_clk) + + filler_size + extra_buffer_margin; + resulting_valid = valid_boundary_link; + pr_debug("Info: delay_start_link=%d, filler_size=%d\n", + delay_start_link, filler_size); + pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n", + valid_boundary_link, ratio_by_tu); + + diff_abs = (resulting_valid >= ratio_by_tu) + ? (resulting_valid - ratio_by_tu) + : (ratio_by_tu - resulting_valid); + + if (err != 0 && ((diff_abs > brute_force_threshold) + || (even_distribution_legacy == 0) + || (dp_brute_force == 1))) { + err = multiplier; + for (tu_size = 32; tu_size <= 64; tu_size++) { + for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15; + i_upper_bdry_cnt++) { + for (i_lower_bdry_cnt = 1; + i_lower_bdry_cnt <= 15; + i_lower_bdry_cnt++) { + new_valid_boundary_link = + roundup_u64(ratio + * tu_size, multiplier); + average_valid2 = (i_upper_bdry_cnt + * new_valid_boundary_link + + i_lower_bdry_cnt + * (new_valid_boundary_link + - multiplier)) + / (i_upper_bdry_cnt + + i_lower_bdry_cnt); + n_tus = rounddown_u64(div64_u64(lwidth + * multiplier * multiplier + * (bpp / 8), average_valid2), + multiplier); + n_tus /= multiplier; + n_tus_per_lane + = rounddown(n_tus + * multiplier + / ln_cnt, multiplier); + n_tus_per_lane /= multiplier; + paired_tus = + rounddown((n_tus_per_lane) + * multiplier + / (i_upper_bdry_cnt + + i_lower_bdry_cnt), + multiplier); + paired_tus /= multiplier; + remainder_tus = n_tus_per_lane + - paired_tus + * (i_upper_bdry_cnt + + i_lower_bdry_cnt); + if ((remainder_tus + - i_upper_bdry_cnt) > 0) { + remainder_tus_upper + = i_upper_bdry_cnt; + remainder_tus_lower = + remainder_tus + - i_upper_bdry_cnt; + } else { + remainder_tus_upper + = remainder_tus; + remainder_tus_lower = 0; + } + total_valid = paired_tus + * (i_upper_bdry_cnt + * new_valid_boundary_link + + i_lower_bdry_cnt + * (new_valid_boundary_link + - multiplier)) + + (remainder_tus_upper + * new_valid_boundary_link) + + (remainder_tus_lower + * (new_valid_boundary_link + - multiplier)); + n_err_neg = nn_err_neg = false; + effective_valid + = div_u64(total_valid, + n_tus_per_lane); + n_n_err = (effective_valid + >= (ratio * tu_size)) + ? (effective_valid + - (ratio * tu_size)) + : ((ratio * tu_size) + - effective_valid); + if (effective_valid < (ratio * tu_size)) + nn_err_neg = true; + n_err = (average_valid2 + >= (ratio * tu_size)) + ? (average_valid2 + - (ratio * tu_size)) + : ((ratio * tu_size) + - average_valid2); + if (average_valid2 < (ratio * tu_size)) + n_err_neg = true; + even_distribution = + n_tus % ln_cnt == 0 ? 1 : 0; + diff_abs = + resulting_valid >= ratio_by_tu + ? (resulting_valid + - ratio_by_tu) + : (ratio_by_tu + - resulting_valid); + + resulting_valid_tmp = div64_u64( + (i_upper_bdry_cnt + * new_valid_boundary_link + + i_lower_bdry_cnt + * (new_valid_boundary_link + - multiplier)), + (i_upper_bdry_cnt + + i_lower_bdry_cnt)); + ratio_by_tu_tmp = + original_ratio * tu_size; + ratio_by_tu_tmp /= multiplier; + n_tus_tmp = rounddown_u64( + div64_u64(lwidth + * multiplier * multiplier + * bpp / 8, + resulting_valid_tmp), + multiplier); + n_tus_tmp /= multiplier; + + temp3 = (resulting_valid_tmp + >= (original_ratio * tu_size)) + ? (resulting_valid_tmp + - original_ratio * tu_size) + : (original_ratio * tu_size) + - resulting_valid_tmp; + temp3 = (n_tus_tmp + 1) * temp3; + temp4 = (new_valid_boundary_link + >= (original_ratio * tu_size)) + ? (new_valid_boundary_link + - original_ratio + * tu_size) + : (original_ratio * tu_size) + - new_valid_boundary_link; + temp4 = (i_upper_bdry_cnt + * ln_cnt * temp4); + + temp3 = roundup_u64(temp3, multiplier); + temp4 = roundup_u64(temp4, multiplier); + dp_ctrl_get_extra_req_bytes + (resulting_valid_tmp, + new_valid_boundary_link, + temp3, temp4, + &extra_req_bytes_is_neg, + &result, + (original_ratio * tu_size)); + extra_req_bytes_new_tmp + = div64_ul(result, multiplier); + if ((extra_req_bytes_is_neg) + && (extra_req_bytes_new_tmp + > 1)) + extra_req_bytes_new_tmp + = extra_req_bytes_new_tmp - 1; + if (extra_req_bytes_new_tmp == 0) + extra_req_bytes_new_tmp = 1; + extra_pclk_cycles_tmp = + (u64)(extra_req_bytes_new_tmp + * 8 * multiplier) / bpp; + extra_pclk_cycles_tmp /= multiplier; + + if (extra_pclk_cycles_tmp <= 0) + extra_pclk_cycles_tmp = 1; + extra_pclk_cycles_in_lclk_tmp = + roundup_u64(div64_u64( + extra_pclk_cycles_tmp + * lclk * multiplier, + pclk), multiplier); + extra_pclk_cycles_in_lclk_tmp + /= multiplier; + filler_size_tmp = roundup_u64( + (tu_size * multiplier * + new_valid_boundary_link), + multiplier); + filler_size_tmp /= multiplier; + lower_filler_size_tmp = + filler_size_tmp + 1; + if (extra_req_bytes_is_neg) + temp3 = (extra_req_bytes_new_tmp + > extra_pclk_cycles_in_lclk_tmp + ? extra_pclk_cycles_in_lclk_tmp + : extra_req_bytes_new_tmp); + else + temp3 = (extra_req_bytes_new_tmp + > extra_pclk_cycles_in_lclk_tmp + ? extra_req_bytes_new_tmp : + extra_pclk_cycles_in_lclk_tmp); + + temp4 = lower_filler_size_tmp + + extra_buffer_margin; + if (extra_req_bytes_is_neg) + delay_start_link_tmp + = (temp3 >= temp4) + ? (temp3 - temp4) + : (temp4 - temp3); + else + delay_start_link_tmp + = temp3 + temp4; + + min_hblank_tmp = (int)div64_u64( + roundup_u64( + div64_u64(delay_start_link_tmp + * pclk * multiplier, lclk), + multiplier), multiplier) + + hblank_margin; + + if (((even_distribution == 1) + || ((even_distribution_bf == 0) + && (even_distribution_legacy + == 0))) + && !n_err_neg && !nn_err_neg + && n_n_err < err + && (n_n_err < diff_abs + || (dp_brute_force == 1)) + && (new_valid_boundary_link + - 1) > 0 + && (h_blank >= + (u32)min_hblank_tmp)) { + upper_bdry_cnt = + i_upper_bdry_cnt; + lower_bdry_cnt = + i_lower_bdry_cnt; + err = n_n_err; + boundary_moderation_en = 1; + tu_size_desired = tu_size; + valid_boundary_link = + new_valid_boundary_link; + effective_valid_recorded + = effective_valid; + delay_start_link + = delay_start_link_tmp; + filler_size = filler_size_tmp; + min_hblank = min_hblank_tmp; + n_tus = n_tus_tmp; + even_distribution_bf = 1; + + pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n", + upper_bdry_cnt, + lower_bdry_cnt, err, + tu_size_desired, + valid_boundary_link, + effective_valid); + } + } + } + } + + if (boundary_moderation_en == 1) { + resulting_valid = (u64)(upper_bdry_cnt + *valid_boundary_link + lower_bdry_cnt + * (valid_boundary_link - 1)) + / (upper_bdry_cnt + lower_bdry_cnt); + ratio_by_tu = original_ratio * tu_size_desired; + valid_lower_boundary_link = + (valid_boundary_link / multiplier) - 1; + + tu_size_minus1 = tu_size_desired - 1; + even_distribution_bf = 1; + valid_boundary_link /= multiplier; + pr_debug("Info: Boundary_moderation enabled\n"); + } + } + + min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk + * multiplier, lclk), multiplier)) + / multiplier + hblank_margin; + if (h_blank < (u32)min_hblank) { + pr_debug(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n", + run_idx, h_blank, min_hblank); + } + + if (fifo_empty) { + tu_size_minus1 = 31; + valid_boundary_link = 32; + delay_start_link = 0; + boundary_moderation_en = 0; + } + + pr_debug("tu_size_minus1=%d valid_boundary_link=%d delay_start_link=%d boundary_moderation_en=%d\n upper_boundary_cnt=%d lower_boundary_cnt=%d valid_lower_boundary_link=%d min_hblank=%d\n", + tu_size_minus1, valid_boundary_link, delay_start_link, + boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt, + valid_lower_boundary_link, min_hblank); + + tu_table->valid_boundary_link = valid_boundary_link; + tu_table->delay_start_link = delay_start_link; + tu_table->boundary_moderation_en = boundary_moderation_en; + tu_table->valid_lower_boundary_link = valid_lower_boundary_link; + tu_table->upper_boundary_count = upper_bdry_cnt; + tu_table->lower_boundary_count = lower_bdry_cnt; + tu_table->tu_size_minus1 = tu_size_minus1; +} + +static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl) +{ + u32 dp_tu = 0x0; + u32 valid_boundary = 0x0; + u32 valid_boundary2 = 0x0; + struct dp_vc_tu_mapping_table tu_calc_table; + + dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table); + + dp_tu |= tu_calc_table.tu_size_minus1; + valid_boundary |= tu_calc_table.valid_boundary_link; + valid_boundary |= (tu_calc_table.delay_start_link << 16); + + valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1); + valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16); + valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20); + + if (tu_calc_table.boundary_moderation_en) + valid_boundary2 |= BIT(0); + + pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n", + dp_tu, valid_boundary, valid_boundary2); + + ctrl->catalog->dp_tu = dp_tu; + ctrl->catalog->valid_boundary = valid_boundary; + ctrl->catalog->valid_boundary2 = valid_boundary2; + + ctrl->catalog->update_transfer_unit(ctrl->catalog); +} + +static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + + ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2); + if (ret <= 0) { + pr_err("Link Train timedout\n"); + ret = -EINVAL; + } + + return ret; +} + +static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl, + u32 voltage_level, u32 pre_emphasis_level) +{ + int i; + u8 buf[4]; + u32 max_level_reached = 0; + + if (voltage_level == DP_LINK_VOLTAGE_MAX) { + pr_debug("max. voltage swing level reached %d\n", + voltage_level); + max_level_reached |= BIT(2); + } + + if (pre_emphasis_level == DP_LINK_PRE_EMPHASIS_MAX) { + pr_debug("max. pre-emphasis level reached %d\n", + pre_emphasis_level); + max_level_reached |= BIT(5); + } + + pre_emphasis_level <<= 3; + + for (i = 0; i < 4; i++) + buf[i] = voltage_level | pre_emphasis_level | max_level_reached; + + pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level); + return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4); +} + +static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) +{ + struct dp_link *link = ctrl->link; + + ctrl->catalog->update_vx_px(ctrl->catalog, + link->phy_params.v_level, link->phy_params.p_level); + + return dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level, + link->phy_params.p_level); +} + +static int dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, + u8 pattern) +{ + u8 buf[4]; + + pr_debug("sink: pattern=%x\n", pattern); + + buf[0] = pattern; + return drm_dp_dpcd_write(ctrl->aux->drm_aux, + DP_TRAINING_PATTERN_SET, buf, 1); +} + +static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl, + u8 *link_status) +{ + int ret = 0, len; + u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS; + u32 link_status_read_max_retries = 100; + + while (--link_status_read_max_retries) { + len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, + link_status); + if (len != DP_LINK_STATUS_SIZE) { + pr_err("DP link status read failed, err: %d\n", len); + ret = len; + break; + } + + if (!(link_status[offset] & DP_LINK_STATUS_UPDATED)) + break; + } + + return ret; +} + +static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) +{ + int tries, old_v_level, ret = 0; + u8 link_status[DP_LINK_STATUS_SIZE]; + int const maximum_retries = 5; + + dp_ctrl_state_ctrl(ctrl, 0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + ctrl->catalog->set_pattern(ctrl->catalog, 0x01); + ret = dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE); /* train_1 */ + if (ret <= 0) { + ret = -EINVAL; + return ret; + } + + ret = dp_ctrl_update_vx_px(ctrl); + if (ret <= 0) { + ret = -EINVAL; + return ret; + } + + tries = 0; + old_v_level = ctrl->link->phy_params.v_level; + while (!atomic_read(&ctrl->aborted)) { + drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd); + + ret = dp_ctrl_read_link_status(ctrl, link_status); + if (ret) + break; + + if (drm_dp_clock_recovery_ok(link_status, + ctrl->link->link_params.lane_count)) { + break; + } + + if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) { + pr_err_ratelimited("max v_level reached\n"); + ret = -EAGAIN; + break; + } + + if (old_v_level == ctrl->link->phy_params.v_level) { + tries++; + if (tries >= maximum_retries) { + pr_err("max tries reached\n"); + ret = -ETIMEDOUT; + break; + } + } else { + tries = 0; + old_v_level = ctrl->link->phy_params.v_level; + } + + pr_debug("clock recovery not done, adjusting vx px\n"); + + ctrl->link->adjust_levels(ctrl->link, link_status); + ret = dp_ctrl_update_vx_px(ctrl); + if (ret <= 0) { + ret = -EINVAL; + break; + } + } + + return ret; +} + +static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + + if (!ctrl) + return -EINVAL; + + switch (ctrl->link->link_params.bw_code) { + case DP_LINK_BW_8_1: + ctrl->link->link_params.bw_code = DP_LINK_BW_5_4; + break; + case DP_LINK_BW_5_4: + ctrl->link->link_params.bw_code = DP_LINK_BW_2_7; + break; + case DP_LINK_BW_2_7: + case DP_LINK_BW_1_62: + default: + ctrl->link->link_params.bw_code = DP_LINK_BW_1_62; + break; + }; + + pr_debug("new bw code=0x%x\n", ctrl->link->link_params.bw_code); + + return ret; +} + +static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) +{ + dp_ctrl_train_pattern_set(ctrl, 0); + drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); +} + +static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) +{ + int tries = 0, ret = 0; + char pattern; + int const maximum_retries = 5; + u8 link_status[DP_LINK_STATUS_SIZE]; + + dp_ctrl_state_ctrl(ctrl, 0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + if (drm_dp_tps3_supported(ctrl->panel->dpcd)) + pattern = DP_TRAINING_PATTERN_3; + else + pattern = DP_TRAINING_PATTERN_2; + + ret = dp_ctrl_update_vx_px(ctrl); + if (ret <= 0) { + ret = -EINVAL; + return ret; + } + ctrl->catalog->set_pattern(ctrl->catalog, pattern); + ret = dp_ctrl_train_pattern_set(ctrl, + pattern | DP_RECOVERED_CLOCK_OUT_EN); + if (ret <= 0) { + ret = -EINVAL; + return ret; + } + + do { + drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); + + ret = dp_ctrl_read_link_status(ctrl, link_status); + if (ret) + break; + + if (drm_dp_channel_eq_ok(link_status, + ctrl->link->link_params.lane_count)) + break; + + if (tries > maximum_retries) { + ret = -ETIMEDOUT; + break; + } + tries++; + + ctrl->link->adjust_levels(ctrl->link, link_status); + ret = dp_ctrl_update_vx_px(ctrl); + if (ret <= 0) { + ret = -EINVAL; + break; + } + } while (!atomic_read(&ctrl->aborted)); + + return ret; +} + +static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + u8 encoding = 0x1; + struct drm_dp_link link_info = {0}; + + ctrl->link->phy_params.p_level = 0; + ctrl->link->phy_params.v_level = 0; + + dp_ctrl_config_ctrl(ctrl); + + link_info.num_lanes = ctrl->link->link_params.lane_count; + link_info.rate = drm_dp_bw_code_to_link_rate( + ctrl->link->link_params.bw_code); + link_info.capabilities = ctrl->panel->link_info.capabilities; + + ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info); + if (ret) + goto end; + + ret = drm_dp_dpcd_write(ctrl->aux->drm_aux, + DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1); + if (ret <= 0) { + ret = -EINVAL; + goto end; + } + + ret = dp_ctrl_link_train_1(ctrl); + if (ret) { + pr_err("link training #1 failed\n"); + goto end; + } + + /* print success info as this is a result of user initiated action */ + pr_info("link training #1 successful\n"); + + ret = dp_ctrl_link_training_2(ctrl); + if (ret) { + pr_err("link training #2 failed\n"); + goto end; + } + + /* print success info as this is a result of user initiated action */ + pr_info("link training #2 successful\n"); + +end: + dp_ctrl_state_ctrl(ctrl, 0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + dp_ctrl_clear_training_pattern(ctrl); + return ret; +} + +static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train) +{ + bool mainlink_ready = false; + int ret = 0; + + ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); + + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) + goto end; + + if (!train) + goto send_video; + + /* + * As part of previous calls, DP controller state might have + * transitioned to PUSH_IDLE. In order to start transmitting a link + * training pattern, we have to first to a DP software reset. + */ + ctrl->catalog->reset(ctrl->catalog); + + ret = dp_ctrl_link_train(ctrl); + if (ret) + goto end; + +send_video: + /* + * Set up transfer unit values and set controller state to send + * video. + */ + dp_ctrl_setup_tr_unit(ctrl); + ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO); + + dp_ctrl_wait4video_ready(ctrl); + mainlink_ready = ctrl->catalog->mainlink_ready(ctrl->catalog); + pr_debug("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY"); +end: + return ret; +} + +static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl, + char *name, u32 rate) +{ + u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk; + struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config; + + while (num && strcmp(cfg->clk_name, name)) { + num--; + cfg++; + } + + pr_debug("setting rate=%d on clk=%s\n", rate, name); + + if (num) + cfg->rate = rate; + else + pr_err("%s clock could not be set with rate %d\n", name, rate); +} + +static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + + ctrl->power->set_pixel_clk_parent(ctrl->power); + + dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk", + drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code)); + + dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate); + + ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true); + if (ret) { + pr_err("Unabled to start link clocks\n"); + ret = -EINVAL; + } + + return ret; +} + +static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl) +{ + return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false); +} + +static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, + bool flip, bool multi_func) +{ + struct dp_ctrl_private *ctrl; + struct dp_catalog_ctrl *catalog; + + if (!dp_ctrl) { + pr_err("Invalid input data\n"); + return -EINVAL; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->orientation = flip; + catalog = ctrl->catalog; + + if (!multi_func) { + catalog->usb_reset(ctrl->catalog, flip); + catalog->phy_reset(ctrl->catalog); + } + catalog->enable_irq(ctrl->catalog, true); + + return 0; +} + +/** + * dp_ctrl_host_deinit() - Uninitialize DP controller + * @ctrl: Display Port Driver data + * + * Perform required steps to uninitialize DP controller + * and its resources. + */ +static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + pr_err("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->catalog->enable_irq(ctrl->catalog, false); + + pr_debug("Host deinitialized successfully\n"); +} + +static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) +{ + u8 *dpcd = ctrl->panel->dpcd; + + /* + * For better interop experience, used a fixed NVID=0x8000 + * whenever connected to a VGA dongle downstream. + */ + if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) { + u8 type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_TYPE_MASK; + if (type == DP_DWN_STRM_PORT_TYPE_ANALOG) + return true; + } + + return false; +} + +static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) +{ + int ret = 0; + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + pr_err("Invalid input data\n"); + return -EINVAL; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->power_on || atomic_read(&ctrl->aborted)) { + pr_err("CTRL off, return\n"); + return -EINVAL; + } + + ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); + ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); + + ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; + + do { + if (ret == -EAGAIN) { + /* try with lower link rate */ + dp_ctrl_link_rate_down_shift(ctrl); + + ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); + } + + ctrl->catalog->phy_lane_cfg(ctrl->catalog, + ctrl->orientation, ctrl->link->link_params.lane_count); + + /* + * Disable and re-enable the mainlink clock since the + * link clock might have been adjusted as part of the + * link maintenance. + */ + dp_ctrl_disable_mainlink_clocks(ctrl); + + ret = dp_ctrl_enable_mainlink_clocks(ctrl); + if (ret) + continue; + + dp_ctrl_configure_source_params(ctrl); + + ctrl->catalog->config_msa(ctrl->catalog, + drm_dp_bw_code_to_link_rate( + ctrl->link->link_params.bw_code), + ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl)); + + reinit_completion(&ctrl->idle_comp); + + ret = dp_ctrl_setup_main_link(ctrl, true); + } while (ret == -EAGAIN); + + return ret; +} + +static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl) +{ + int ret = 0; + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + pr_err("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->link->phy_params.phy_test_pattern_sel) { + pr_debug("no test pattern selected by sink\n"); + return; + } + + pr_debug("start\n"); + + ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); + /* + * The global reset will need DP link ralated clocks to be + * running. Add the global reset just before disabling the + * link clocks and core clocks. + */ + ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); + ctrl->dp_ctrl.off(&ctrl->dp_ctrl); + + ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl); + if (ret) + pr_err("failed to enable DP controller\n"); + + pr_debug("end\n"); +} + +static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) +{ + bool success = false; + u32 pattern_sent = 0x0; + u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; + + ctrl->catalog->update_vx_px(ctrl->catalog, + ctrl->link->phy_params.v_level, + ctrl->link->phy_params.p_level); + ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); + ctrl->link->send_test_response(ctrl->link); + + pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog); + pr_debug("pattern_request: %s. pattern_sent: 0x%x\n", + dp_link_get_phy_test_pattern(pattern_requested), + pattern_sent); + + switch (pattern_sent) { + case MR_LINK_TRAINING1: + if (pattern_requested == + DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING) + success = true; + break; + case MR_LINK_SYMBOL_ERM: + if ((pattern_requested == + DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT) + || (pattern_requested == + DP_TEST_PHY_PATTERN_CP2520_PATTERN_1)) + success = true; + break; + case MR_LINK_PRBS7: + if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7) + success = true; + break; + case MR_LINK_CUSTOM80: + if (pattern_requested == + DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN) + success = true; + break; + case MR_LINK_TRAINING4: + if (pattern_requested == + DP_TEST_PHY_PATTERN_CP2520_PATTERN_3) + success = true; + break; + default: + success = false; + break; + } + + pr_debug("%s: %s\n", success ? "success" : "failed", + dp_link_get_phy_test_pattern(pattern_requested)); +} + +static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + pr_err("invalid params\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl->catalog->reset(ctrl->catalog); +} + +static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) +{ + int rc = 0; + struct dp_ctrl_private *ctrl; + u32 rate = 0; + u32 link_train_max_retries = 100; + u32 const phy_cts_pixel_clk_khz = 148500; + + if (!dp_ctrl) { + rc = -EINVAL; + goto end; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + atomic_set(&ctrl->aborted, 0); + rate = ctrl->panel->link_info.rate; + + ctrl->catalog->hpd_config(ctrl->catalog, true); + + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { + pr_debug("using phy test link parameters\n"); + if (!ctrl->panel->pinfo.pixel_clk_khz) + ctrl->pixel_rate = phy_cts_pixel_clk_khz; + } else { + ctrl->link->link_params.bw_code = + drm_dp_link_rate_to_bw_code(rate); + ctrl->link->link_params.lane_count = + ctrl->panel->link_info.num_lanes; + ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; + } + + pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n", + ctrl->link->link_params.bw_code, + ctrl->link->link_params.lane_count, ctrl->pixel_rate); + + ctrl->catalog->phy_lane_cfg(ctrl->catalog, + ctrl->orientation, ctrl->link->link_params.lane_count); + + rc = dp_ctrl_enable_mainlink_clocks(ctrl); + if (rc) + goto end; + + reinit_completion(&ctrl->idle_comp); + + dp_ctrl_configure_source_params(ctrl); + + while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) { + ctrl->catalog->config_msa(ctrl->catalog, + drm_dp_bw_code_to_link_rate( + ctrl->link->link_params.bw_code), + ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl)); + + rc = dp_ctrl_setup_main_link(ctrl, true); + if (!rc) + break; + + /* try with lower link rate */ + dp_ctrl_link_rate_down_shift(ctrl); + + ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); + + dp_ctrl_disable_mainlink_clocks(ctrl); + /* hw recommended delay before re-enabling clocks */ + msleep(20); + + dp_ctrl_enable_mainlink_clocks(ctrl); + } + + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) + dp_ctrl_send_phy_test_pattern(ctrl); + + ctrl->power_on = true; + pr_debug("End-\n"); + +end: + return rc; +} + +static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); + ctrl->catalog->reset(ctrl->catalog); + + /* Make sure DP is disabled before clk disable */ + wmb(); + + dp_ctrl_disable_mainlink_clocks(ctrl); + + ctrl->power_on = false; + pr_debug("DP off done\n"); +} + +static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->catalog->get_interrupt(ctrl->catalog); + + if (ctrl->catalog->isr & DP_CTRL_INTR_READY_FOR_VIDEO) + dp_ctrl_video_ready(ctrl); + + if (ctrl->catalog->isr & DP_CTRL_INTR_IDLE_PATTERN_SENT) + dp_ctrl_idle_patterns_sent(ctrl); +} + +struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in) +{ + int rc = 0; + struct dp_ctrl_private *ctrl; + struct dp_ctrl *dp_ctrl; + + if (!in->dev || !in->panel || !in->aux || + !in->link || !in->catalog) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + ctrl = devm_kzalloc(in->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) { + rc = -ENOMEM; + goto error; + } + + init_completion(&ctrl->idle_comp); + init_completion(&ctrl->video_comp); + + /* in parameters */ + ctrl->parser = in->parser; + ctrl->panel = in->panel; + ctrl->power = in->power; + ctrl->aux = in->aux; + ctrl->link = in->link; + ctrl->catalog = in->catalog; + ctrl->dev = in->dev; + + dp_ctrl = &ctrl->dp_ctrl; + + /* out parameters */ + dp_ctrl->init = dp_ctrl_host_init; + dp_ctrl->deinit = dp_ctrl_host_deinit; + dp_ctrl->on = dp_ctrl_on; + dp_ctrl->off = dp_ctrl_off; + dp_ctrl->push_idle = dp_ctrl_push_idle; + dp_ctrl->abort = dp_ctrl_abort; + dp_ctrl->isr = dp_ctrl_isr; + dp_ctrl->reset = dp_ctrl_reset; + dp_ctrl->link_maintenance = dp_ctrl_link_maintenance; + dp_ctrl->process_phy_test_request = dp_ctrl_process_phy_test_request; + + return dp_ctrl; +error: + return ERR_PTR(rc); +} + +void dp_ctrl_put(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + devm_kfree(ctrl->dev, ctrl); +} diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h new file mode 100644 index 0000000000000000000000000000000000000000..229c779c4027e6718f325c0ad29e3355759d52bb --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_CTRL_H_ +#define _DP_CTRL_H_ + +#include "dp_aux.h" +#include "dp_panel.h" +#include "dp_link.h" +#include "dp_parser.h" +#include "dp_power.h" +#include "dp_catalog.h" + +struct dp_ctrl { + int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func); + void (*deinit)(struct dp_ctrl *dp_ctrl); + int (*on)(struct dp_ctrl *dp_ctrl); + void (*off)(struct dp_ctrl *dp_ctrl); + void (*reset)(struct dp_ctrl *dp_ctrl); + void (*push_idle)(struct dp_ctrl *dp_ctrl); + void (*abort)(struct dp_ctrl *dp_ctrl); + void (*isr)(struct dp_ctrl *dp_ctrl); + bool (*handle_sink_request)(struct dp_ctrl *dp_ctrl); + void (*process_phy_test_request)(struct dp_ctrl *dp_ctrl); + int (*link_maintenance)(struct dp_ctrl *dp_ctrl); +}; + +struct dp_ctrl_in { + struct device *dev; + struct dp_panel *panel; + struct dp_aux *aux; + struct dp_link *link; + struct dp_parser *parser; + struct dp_power *power; + struct dp_catalog_ctrl *catalog; +}; + +struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in); +void dp_ctrl_put(struct dp_ctrl *dp_ctrl); + +#endif /* _DP_CTRL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..054b3c849e65755eb3f5e632c1b602ea4f00084e --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -0,0 +1,1069 @@ +/* + * Copyright (c) 2017-2018, 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) "[drm-dp] %s: " fmt, __func__ + +#include + +#include "dp_parser.h" +#include "dp_power.h" +#include "dp_catalog.h" +#include "dp_aux.h" +#include "dp_ctrl.h" +#include "dp_debug.h" +#include "drm_connector.h" +#include "sde_connector.h" +#include "dp_display.h" + +#define DEBUG_NAME "drm_dp" + +struct dp_debug_private { + struct dentry *root; + u8 *edid; + u32 edid_size; + + u8 *dpcd; + u32 dpcd_size; + + struct dp_usbpd *usbpd; + struct dp_link *link; + struct dp_panel *panel; + struct drm_connector **connector; + struct device *dev; + + struct dp_debug dp_debug; +}; + +static ssize_t dp_debug_write_edid(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + u8 *buf = NULL, *buf_t = NULL, *edid = NULL; + const int char_to_nib = 2; + size_t edid_size = 0; + size_t size = 0, edid_buf_index = 0; + ssize_t rc = count; + + if (!debug) + return -ENODEV; + + if (*ppos) + goto bail; + + size = min_t(size_t, count, SZ_1K); + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto bail; + } + + if (copy_from_user(buf, user_buff, size)) + goto bail; + + edid_size = size / char_to_nib; + buf_t = buf; + + memset(debug->edid, 0, debug->edid_size); + + if (edid_size != debug->edid_size) { + pr_debug("clearing debug edid\n"); + goto bail; + } + + while (edid_size--) { + char t[3]; + int d; + + memcpy(t, buf_t, sizeof(char) * char_to_nib); + t[char_to_nib] = '\0'; + + if (kstrtoint(t, 16, &d)) { + pr_err("kstrtoint error\n"); + goto bail; + } + + if (edid_buf_index < debug->edid_size) + debug->edid[edid_buf_index++] = d; + + buf_t += char_to_nib; + } + + print_hex_dump(KERN_DEBUG, "DEBUG EDID: ", DUMP_PREFIX_NONE, + 16, 1, debug->edid, debug->edid_size, false); + + edid = debug->edid; +bail: + kfree(buf); + debug->panel->set_edid(debug->panel, edid); + return rc; +} + +static ssize_t dp_debug_write_dpcd(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + u8 *buf = NULL, *buf_t = NULL, *dpcd = NULL; + const int char_to_nib = 2; + size_t dpcd_size = 0; + size_t size = 0, dpcd_buf_index = 0; + ssize_t rc = count; + + pr_debug("count=%zu\n", count); + + if (!debug) + return -ENODEV; + + if (*ppos) + goto bail; + + size = min_t(size_t, count, SZ_32); + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto bail; + } + + if (copy_from_user(buf, user_buff, size)) + goto bail; + + dpcd_size = size / char_to_nib; + buf_t = buf; + + memset(debug->dpcd, 0, debug->dpcd_size); + + if (dpcd_size != debug->dpcd_size) { + pr_debug("clearing debug dpcd\n"); + goto bail; + } + + while (dpcd_size--) { + char t[3]; + int d; + + memcpy(t, buf_t, sizeof(char) * char_to_nib); + t[char_to_nib] = '\0'; + + if (kstrtoint(t, 16, &d)) { + pr_err("kstrtoint error\n"); + goto bail; + } + + if (dpcd_buf_index < debug->dpcd_size) + debug->dpcd[dpcd_buf_index++] = d; + + buf_t += char_to_nib; + } + + print_hex_dump(KERN_DEBUG, "DEBUG DPCD: ", DUMP_PREFIX_NONE, + 8, 1, debug->dpcd, debug->dpcd_size, false); + + dpcd = debug->dpcd; +bail: + kfree(buf); + debug->panel->set_dpcd(debug->panel, dpcd); + return rc; +} + +static ssize_t dp_debug_write_hpd(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + int hpd; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &hpd) != 0) + goto end; + + hpd &= 0x3; + + debug->dp_debug.psm_enabled = !!(hpd & BIT(1)); + + debug->usbpd->simulate_connect(debug->usbpd, !!(hpd & BIT(0))); +end: + return len; +} + +static ssize_t dp_debug_write_edid_modes(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_32]; + size_t len = 0; + int hdisplay = 0, vdisplay = 0, vrefresh = 0, aspect_ratio; + + if (!debug) + return -ENODEV; + + if (*ppos) + goto end; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto clear; + + buf[len] = '\0'; + + if (sscanf(buf, "%d %d %d %d", &hdisplay, &vdisplay, &vrefresh, + &aspect_ratio) != 4) + goto clear; + + if (!hdisplay || !vdisplay || !vrefresh) + goto clear; + + debug->dp_debug.debug_en = true; + debug->dp_debug.hdisplay = hdisplay; + debug->dp_debug.vdisplay = vdisplay; + debug->dp_debug.vrefresh = vrefresh; + debug->dp_debug.aspect_ratio = aspect_ratio; + goto end; +clear: + pr_debug("clearing debug modes\n"); + debug->dp_debug.debug_en = false; +end: + return len; +} + +static ssize_t dp_debug_bw_code_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 max_bw_code = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return 0; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &max_bw_code) != 0) + return 0; + + if (!is_link_rate_valid(max_bw_code)) { + pr_err("Unsupported bw code %d\n", max_bw_code); + return len; + } + debug->panel->max_bw_code = max_bw_code; + pr_debug("max_bw_code: %d\n", max_bw_code); + + return len; +} + +static ssize_t dp_debug_tpg_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 tpg_state = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto bail; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &tpg_state) != 0) + goto bail; + + tpg_state &= 0x1; + pr_debug("tpg_state: %d\n", tpg_state); + + if (tpg_state == debug->dp_debug.tpg_state) + goto bail; + + if (debug->panel) + debug->panel->tpg_config(debug->panel, tpg_state); + + debug->dp_debug.tpg_state = tpg_state; +bail: + return len; +} + +static ssize_t dp_debug_read_connected(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len += snprintf(buf, SZ_8, "%d\n", debug->usbpd->hpd_high); + + if (copy_to_user(user_buff, buf, len)) + return -EFAULT; + + *ppos += len; + return len; +} + +static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len) +{ + if (rc >= *max_size) { + pr_err("buffer overflow\n"); + return -EINVAL; + } + *len += rc; + *max_size = SZ_4K - *len; + + return 0; +} + +static ssize_t dp_debug_read_edid_modes(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0, ret = 0, max_size = SZ_4K; + int rc = 0; + struct drm_connector *connector; + struct drm_display_mode *mode; + + if (!debug) { + pr_err("invalid data\n"); + rc = -ENODEV; + goto error; + } + + connector = *debug->connector; + + if (!connector) { + pr_err("connector is NULL\n"); + rc = -EINVAL; + goto error; + } + + if (*ppos) + goto error; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto error; + } + + mutex_lock(&connector->dev->mode_config.mutex); + list_for_each_entry(mode, &connector->modes, head) { + ret = snprintf(buf + len, max_size, + "%s %d %d %d %d %d 0x%x\n", + mode->name, mode->vrefresh, mode->picture_aspect_ratio, + mode->htotal, mode->vtotal, mode->clock, mode->flags); + if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) + break; + } + mutex_unlock(&connector->dev->mode_config.mutex); + + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + rc = -EFAULT; + goto error; + } + + *ppos += len; + kfree(buf); + + return len; +error: + return rc; +} + +static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, + size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0, rc = 0; + u64 lclk = 0; + u32 max_size = SZ_4K; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tdp_panel\n\t\tmax_pclk_khz = %d\n", + debug->panel->max_pclk_khz); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tdrm_dp_link\n\t\trate = %u\n", + debug->panel->link_info.rate); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tnum_lanes = %u\n", + debug->panel->link_info.num_lanes); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tcapabilities = %lu\n", + debug->panel->link_info.capabilities); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tdp_panel_info:\n\t\tactive = %dx%d\n", + debug->panel->pinfo.h_active, + debug->panel->pinfo.v_active); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tback_porch = %dx%d\n", + debug->panel->pinfo.h_back_porch, + debug->panel->pinfo.v_back_porch); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tfront_porch = %dx%d\n", + debug->panel->pinfo.h_front_porch, + debug->panel->pinfo.v_front_porch); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tsync_width = %dx%d\n", + debug->panel->pinfo.h_sync_width, + debug->panel->pinfo.v_sync_width); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tactive_low = %dx%d\n", + debug->panel->pinfo.h_active_low, + debug->panel->pinfo.v_active_low); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\th_skew = %d\n", + debug->panel->pinfo.h_skew); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\trefresh rate = %d\n", + debug->panel->pinfo.refresh_rate); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tpixel clock khz = %d\n", + debug->panel->pinfo.pixel_clk_khz); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tbpp = %d\n", + debug->panel->pinfo.bpp); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + /* Link Information */ + rc = snprintf(buf + len, max_size, + "\tdp_link:\n\t\ttest_requested = %d\n", + debug->link->sink_request); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tlane_count = %d\n", debug->link->link_params.lane_count); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tbw_code = %d\n", debug->link->link_params.bw_code); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + lclk = drm_dp_bw_code_to_link_rate( + debug->link->link_params.bw_code) * 1000; + rc = snprintf(buf + len, max_size, + "\t\tlclk = %lld\n", lclk); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tv_level = %d\n", debug->link->phy_params.v_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\t\tp_level = %d\n", debug->link->phy_params.p_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + if (copy_to_user(user_buff, buf, len)) + goto error; + + *ppos += len; + + kfree(buf); + return len; +error: + kfree(buf); + return -EINVAL; +} + +static ssize_t dp_debug_bw_code_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += snprintf(buf + len, (SZ_4K - len), + "max_bw_code = %d\n", debug->panel->max_bw_code); + + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static ssize_t dp_debug_tpg_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len += snprintf(buf, SZ_8, "%d\n", debug->dp_debug.tpg_state); + + if (copy_to_user(user_buff, buf, len)) + return -EFAULT; + + *ppos += len; + return len; +} + +static ssize_t dp_debug_write_hdr(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct drm_connector *connector; + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct dp_debug_private *debug = file->private_data; + char buf[SZ_1K]; + size_t len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + connector = *debug->connector; + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_1K - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (sscanf(buf, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + &c_state->hdr_meta.hdr_supported, + &c_state->hdr_meta.hdr_state, + &c_state->hdr_meta.eotf, + &c_state->hdr_meta.display_primaries_x[0], + &c_state->hdr_meta.display_primaries_x[1], + &c_state->hdr_meta.display_primaries_x[2], + &c_state->hdr_meta.display_primaries_y[0], + &c_state->hdr_meta.display_primaries_y[1], + &c_state->hdr_meta.display_primaries_y[2], + &c_state->hdr_meta.white_point_x, + &c_state->hdr_meta.white_point_y, + &c_state->hdr_meta.max_luminance, + &c_state->hdr_meta.min_luminance, + &c_state->hdr_meta.max_content_light_level, + &c_state->hdr_meta.max_average_light_level) != 15) { + pr_err("invalid input\n"); + len = -EINVAL; + } + + debug->panel->setup_hdr(debug->panel, &c_state->hdr_meta); +end: + return len; +} + +static ssize_t dp_debug_read_hdr(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0, i; + u32 max_size = SZ_4K; + int rc = 0; + struct drm_connector *connector; + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct drm_msm_ext_hdr_metadata *hdr; + + if (!debug) { + pr_err("invalid data\n"); + rc = -ENODEV; + goto error; + } + + connector = *debug->connector; + + if (!connector) { + pr_err("connector is NULL\n"); + rc = -EINVAL; + goto error; + } + + if (*ppos) + goto error; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto error; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + + hdr = &c_state->hdr_meta; + + rc = snprintf(buf + len, max_size, + "============SINK HDR PARAMETERS===========\n"); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "eotf = %d\n", + connector->hdr_eotf); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "type_one = %d\n", + connector->hdr_metadata_type_one); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "max_luminance = %d\n", + connector->hdr_max_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "avg_luminance = %d\n", + connector->hdr_avg_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "min_luminance = %d\n", + connector->hdr_min_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "============VIDEO HDR PARAMETERS===========\n"); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "hdr_state = %d\n", hdr->hdr_state); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "hdr_supported = %d\n", + hdr->hdr_supported); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "eotf = %d\n", hdr->eotf); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "white_point_x = %d\n", + hdr->white_point_x); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "white_point_y = %d\n", + hdr->white_point_y); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "max_luminance = %d\n", + hdr->max_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "min_luminance = %d\n", + hdr->min_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "max_content_light_level = %d\n", + hdr->max_content_light_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "min_content_light_level = %d\n", + hdr->max_average_light_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + for (i = 0; i < HDR_PRIMARIES_COUNT; i++) { + rc = snprintf(buf + len, max_size, "primaries_x[%d] = %d\n", + i, hdr->display_primaries_x[i]); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "primaries_y[%d] = %d\n", + i, hdr->display_primaries_y[i]); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + } + + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + rc = -EFAULT; + goto error; + } + + *ppos += len; + kfree(buf); + + return len; +error: + return rc; +} + +static const struct file_operations dp_debug_fops = { + .open = simple_open, + .read = dp_debug_read_info, +}; + +static const struct file_operations edid_modes_fops = { + .open = simple_open, + .read = dp_debug_read_edid_modes, + .write = dp_debug_write_edid_modes, +}; + +static const struct file_operations hpd_fops = { + .open = simple_open, + .write = dp_debug_write_hpd, +}; + +static const struct file_operations edid_fops = { + .open = simple_open, + .write = dp_debug_write_edid, +}; + +static const struct file_operations dpcd_fops = { + .open = simple_open, + .write = dp_debug_write_dpcd, +}; + +static const struct file_operations connected_fops = { + .open = simple_open, + .read = dp_debug_read_connected, +}; + +static const struct file_operations bw_code_fops = { + .open = simple_open, + .read = dp_debug_bw_code_read, + .write = dp_debug_bw_code_write, +}; + +static const struct file_operations tpg_fops = { + .open = simple_open, + .read = dp_debug_tpg_read, + .write = dp_debug_tpg_write, +}; + +static const struct file_operations hdr_fops = { + .open = simple_open, + .write = dp_debug_write_hdr, + .read = dp_debug_read_hdr, +}; + +static int dp_debug_init(struct dp_debug *dp_debug) +{ + int rc = 0; + struct dp_debug_private *debug = container_of(dp_debug, + struct dp_debug_private, dp_debug); + struct dentry *dir, *file; + + dir = debugfs_create_dir(DEBUG_NAME, NULL); + if (IS_ERR_OR_NULL(dir)) { + if (!dir) + rc = -EINVAL; + else + rc = PTR_ERR(dir); + pr_err("[%s] debugfs create dir failed, rc = %d\n", + DEBUG_NAME, rc); + goto error; + } + + debug->root = dir; + + file = debugfs_create_file("dp_debug", 0444, dir, + debug, &dp_debug_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs create file failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("edid_modes", 0644, dir, + debug, &edid_modes_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs create edid_modes failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("hpd", 0644, dir, + debug, &hpd_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs hpd failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("connected", 0444, dir, + debug, &connected_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs connected failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("max_bw_code", 0644, dir, + debug, &bw_code_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs max_bw_code failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("edid", 0644, dir, + debug, &edid_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs edid failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("dpcd", 0644, dir, + debug, &dpcd_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs dpcd failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("tpg_ctrl", 0644, dir, + debug, &tpg_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs tpg failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("hdr", 0644, dir, + debug, &hdr_fops); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs hdr failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + return 0; + +error_remove_dir: + if (!file) + rc = -EINVAL; + debugfs_remove_recursive(dir); +error: + return rc; +} + +struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, + struct dp_usbpd *usbpd, struct dp_link *link, + struct drm_connector **connector) +{ + int rc = 0; + struct dp_debug_private *debug; + struct dp_debug *dp_debug; + + if (!dev || !panel || !usbpd || !link) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL); + if (!debug) { + rc = -ENOMEM; + goto error; + } + + debug->edid = devm_kzalloc(dev, SZ_256, GFP_KERNEL); + if (!debug->edid) { + rc = -ENOMEM; + kfree(debug); + goto error; + } + + debug->edid_size = SZ_256; + + debug->dpcd = devm_kzalloc(dev, SZ_16, GFP_KERNEL); + if (!debug->dpcd) { + rc = -ENOMEM; + kfree(debug); + goto error; + } + + debug->dpcd_size = SZ_16; + + debug->dp_debug.debug_en = false; + debug->usbpd = usbpd; + debug->link = link; + debug->panel = panel; + debug->dev = dev; + debug->connector = connector; + + dp_debug = &debug->dp_debug; + dp_debug->vdisplay = 0; + dp_debug->hdisplay = 0; + dp_debug->vrefresh = 0; + + rc = dp_debug_init(dp_debug); + if (rc) { + devm_kfree(dev, debug); + goto error; + } + + return dp_debug; +error: + return ERR_PTR(rc); +} + +static int dp_debug_deinit(struct dp_debug *dp_debug) +{ + struct dp_debug_private *debug; + + if (!dp_debug) + return -EINVAL; + + debug = container_of(dp_debug, struct dp_debug_private, dp_debug); + + debugfs_remove_recursive(debug->root); + + return 0; +} + +void dp_debug_put(struct dp_debug *dp_debug) +{ + struct dp_debug_private *debug; + + if (!dp_debug) + return; + + debug = container_of(dp_debug, struct dp_debug_private, dp_debug); + + dp_debug_deinit(dp_debug); + + devm_kfree(debug->dev, debug->edid); + devm_kfree(debug->dev, debug->dpcd); + devm_kfree(debug->dev, debug); +} diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..3b2d23eab1b8f538ba0fa18495ed6f48e7b53ad5 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, 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 _DP_DEBUG_H_ +#define _DP_DEBUG_H_ + +#include "dp_panel.h" +#include "dp_link.h" +#include "dp_usbpd.h" + +/** + * struct dp_debug + * @debug_en: specifies whether debug mode enabled + * @vdisplay: used to filter out vdisplay value + * @hdisplay: used to filter out hdisplay value + * @vrefresh: used to filter out vrefresh value + * @tpg_state: specifies whether tpg feature is enabled + */ +struct dp_debug { + bool debug_en; + bool psm_enabled; + int aspect_ratio; + int vdisplay; + int hdisplay; + int vrefresh; + bool tpg_state; +}; + +/** + * dp_debug_get() - configure and get the DisplayPlot debug module data + * + * @dev: device instance of the caller + * @panel: instance of panel module + * @usbpd: instance of usbpd module + * @link: instance of link module + * @connector: double pointer to display connector + * return: pointer to allocated debug module data + * + * This function sets up the debug module and provides a way + * for debugfs input to be communicated with existing modules + */ +struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, + struct dp_usbpd *usbpd, struct dp_link *link, + struct drm_connector **connector); +/** + * dp_debug_put() + * + * Cleans up dp_debug instance + * + * @dp_debug: instance of dp_debug + */ +void dp_debug_put(struct dp_debug *dp_debug); +#endif /* _DP_DEBUG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c new file mode 100644 index 0000000000000000000000000000000000000000..96d4c9c93e9ff321962896b0a2bd05dbc19bdd58 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -0,0 +1,1463 @@ +/* + * Copyright (c) 2017-2018, 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) "[drm-dp] %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include + +#include "sde_connector.h" + +#include "msm_drv.h" +#include "dp_usbpd.h" +#include "dp_parser.h" +#include "dp_power.h" +#include "dp_catalog.h" +#include "dp_aux.h" +#include "dp_link.h" +#include "dp_panel.h" +#include "dp_ctrl.h" +#include "dp_audio.h" +#include "dp_display.h" +#include "sde_hdcp.h" +#include "dp_debug.h" + +static struct dp_display *g_dp_display; +#define HPD_STRING_SIZE 30 + +struct dp_hdcp { + void *data; + struct sde_hdcp_ops *ops; + + void *hdcp1; + void *hdcp2; + + int enc_lvl; + + bool auth_state; + bool hdcp1_present; + bool hdcp2_present; + bool feature_enabled; +}; + +struct dp_display_private { + char *name; + int irq; + + /* state variables */ + bool core_initialized; + bool power_on; + bool audio_supported; + + struct platform_device *pdev; + struct dentry *root; + struct completion notification_comp; + + struct dp_usbpd *usbpd; + struct dp_parser *parser; + struct dp_power *power; + struct dp_catalog *catalog; + struct dp_aux *aux; + struct dp_link *link; + struct dp_panel *panel; + struct dp_ctrl *ctrl; + struct dp_audio *audio; + struct dp_debug *debug; + + struct dp_hdcp hdcp; + + struct dp_usbpd_cb usbpd_cb; + struct dp_display_mode mode; + struct dp_display dp_display; + struct msm_drm_private *priv; + + struct workqueue_struct *wq; + struct delayed_work hdcp_cb_work; + struct delayed_work connect_work; + struct work_struct attention_work; + struct mutex hdcp_mutex; + struct mutex session_lock; + int hdcp_status; + unsigned long audio_status; +}; + +static const struct of_device_id dp_dt_match[] = { + {.compatible = "qcom,dp-display"}, + {} +}; + +static bool dp_display_framework_ready(struct dp_display_private *dp) +{ + return dp->dp_display.post_open ? false : true; +} + +static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp) +{ + return dp->hdcp.feature_enabled && + (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) && + dp->hdcp.ops; +} + +static irqreturn_t dp_display_irq(int irq, void *dev_id) +{ + struct dp_display_private *dp = dev_id; + + if (!dp) { + pr_err("invalid data\n"); + return IRQ_NONE; + } + + /* DP controller isr */ + dp->ctrl->isr(dp->ctrl); + + /* DP aux isr */ + dp->aux->isr(dp->aux); + + /* HDCP isr */ + if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) { + if (dp->hdcp.ops->isr(dp->hdcp.data)) + pr_err("dp_hdcp_isr failed\n"); + } + + return IRQ_HANDLED; +} + +static void dp_display_hdcp_cb_work(struct work_struct *work) +{ + struct dp_display_private *dp; + struct delayed_work *dw = to_delayed_work(work); + struct sde_hdcp_ops *ops; + int rc = 0; + u32 hdcp_auth_state; + + dp = container_of(dw, struct dp_display_private, hdcp_cb_work); + + rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl); + if (rc >= 0) { + hdcp_auth_state = (rc >> 20) & 0x3; + pr_debug("hdcp auth state %d\n", hdcp_auth_state); + } + + ops = dp->hdcp.ops; + + switch (dp->hdcp_status) { + case HDCP_STATE_AUTHENTICATING: + pr_debug("start authenticaton\n"); + + if (dp->hdcp.ops && dp->hdcp.ops->authenticate) + rc = dp->hdcp.ops->authenticate(dp->hdcp.data); + + break; + case HDCP_STATE_AUTHENTICATED: + pr_debug("hdcp authenticated\n"); + dp->hdcp.auth_state = true; + break; + case HDCP_STATE_AUTH_FAIL: + dp->hdcp.auth_state = false; + + if (dp->power_on) { + pr_debug("Reauthenticating\n"); + if (ops && ops->reauthenticate) { + rc = ops->reauthenticate(dp->hdcp.data); + if (rc) + pr_err("reauth failed rc=%d\n", rc); + } + } else { + pr_debug("not reauthenticating, cable disconnected\n"); + } + + break; + default: + break; + } +} + +static void dp_display_notify_hdcp_status_cb(void *ptr, + enum sde_hdcp_states status) +{ + struct dp_display_private *dp = ptr; + + if (!dp) { + pr_err("invalid input\n"); + return; + } + + dp->hdcp_status = status; + + if (dp->dp_display.is_connected) + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4); +} + +static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp) +{ + if (dp->wq) + destroy_workqueue(dp->wq); +} + +static void dp_display_update_hdcp_info(struct dp_display_private *dp) +{ + void *fd = NULL; + struct sde_hdcp_ops *ops = NULL; + + if (!dp) { + pr_err("invalid input\n"); + return; + } + + if (!dp->hdcp.feature_enabled) { + pr_debug("feature not enabled\n"); + return; + } + + fd = dp->hdcp.hdcp2; + if (fd) + ops = sde_dp_hdcp2p2_start(fd); + + if (ops && ops->feature_supported) + dp->hdcp.hdcp2_present = ops->feature_supported(fd); + else + dp->hdcp.hdcp2_present = false; + + pr_debug("hdcp2p2: %s\n", + dp->hdcp.hdcp2_present ? "supported" : "not supported"); + + if (!dp->hdcp.hdcp2_present) { + dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app(); + + if (dp->hdcp.hdcp1_present) { + fd = dp->hdcp.hdcp1; + ops = sde_hdcp_1x_start(fd); + } + } + + pr_debug("hdcp1x: %s\n", + dp->hdcp.hdcp1_present ? "supported" : "not supported"); + + if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) { + dp->hdcp.data = fd; + dp->hdcp.ops = ops; + } else { + dp->hdcp.data = NULL; + dp->hdcp.ops = NULL; + } +} + +static void dp_display_deinitialize_hdcp(struct dp_display_private *dp) +{ + if (!dp) { + pr_err("invalid input\n"); + return; + } + + sde_dp_hdcp2p2_deinit(dp->hdcp.data); + dp_display_destroy_hdcp_workqueue(dp); + if (&dp->hdcp_mutex) + mutex_destroy(&dp->hdcp_mutex); +} + +static int dp_display_initialize_hdcp(struct dp_display_private *dp) +{ + struct sde_hdcp_init_data hdcp_init_data; + int rc = 0; + + if (!dp) { + pr_err("invalid input\n"); + return -EINVAL; + } + + mutex_init(&dp->hdcp_mutex); + + hdcp_init_data.client_id = HDCP_CLIENT_DP; + hdcp_init_data.drm_aux = dp->aux->drm_aux; + hdcp_init_data.cb_data = (void *)dp; + hdcp_init_data.workq = dp->wq; + hdcp_init_data.mutex = &dp->hdcp_mutex; + hdcp_init_data.sec_access = true; + hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb; + hdcp_init_data.core_io = &dp->parser->io.ctrl_io; + hdcp_init_data.dp_ahb = &dp->parser->io.dp_ahb; + hdcp_init_data.dp_aux = &dp->parser->io.dp_aux; + hdcp_init_data.dp_link = &dp->parser->io.dp_link; + hdcp_init_data.dp_p0 = &dp->parser->io.dp_p0; + hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io; + hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io; + hdcp_init_data.revision = &dp->panel->link_info.revision; + + dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data); + if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) { + pr_err("Error initializing HDCP 1.x\n"); + rc = -EINVAL; + goto error; + } + + pr_debug("HDCP 1.3 initialized\n"); + + dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data); + if (IS_ERR_OR_NULL(dp->hdcp.hdcp2)) { + pr_err("Error initializing HDCP 2.x\n"); + rc = -EINVAL; + goto error; + } + + pr_debug("HDCP 2.2 initialized\n"); + + dp->hdcp.feature_enabled = true; + + return 0; +error: + dp_display_deinitialize_hdcp(dp); + return rc; +} + +static int dp_display_bind(struct device *dev, struct device *master, + void *data) +{ + int rc = 0; + struct dp_display_private *dp; + struct drm_device *drm; + struct platform_device *pdev = to_platform_device(dev); + + if (!dev || !pdev || !master) { + pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n", + dev, pdev, master); + rc = -EINVAL; + goto end; + } + + drm = dev_get_drvdata(master); + dp = platform_get_drvdata(pdev); + if (!drm || !dp) { + pr_err("invalid param(s), drm %pK, dp %pK\n", + drm, dp); + rc = -EINVAL; + goto end; + } + + dp->dp_display.drm_dev = drm; + dp->priv = drm->dev_private; +end: + return rc; +} + +static void dp_display_unbind(struct device *dev, struct device *master, + void *data) +{ + struct dp_display_private *dp; + struct platform_device *pdev = to_platform_device(dev); + + if (!dev || !pdev) { + pr_err("invalid param(s)\n"); + return; + } + + dp = platform_get_drvdata(pdev); + if (!dp) { + pr_err("Invalid params\n"); + return; + } + + (void)dp->power->power_client_deinit(dp->power); + (void)dp->aux->drm_aux_deregister(dp->aux); + dp_display_deinitialize_hdcp(dp); +} + +static const struct component_ops dp_display_comp_ops = { + .bind = dp_display_bind, + .unbind = dp_display_unbind, +}; + +static bool dp_display_is_ds_bridge(struct dp_panel *panel) +{ + return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_PRESENT); +} + +static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) +{ + return dp_display_is_ds_bridge(dp->panel) && + (dp->link->sink_count.count == 0); +} + +static void dp_display_send_hpd_event(struct dp_display_private *dp) +{ + struct drm_device *dev = NULL; + struct drm_connector *connector; + char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE], + bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE]; + char *envp[5]; + + connector = dp->dp_display.connector; + + if (!connector) { + pr_err("connector not set\n"); + return; + } + + connector->status = connector->funcs->detect(connector, false); + + dev = dp->dp_display.connector->dev; + + snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name); + snprintf(status, HPD_STRING_SIZE, "status=%s", + drm_get_connector_status_name(connector->status)); + snprintf(bpp, HPD_STRING_SIZE, "bpp=%d", + dp_link_bit_depth_to_bpp( + dp->link->test_video.test_bit_depth)); + snprintf(pattern, HPD_STRING_SIZE, "pattern=%d", + dp->link->test_video.test_video_pattern); + + pr_debug("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern); + envp[0] = name; + envp[1] = status; + envp[2] = bpp; + envp[3] = pattern; + envp[4] = NULL; + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, + envp); +} + +static void dp_display_post_open(struct dp_display *dp_display) +{ + struct drm_connector *connector; + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + if (IS_ERR_OR_NULL(dp)) { + pr_err("invalid params\n"); + return; + } + + connector = dp->dp_display.connector; + + if (!connector) { + pr_err("connector not set\n"); + return; + } + + /* if cable is already connected, send notification */ + if (dp->usbpd->hpd_high) + queue_delayed_work(dp->wq, &dp->connect_work, HZ * 10); + else + dp_display->post_open = NULL; +} + +static int dp_display_send_hpd_notification(struct dp_display_private *dp, + bool hpd) +{ + u32 timeout_sec; + + dp->dp_display.is_connected = hpd; + + if (dp_display_framework_ready(dp)) + timeout_sec = 5; + else + timeout_sec = 10; + + reinit_completion(&dp->notification_comp); + dp_display_send_hpd_event(dp); + + if (!wait_for_completion_timeout(&dp->notification_comp, + HZ * timeout_sec)) { + pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); + return -EINVAL; + } + + return 0; +} + +static int dp_display_process_hpd_high(struct dp_display_private *dp) +{ + int rc = 0; + struct edid *edid; + + dp->aux->init(dp->aux, dp->parser->aux_cfg); + + if (dp->debug->psm_enabled) { + dp->link->psm_config(dp->link, &dp->panel->link_info, false); + dp->debug->psm_enabled = false; + } + + if (!dp->dp_display.connector) + return 0; + + rc = dp->panel->read_sink_caps(dp->panel, + dp->dp_display.connector, dp->usbpd->multi_func); + if (rc) { + /* + * ETIMEDOUT --> cable may have been removed + * ENOTCONN --> no downstream device connected + */ + if (rc == -ETIMEDOUT || rc == -ENOTCONN) + goto end; + else + goto notify; + } + + edid = dp->panel->edid_ctrl->edid; + + dp->audio_supported = drm_detect_monitor_audio(edid); + + dp->link->process_request(dp->link); + dp->panel->handle_sink_request(dp->panel); + + dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz; +notify: + dp_display_send_hpd_notification(dp, true); + +end: + return rc; +} + +static void dp_display_host_init(struct dp_display_private *dp) +{ + bool flip = false; + + if (dp->core_initialized) { + pr_debug("DP core already initialized\n"); + return; + } + + if (dp->usbpd->orientation == ORIENTATION_CC2) + flip = true; + + dp->power->init(dp->power, flip); + dp->ctrl->init(dp->ctrl, flip, dp->usbpd->multi_func); + enable_irq(dp->irq); + dp->core_initialized = true; +} + +static void dp_display_host_deinit(struct dp_display_private *dp) +{ + if (!dp->core_initialized) { + pr_debug("DP core already off\n"); + return; + } + + dp->ctrl->deinit(dp->ctrl); + dp->power->deinit(dp->power); + disable_irq(dp->irq); + dp->core_initialized = false; +} + +static int dp_display_process_hpd_low(struct dp_display_private *dp) +{ + int rc = 0; + + if (!dp->dp_display.is_connected) { + pr_debug("HPD already off\n"); + return 0; + } + + if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + + if (dp->audio_supported) + dp->audio->off(dp->audio); + + dp->audio_status = -ENODEV; + + rc = dp_display_send_hpd_notification(dp, false); + + dp->panel->video_test = false; + + return rc; +} + +static int dp_display_usbpd_configure_cb(struct device *dev) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dev) { + pr_err("invalid dev\n"); + rc = -EINVAL; + goto end; + } + + dp = dev_get_drvdata(dev); + if (!dp) { + pr_err("no driver data found\n"); + rc = -ENODEV; + goto end; + } + + dp_display_host_init(dp); + + /* check for hpd high and framework ready */ + if (dp->usbpd->hpd_high && dp_display_framework_ready(dp)) + queue_delayed_work(dp->wq, &dp->connect_work, 0); +end: + return rc; +} + +static void dp_display_clean(struct dp_display_private *dp) +{ + if (dp_display_is_hdcp_enabled(dp)) { + dp->hdcp_status = HDCP_STATE_INACTIVE; + + cancel_delayed_work_sync(&dp->hdcp_cb_work); + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + } + + dp->ctrl->push_idle(dp->ctrl); + dp->ctrl->off(dp->ctrl); + dp->panel->deinit(dp->panel); + dp->aux->deinit(dp->aux); + dp->power_on = false; +} + +static int dp_display_handle_disconnect(struct dp_display_private *dp) +{ + int rc; + + rc = dp_display_process_hpd_low(dp); + + mutex_lock(&dp->session_lock); + if (rc && dp->power_on) + dp_display_clean(dp); + + if (!dp->usbpd->alt_mode_cfg_done) + dp_display_host_deinit(dp); + + mutex_unlock(&dp->session_lock); + + return rc; +} + +static int dp_display_usbpd_disconnect_cb(struct device *dev) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dev) { + pr_err("invalid dev\n"); + rc = -EINVAL; + goto end; + } + + dp = dev_get_drvdata(dev); + if (!dp) { + pr_err("no driver data found\n"); + rc = -ENODEV; + goto end; + } + + /* + * In case cable/dongle is disconnected during adb shell stop, + * reset psm_enabled flag to false since it is no more needed + */ + if (dp->dp_display.post_open) + dp->debug->psm_enabled = false; + + if (dp->debug->psm_enabled) + dp->link->psm_config(dp->link, &dp->panel->link_info, true); + + /* cancel any pending request */ + dp->ctrl->abort(dp->ctrl); + dp->aux->abort(dp->aux); + + /* wait for idle state */ + cancel_delayed_work(&dp->connect_work); + flush_workqueue(dp->wq); + + dp_display_handle_disconnect(dp); +end: + return rc; +} + +static void dp_display_handle_maintenance_req(struct dp_display_private *dp) +{ + mutex_lock(&dp->audio->ops_lock); + + if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status)) + dp->audio->off(dp->audio); + + dp->ctrl->link_maintenance(dp->ctrl); + + if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status)) + dp->audio_status = dp->audio->on(dp->audio); + + mutex_unlock(&dp->audio->ops_lock); +} + +static void dp_display_attention_work(struct work_struct *work) +{ + struct dp_display_private *dp = container_of(work, + struct dp_display_private, attention_work); + + if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) { + if (!dp->hdcp.ops->cp_irq(dp->hdcp.data)) + return; + } + + if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) { + dp_display_handle_disconnect(dp); + + if (dp_display_is_sink_count_zero(dp)) { + pr_debug("sink count is zero, nothing to do\n"); + return; + } + + queue_delayed_work(dp->wq, &dp->connect_work, 0); + return; + } + + if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { + dp_display_handle_disconnect(dp); + + dp->panel->video_test = true; + dp_display_send_hpd_notification(dp, true); + dp->link->send_test_response(dp->link); + + return; + } + + if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { + dp->ctrl->process_phy_test_request(dp->ctrl); + return; + } + + if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) { + dp_display_handle_maintenance_req(dp); + return; + } + + if (dp->link->sink_request & DP_TEST_LINK_TRAINING) { + dp->link->send_test_response(dp->link); + dp_display_handle_maintenance_req(dp); + return; + } +} + +static int dp_display_usbpd_attention_cb(struct device *dev) +{ + struct dp_display_private *dp; + + if (!dev) { + pr_err("invalid dev\n"); + return -EINVAL; + } + + dp = dev_get_drvdata(dev); + if (!dp) { + pr_err("no driver data found\n"); + return -ENODEV; + } + + if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high && + dp->power_on) { + dp->link->process_request(dp->link); + queue_work(dp->wq, &dp->attention_work); + } else if (dp->usbpd->hpd_high) { + queue_delayed_work(dp->wq, &dp->connect_work, 0); + } else { + /* cancel any pending request */ + dp->ctrl->abort(dp->ctrl); + dp->aux->abort(dp->aux); + + /* wait for idle state */ + cancel_delayed_work(&dp->connect_work); + flush_workqueue(dp->wq); + + dp_display_handle_disconnect(dp); + } + + return 0; +} + +static void dp_display_connect_work(struct work_struct *work) +{ + struct delayed_work *dw = to_delayed_work(work); + struct dp_display_private *dp = container_of(dw, + struct dp_display_private, connect_work); + + if (dp->dp_display.is_connected) { + pr_debug("HPD already on\n"); + return; + } + + dp_display_process_hpd_high(dp); +} + +static void dp_display_deinit_sub_modules(struct dp_display_private *dp) +{ + dp_audio_put(dp->audio); + dp_ctrl_put(dp->ctrl); + dp_link_put(dp->link); + dp_panel_put(dp->panel); + dp_aux_put(dp->aux); + dp_power_put(dp->power); + dp_catalog_put(dp->catalog); + dp_parser_put(dp->parser); + dp_usbpd_put(dp->usbpd); + mutex_destroy(&dp->session_lock); + dp_debug_put(dp->debug); +} + +static int dp_init_sub_modules(struct dp_display_private *dp) +{ + int rc = 0; + struct device *dev = &dp->pdev->dev; + struct dp_usbpd_cb *cb = &dp->usbpd_cb; + struct dp_ctrl_in ctrl_in = { + .dev = dev, + }; + struct dp_panel_in panel_in = { + .dev = dev, + }; + + mutex_init(&dp->session_lock); + + dp->parser = dp_parser_get(dp->pdev); + if (IS_ERR(dp->parser)) { + rc = PTR_ERR(dp->parser); + pr_err("failed to initialize parser, rc = %d\n", rc); + dp->parser = NULL; + goto error; + } + + rc = dp->parser->parse(dp->parser); + if (rc) { + pr_err("device tree parsing failed\n"); + goto error_catalog; + } + + dp->catalog = dp_catalog_get(dev, &dp->parser->io); + if (IS_ERR(dp->catalog)) { + rc = PTR_ERR(dp->catalog); + pr_err("failed to initialize catalog, rc = %d\n", rc); + dp->catalog = NULL; + goto error_catalog; + } + + dp->power = dp_power_get(dp->parser); + if (IS_ERR(dp->power)) { + rc = PTR_ERR(dp->power); + pr_err("failed to initialize power, rc = %d\n", rc); + dp->power = NULL; + goto error_power; + } + + rc = dp->power->power_client_init(dp->power, &dp->priv->phandle); + if (rc) { + pr_err("Power client create failed\n"); + goto error_aux; + } + + dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg); + if (IS_ERR(dp->aux)) { + rc = PTR_ERR(dp->aux); + pr_err("failed to initialize aux, rc = %d\n", rc); + dp->aux = NULL; + goto error_aux; + } + + rc = dp->aux->drm_aux_register(dp->aux); + if (rc) { + pr_err("DRM DP AUX register failed\n"); + goto error_link; + } + + dp->link = dp_link_get(dev, dp->aux); + if (IS_ERR(dp->link)) { + rc = PTR_ERR(dp->link); + pr_err("failed to initialize link, rc = %d\n", rc); + dp->link = NULL; + goto error_link; + } + + panel_in.aux = dp->aux; + panel_in.catalog = &dp->catalog->panel; + panel_in.link = dp->link; + + dp->panel = dp_panel_get(&panel_in); + if (IS_ERR(dp->panel)) { + rc = PTR_ERR(dp->panel); + pr_err("failed to initialize panel, rc = %d\n", rc); + dp->panel = NULL; + goto error_panel; + } + + ctrl_in.link = dp->link; + ctrl_in.panel = dp->panel; + ctrl_in.aux = dp->aux; + ctrl_in.power = dp->power; + ctrl_in.catalog = &dp->catalog->ctrl; + ctrl_in.parser = dp->parser; + + dp->ctrl = dp_ctrl_get(&ctrl_in); + if (IS_ERR(dp->ctrl)) { + rc = PTR_ERR(dp->ctrl); + pr_err("failed to initialize ctrl, rc = %d\n", rc); + dp->ctrl = NULL; + goto error_ctrl; + } + + dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio); + if (IS_ERR(dp->audio)) { + rc = PTR_ERR(dp->audio); + pr_err("failed to initialize audio, rc = %d\n", rc); + dp->audio = NULL; + goto error_audio; + } + + cb->configure = dp_display_usbpd_configure_cb; + cb->disconnect = dp_display_usbpd_disconnect_cb; + cb->attention = dp_display_usbpd_attention_cb; + + dp->usbpd = dp_usbpd_get(dev, cb); + if (IS_ERR(dp->usbpd)) { + rc = PTR_ERR(dp->usbpd); + pr_err("failed to initialize usbpd, rc = %d\n", rc); + dp->usbpd = NULL; + goto error_usbpd; + } + + dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, + dp->link, &dp->dp_display.connector); + if (IS_ERR(dp->debug)) { + rc = PTR_ERR(dp->debug); + pr_err("failed to initialize debug, rc = %d\n", rc); + dp->debug = NULL; + goto error_debug; + } + + return rc; +error_debug: + dp_usbpd_put(dp->usbpd); +error_usbpd: + dp_audio_put(dp->audio); +error_audio: + dp_ctrl_put(dp->ctrl); +error_ctrl: + dp_panel_put(dp->panel); +error_panel: + dp_link_put(dp->link); +error_link: + dp_aux_put(dp->aux); +error_aux: + dp_power_put(dp->power); +error_power: + dp_catalog_put(dp->catalog); +error_catalog: + dp_parser_put(dp->parser); +error: + mutex_destroy(&dp->session_lock); + return rc; +} + +static void dp_display_post_init(struct dp_display *dp_display) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + if (IS_ERR_OR_NULL(dp)) { + pr_err("invalid params\n"); + rc = -EINVAL; + goto end; + } + + rc = dp_init_sub_modules(dp); + if (rc) + goto end; + + dp_display_initialize_hdcp(dp); + + dp_display->post_init = NULL; +end: + pr_debug("%s\n", rc ? "failed" : "success"); +} + +static int dp_display_set_mode(struct dp_display *dp_display, + struct dp_display_mode *mode) +{ + const u32 num_components = 3, default_bpp = 24; + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + mode->timing.bpp = + dp_display->connector->display_info.bpc * num_components; + if (!mode->timing.bpp) + mode->timing.bpp = default_bpp; + + mode->timing.bpp = dp->panel->get_mode_bpp(dp->panel, + mode->timing.bpp, mode->timing.pixel_clk_khz); + + dp->panel->pinfo = mode->timing; + dp->panel->init(dp->panel); + mutex_unlock(&dp->session_lock); + + return 0; +} + +static int dp_display_prepare(struct dp_display *dp) +{ + return 0; +} + +static int dp_display_enable(struct dp_display *dp_display) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + if (dp->power_on) { + pr_debug("Link already setup, return\n"); + goto end; + } + + dp->aux->init(dp->aux, dp->parser->aux_cfg); + + rc = dp->ctrl->on(dp->ctrl); + + if (dp->debug->tpg_state) + dp->panel->tpg_config(dp->panel, true); + + if (!rc) + dp->power_on = true; +end: + mutex_unlock(&dp->session_lock); + return rc; +} + +static int dp_display_post_enable(struct dp_display *dp_display) +{ + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + if (!dp->power_on) { + pr_debug("Link not setup, return\n"); + goto end; + } + + dp->panel->spd_config(dp->panel); + + if (dp->audio_supported) { + dp->audio->bw_code = dp->link->link_params.bw_code; + dp->audio->lane_count = dp->link->link_params.lane_count; + dp->audio_status = dp->audio->on(dp->audio); + } + + dp_display_update_hdcp_info(dp); + + if (dp_display_is_hdcp_enabled(dp)) { + cancel_delayed_work_sync(&dp->hdcp_cb_work); + + dp->hdcp_status = HDCP_STATE_AUTHENTICATING; + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2); + } + + dp->panel->setup_hdr(dp->panel, NULL); +end: + /* clear framework event notifier */ + dp_display->post_open = NULL; + + complete_all(&dp->notification_comp); + mutex_unlock(&dp->session_lock); + return 0; +} + +static int dp_display_pre_disable(struct dp_display *dp_display) +{ + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + if (!dp->power_on) { + pr_debug("Link already powered off, return\n"); + goto end; + } + + if (dp_display_is_hdcp_enabled(dp)) { + dp->hdcp_status = HDCP_STATE_INACTIVE; + + cancel_delayed_work_sync(&dp->hdcp_cb_work); + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + } + + if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) { + if (dp->audio_supported) + dp->audio->off(dp->audio); + + dp->link->psm_config(dp->link, &dp->panel->link_info, true); + dp->debug->psm_enabled = true; + } + + dp->ctrl->push_idle(dp->ctrl); +end: + mutex_unlock(&dp->session_lock); + return 0; +} + +static int dp_display_disable(struct dp_display *dp_display) +{ + struct dp_display_private *dp; + struct drm_connector *connector; + struct sde_connector_state *c_state; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + connector = dp->dp_display.connector; + c_state = to_sde_connector_state(connector->state); + + mutex_lock(&dp->session_lock); + + if (!dp->power_on || !dp->core_initialized) { + pr_debug("Link already powered off, return\n"); + goto end; + } + + dp->ctrl->off(dp->ctrl); + dp->panel->deinit(dp->panel); + dp->aux->deinit(dp->aux); + + connector->hdr_eotf = 0; + connector->hdr_metadata_type_one = 0; + connector->hdr_max_luminance = 0; + connector->hdr_avg_luminance = 0; + connector->hdr_min_luminance = 0; + + memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); + + /* + * In case of framework reboot, the DP off sequence is executed without + * any notification from driver. Initialize post_open callback to notify + * DP connection once framework restarts. + */ + if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) { + dp_display->post_open = dp_display_post_open; + dp->dp_display.is_connected = false; + } + dp->power_on = false; + +end: + complete_all(&dp->notification_comp); + mutex_unlock(&dp->session_lock); + return 0; +} + +static int dp_request_irq(struct dp_display *dp_display) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0); + if (dp->irq < 0) { + rc = dp->irq; + pr_err("failed to get irq: %d\n", rc); + return rc; + } + + rc = devm_request_irq(&dp->pdev->dev, dp->irq, dp_display_irq, + IRQF_TRIGGER_HIGH, "dp_display_isr", dp); + if (rc < 0) { + pr_err("failed to request IRQ%u: %d\n", + dp->irq, rc); + return rc; + } + disable_irq(dp->irq); + + return 0; +} + +static struct dp_debug *dp_get_debug(struct dp_display *dp_display) +{ + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return ERR_PTR(-EINVAL); + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + return dp->debug; +} + +static int dp_display_unprepare(struct dp_display *dp) +{ + return 0; +} + +static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz) +{ + const u32 num_components = 3, default_bpp = 24; + struct dp_display_private *dp_display; + struct drm_dp_link *link_info; + u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; + + if (!dp || !mode_pclk_khz || !dp->connector) { + pr_err("invalid params\n"); + return -EINVAL; + } + + dp_display = container_of(dp, struct dp_display_private, dp_display); + link_info = &dp_display->panel->link_info; + + mode_bpp = dp->connector->display_info.bpc * num_components; + if (!mode_bpp) + mode_bpp = default_bpp; + + mode_bpp = dp_display->panel->get_mode_bpp(dp_display->panel, + mode_bpp, mode_pclk_khz); + + mode_rate_khz = mode_pclk_khz * mode_bpp; + supported_rate_khz = link_info->num_lanes * link_info->rate * 8; + + if (mode_rate_khz > supported_rate_khz) + return MODE_BAD; + + return MODE_OK; +} + +static int dp_display_get_modes(struct dp_display *dp, + struct dp_display_mode *dp_mode) +{ + struct dp_display_private *dp_display; + int ret = 0; + + if (!dp || !dp->connector) { + pr_err("invalid params\n"); + return 0; + } + + dp_display = container_of(dp, struct dp_display_private, dp_display); + + ret = dp_display->panel->get_modes(dp_display->panel, + dp->connector, dp_mode); + if (dp_mode->timing.pixel_clk_khz) + dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz; + return ret; +} + +static int dp_display_config_hdr(struct dp_display *dp_display, + struct drm_msm_ext_hdr_metadata *hdr) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + rc = dp->panel->setup_hdr(dp->panel, hdr); + + return rc; +} + +static int dp_display_create_workqueue(struct dp_display_private *dp) +{ + dp->wq = create_singlethread_workqueue("drm_dp"); + if (IS_ERR_OR_NULL(dp->wq)) { + pr_err("Error creating wq\n"); + return -EPERM; + } + + INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work); + INIT_DELAYED_WORK(&dp->connect_work, dp_display_connect_work); + INIT_WORK(&dp->attention_work, dp_display_attention_work); + + return 0; +} + +static int dp_display_probe(struct platform_device *pdev) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!pdev || !pdev->dev.of_node) { + pr_err("pdev not found\n"); + rc = -ENODEV; + goto bail; + } + + dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL); + if (!dp) { + rc = -ENOMEM; + goto bail; + } + + init_completion(&dp->notification_comp); + + dp->pdev = pdev; + dp->name = "drm_dp"; + dp->audio_status = -ENODEV; + + rc = dp_display_create_workqueue(dp); + if (rc) { + pr_err("Failed to create workqueue\n"); + goto error; + } + + platform_set_drvdata(pdev, dp); + + g_dp_display = &dp->dp_display; + + g_dp_display->enable = dp_display_enable; + g_dp_display->post_enable = dp_display_post_enable; + g_dp_display->pre_disable = dp_display_pre_disable; + g_dp_display->disable = dp_display_disable; + g_dp_display->set_mode = dp_display_set_mode; + g_dp_display->validate_mode = dp_display_validate_mode; + g_dp_display->get_modes = dp_display_get_modes; + g_dp_display->prepare = dp_display_prepare; + g_dp_display->unprepare = dp_display_unprepare; + g_dp_display->request_irq = dp_request_irq; + g_dp_display->get_debug = dp_get_debug; + g_dp_display->post_open = dp_display_post_open; + g_dp_display->post_init = dp_display_post_init; + g_dp_display->config_hdr = dp_display_config_hdr; + + rc = component_add(&pdev->dev, &dp_display_comp_ops); + if (rc) { + pr_err("component add failed, rc=%d\n", rc); + goto error; + } + + return 0; +error: + devm_kfree(&pdev->dev, dp); +bail: + return rc; +} + +int dp_display_get_displays(void **displays, int count) +{ + if (!displays) { + pr_err("invalid data\n"); + return -EINVAL; + } + + if (count != 1) { + pr_err("invalid number of displays\n"); + return -EINVAL; + } + + displays[0] = g_dp_display; + return count; +} + +int dp_display_get_num_of_displays(void) +{ + return 1; +} + +static int dp_display_remove(struct platform_device *pdev) +{ + struct dp_display_private *dp; + + if (!pdev) + return -EINVAL; + + dp = platform_get_drvdata(pdev); + + dp_display_deinit_sub_modules(dp); + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, dp); + + return 0; +} + +static struct platform_driver dp_display_driver = { + .probe = dp_display_probe, + .remove = dp_display_remove, + .driver = { + .name = "msm-dp-display", + .of_match_table = dp_dt_match, + }, +}; + +static int __init dp_display_init(void) +{ + int ret; + + ret = platform_driver_register(&dp_display_driver); + if (ret) { + pr_err("driver register failed"); + return ret; + } + + return ret; +} +late_initcall(dp_display_init); + +static void __exit dp_display_cleanup(void) +{ + platform_driver_unregister(&dp_display_driver); +} +module_exit(dp_display_cleanup); + diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h new file mode 100644 index 0000000000000000000000000000000000000000..266de5fe174b41e93d50277e5e632df9f2d3c0e4 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-2018, 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 _DP_DISPLAY_H_ +#define _DP_DISPLAY_H_ + +#include +#include + +#include "dp_panel.h" + +struct dp_display { + struct drm_device *drm_dev; + struct dp_bridge *bridge; + struct drm_connector *connector; + bool is_connected; + u32 max_pclk_khz; + + int (*enable)(struct dp_display *dp_display); + int (*post_enable)(struct dp_display *dp_display); + + int (*pre_disable)(struct dp_display *dp_display); + int (*disable)(struct dp_display *dp_display); + + int (*set_mode)(struct dp_display *dp_display, + struct dp_display_mode *mode); + int (*validate_mode)(struct dp_display *dp_display, u32 mode_pclk_khz); + int (*get_modes)(struct dp_display *dp_display, + struct dp_display_mode *dp_mode); + int (*prepare)(struct dp_display *dp_display); + int (*unprepare)(struct dp_display *dp_display); + int (*request_irq)(struct dp_display *dp_display); + struct dp_debug *(*get_debug)(struct dp_display *dp_display); + void (*post_open)(struct dp_display *dp_display); + int (*config_hdr)(struct dp_display *dp_display, + struct drm_msm_ext_hdr_metadata *hdr_meta); + void (*post_init)(struct dp_display *dp_display); +}; + +int dp_display_get_num_of_displays(void); +int dp_display_get_displays(void **displays, int count); +#endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c new file mode 100644 index 0000000000000000000000000000000000000000..b834230bb4ec3f79e7e1dddd4e45f92bba5f31f7 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2017-2018, 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) "[drm-dp]: %s: " fmt, __func__ + +#include +#include +#include + +#include "msm_drv.h" +#include "msm_kms.h" +#include "sde_connector.h" +#include "dp_drm.h" +#include "dp_debug.h" + +#define to_dp_bridge(x) container_of((x), struct dp_bridge, base) + +static void convert_to_dp_mode(const struct drm_display_mode *drm_mode, + struct dp_display_mode *dp_mode, struct dp_display *dp) +{ + memset(dp_mode, 0, sizeof(*dp_mode)); + + dp_mode->timing.h_active = drm_mode->hdisplay; + dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; + dp_mode->timing.h_sync_width = drm_mode->htotal - + (drm_mode->hsync_start + dp_mode->timing.h_back_porch); + dp_mode->timing.h_front_porch = drm_mode->hsync_start - + drm_mode->hdisplay; + dp_mode->timing.h_skew = drm_mode->hskew; + + dp_mode->timing.v_active = drm_mode->vdisplay; + dp_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; + dp_mode->timing.v_sync_width = drm_mode->vtotal - + (drm_mode->vsync_start + dp_mode->timing.v_back_porch); + + dp_mode->timing.v_front_porch = drm_mode->vsync_start - + drm_mode->vdisplay; + + dp_mode->timing.refresh_rate = drm_mode->vrefresh; + + dp_mode->timing.pixel_clk_khz = drm_mode->clock; + + dp_mode->timing.v_active_low = + !!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC); + + dp_mode->timing.h_active_low = + !!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC); +} + +static void convert_to_drm_mode(const struct dp_display_mode *dp_mode, + struct drm_display_mode *drm_mode) +{ + u32 flags = 0; + + memset(drm_mode, 0, sizeof(*drm_mode)); + + drm_mode->hdisplay = dp_mode->timing.h_active; + drm_mode->hsync_start = drm_mode->hdisplay + + dp_mode->timing.h_front_porch; + drm_mode->hsync_end = drm_mode->hsync_start + + dp_mode->timing.h_sync_width; + drm_mode->htotal = drm_mode->hsync_end + dp_mode->timing.h_back_porch; + drm_mode->hskew = dp_mode->timing.h_skew; + + drm_mode->vdisplay = dp_mode->timing.v_active; + drm_mode->vsync_start = drm_mode->vdisplay + + dp_mode->timing.v_front_porch; + drm_mode->vsync_end = drm_mode->vsync_start + + dp_mode->timing.v_sync_width; + drm_mode->vtotal = drm_mode->vsync_end + dp_mode->timing.v_back_porch; + + drm_mode->vrefresh = dp_mode->timing.refresh_rate; + drm_mode->clock = dp_mode->timing.pixel_clk_khz; + + if (dp_mode->timing.h_active_low) + flags |= DRM_MODE_FLAG_NHSYNC; + else + flags |= DRM_MODE_FLAG_PHSYNC; + + if (dp_mode->timing.v_active_low) + flags |= DRM_MODE_FLAG_NVSYNC; + else + flags |= DRM_MODE_FLAG_PVSYNC; + + drm_mode->flags = flags; + + drm_mode->type = 0x48; + drm_mode_set_name(drm_mode); +} + +static int dp_bridge_attach(struct drm_bridge *dp_bridge) +{ + struct dp_bridge *bridge = to_dp_bridge(dp_bridge); + + if (!dp_bridge) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + pr_debug("[%d] attached\n", bridge->id); + + return 0; +} + +static void dp_bridge_pre_enable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + pr_err("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + /* By this point mode should have been validated through mode_fixup */ + rc = dp->set_mode(dp, &bridge->dp_mode); + if (rc) { + pr_err("[%d] failed to perform a mode set, rc=%d\n", + bridge->id, rc); + return; + } + + rc = dp->prepare(dp); + if (rc) { + pr_err("[%d] DP display prepare failed, rc=%d\n", + bridge->id, rc); + return; + } + + rc = dp->enable(dp); + if (rc) { + pr_err("[%d] DP display enable failed, rc=%d\n", + bridge->id, rc); + dp->unprepare(dp); + } +} + +static void dp_bridge_enable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + pr_err("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + rc = dp->post_enable(dp); + if (rc) + pr_err("[%d] DP display post enable failed, rc=%d\n", + bridge->id, rc); +} + +static void dp_bridge_disable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + pr_err("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + if (dp && dp->connector) + sde_connector_helper_bridge_disable(dp->connector); + + rc = dp->pre_disable(dp); + if (rc) { + pr_err("[%d] DP display pre disable failed, rc=%d\n", + bridge->id, rc); + } +} + +static void dp_bridge_post_disable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + pr_err("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + rc = dp->disable(dp); + if (rc) { + pr_err("[%d] DP display disable failed, rc=%d\n", + bridge->id, rc); + return; + } + + rc = dp->unprepare(dp); + if (rc) { + pr_err("[%d] DP display unprepare failed, rc=%d\n", + bridge->id, rc); + return; + } +} + +static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge || !mode || !adjusted_mode) { + pr_err("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + memset(&bridge->dp_mode, 0x0, sizeof(struct dp_display_mode)); + convert_to_dp_mode(adjusted_mode, &bridge->dp_mode, dp); +} + +static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + bool ret = true; + struct dp_display_mode dp_mode; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge || !mode || !adjusted_mode) { + pr_err("Invalid params\n"); + ret = false; + goto end; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + convert_to_dp_mode(mode, &dp_mode, dp); + convert_to_drm_mode(&dp_mode, adjusted_mode); +end: + return ret; +} + +static const struct drm_bridge_funcs dp_bridge_ops = { + .attach = dp_bridge_attach, + .mode_fixup = dp_bridge_mode_fixup, + .pre_enable = dp_bridge_pre_enable, + .enable = dp_bridge_enable, + .disable = dp_bridge_disable, + .post_disable = dp_bridge_post_disable, + .mode_set = dp_bridge_mode_set, +}; + +int dp_connector_config_hdr(void *display, + struct sde_connector_state *c_state) +{ + struct dp_display *dp = display; + + if (!display || !c_state) { + pr_err("invalid params\n"); + return -EINVAL; + } + + return dp->config_hdr(dp, &c_state->hdr_meta); +} + +int dp_connector_post_init(struct drm_connector *connector, void *display) +{ + struct dp_display *dp_display = display; + + if (!dp_display) + return -EINVAL; + + dp_display->connector = connector; + + if (dp_display->post_init) + dp_display->post_init(dp_display); + + return 0; +} + +int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, u32 max_mixer_width, void *display) +{ + const u32 dual_lm = 2; + const u32 single_lm = 1; + const u32 single_intf = 1; + const u32 no_enc = 0; + struct msm_display_topology *topology; + + if (!drm_mode || !mode_info || !max_mixer_width) { + pr_err("invalid params\n"); + return -EINVAL; + } + + topology = &mode_info->topology; + topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? + dual_lm : single_lm; + topology->num_enc = no_enc; + topology->num_intf = single_intf; + + mode_info->frame_rate = drm_mode->vrefresh; + mode_info->vtotal = drm_mode->vtotal; + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; + + return 0; +} + +int dp_connector_get_info(struct msm_display_info *info, void *data) +{ + struct dp_display *display = data; + + if (!info || !display) { + pr_err("invalid params\n"); + return -EINVAL; + } + + info->intf_type = DRM_MODE_CONNECTOR_DisplayPort; + + info->num_of_h_tiles = 1; + info->h_tile_instance[0] = 0; + info->is_connected = display->is_connected; + info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID | + MSM_DISPLAY_CAP_HOT_PLUG; + + return 0; +} + +enum drm_connector_status dp_connector_detect(struct drm_connector *conn, + bool force, + void *display) +{ + enum drm_connector_status status = connector_status_unknown; + struct msm_display_info info; + int rc; + + if (!conn || !display) + return status; + + /* get display dp_info */ + memset(&info, 0x0, sizeof(info)); + rc = dp_connector_get_info(&info, display); + if (rc) { + pr_err("failed to get display info, rc=%d\n", rc); + return connector_status_disconnected; + } + + if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) + status = (info.is_connected ? connector_status_connected : + connector_status_disconnected); + else + status = connector_status_connected; + + conn->display_info.width_mm = info.width_mm; + conn->display_info.height_mm = info.height_mm; + + return status; +} + +void dp_connector_post_open(void *display) +{ + struct dp_display *dp; + + if (!display) { + pr_err("invalid input\n"); + return; + } + + dp = display; + + if (dp->post_open) + dp->post_open(dp); +} + +int dp_connector_get_modes(struct drm_connector *connector, + void *display) +{ + int rc = 0; + struct dp_display *dp; + struct dp_display_mode *dp_mode = NULL; + struct drm_display_mode *m, drm_mode; + + if (!connector || !display) + return 0; + + dp = display; + + dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL); + if (!dp_mode) + return 0; + + /* pluggable case assumes EDID is read when HPD */ + if (dp->is_connected) { + rc = dp->get_modes(dp, dp_mode); + if (!rc) + pr_err("failed to get DP sink modes, rc=%d\n", rc); + + if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */ + memset(&drm_mode, 0x0, sizeof(drm_mode)); + convert_to_drm_mode(dp_mode, &drm_mode); + m = drm_mode_duplicate(connector->dev, &drm_mode); + if (!m) { + pr_err("failed to add mode %ux%u\n", + drm_mode.hdisplay, + drm_mode.vdisplay); + kfree(dp_mode); + return 0; + } + m->width_mm = connector->display_info.width_mm; + m->height_mm = connector->display_info.height_mm; + drm_mode_probed_add(connector, m); + } + } else { + pr_err("No sink connected\n"); + } + kfree(dp_mode); + + return rc; +} + +int dp_drm_bridge_init(void *data, struct drm_encoder *encoder) +{ + int rc = 0; + struct dp_bridge *bridge; + struct drm_device *dev; + struct dp_display *display = data; + struct msm_drm_private *priv = NULL; + + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + if (!bridge) { + rc = -ENOMEM; + goto error; + } + + dev = display->drm_dev; + bridge->display = display; + bridge->base.funcs = &dp_bridge_ops; + bridge->base.encoder = encoder; + + priv = dev->dev_private; + + rc = drm_bridge_attach(dev, &bridge->base); + if (rc) { + pr_err("failed to attach bridge, rc=%d\n", rc); + goto error_free_bridge; + } + + rc = display->request_irq(display); + if (rc) { + pr_err("request_irq failed, rc=%d\n", rc); + goto error_free_bridge; + } + + encoder->bridge = &bridge->base; + priv->bridges[priv->num_bridges++] = &bridge->base; + display->bridge = bridge; + + return 0; +error_free_bridge: + kfree(bridge); +error: + return rc; +} + +void dp_drm_bridge_deinit(void *data) +{ + struct dp_display *display = data; + struct dp_bridge *bridge = display->bridge; + + if (bridge && bridge->base.encoder) + bridge->base.encoder->bridge = NULL; + + kfree(bridge); +} + +enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display) +{ + struct dp_display *dp_disp; + struct dp_debug *debug; + + if (!mode || !display) { + pr_err("invalid params\n"); + return MODE_ERROR; + } + + dp_disp = display; + debug = dp_disp->get_debug(dp_disp); + + mode->vrefresh = drm_mode_vrefresh(mode); + + if (mode->clock > dp_disp->max_pclk_khz) + return MODE_BAD; + + if (debug->debug_en && (mode->hdisplay != debug->hdisplay || + mode->vdisplay != debug->vdisplay || + mode->vrefresh != debug->vrefresh || + mode->picture_aspect_ratio != debug->aspect_ratio)) + return MODE_BAD; + + return dp_disp->validate_mode(dp_disp, mode->clock); +} diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h new file mode 100644 index 0000000000000000000000000000000000000000..3ca10c2c9c5ceadd1643d3b28d3676986f42da18 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_drm.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017-2018, 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 _DP_DRM_H_ +#define _DP_DRM_H_ + +#include +#include +#include +#include + +#include "msm_drv.h" +#include "dp_display.h" + +struct dp_bridge { + struct drm_bridge base; + u32 id; + + struct dp_display *display; + struct dp_display_mode dp_mode; +}; + +/** + * dp_connector_config_hdr - callback to configure HDR + * @display: Pointer to private display handle + * @c_state: connect state data + * Returns: Zero on success + */ +int dp_connector_config_hdr(void *display, + struct sde_connector_state *c_state); + +/** + * dp_connector_post_init - callback to perform additional initialization steps + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ +int dp_connector_post_init(struct drm_connector *connector, void *display); + +/** + * dp_connector_detect - callback to determine if connector is connected + * @connector: Pointer to drm connector structure + * @force: Force detect setting from drm framework + * @display: Pointer to private display handle + * Returns: Connector 'is connected' status + */ +enum drm_connector_status dp_connector_detect(struct drm_connector *conn, + bool force, + void *display); + +/** + * dp_connector_get_modes - callback to add drm modes via drm_mode_probed_add() + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Number of modes added + */ +int dp_connector_get_modes(struct drm_connector *connector, + void *display); + +/** + * dp_connector_mode_valid - callback to determine if specified mode is valid + * @connector: Pointer to drm connector structure + * @mode: Pointer to drm mode structure + * @display: Pointer to private display handle + * Returns: Validity status for specified mode + */ +enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display); + +/** + * dp_connector_get_mode_info - retrieve information of the mode selected + * @drm_mode: Display mode set for the display + * @mode_info: Out parameter. Information of the mode + * @max_mixer_width: max width supported by HW layer mixer + * @display: Pointer to private display structure + * Returns: zero on success + */ +int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + u32 max_mixer_width, void *display); + +int dp_connector_get_info(struct msm_display_info *info, void *display); + +/** + * dp_connector_post_open - handle the post open functionalites + * @display: Pointer to private display structure + */ +void dp_connector_post_open(void *display); + +int dp_drm_bridge_init(void *display, + struct drm_encoder *encoder); + +void dp_drm_bridge_deinit(void *display); +#endif /* _DP_DRM_H_ */ + diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c new file mode 100644 index 0000000000000000000000000000000000000000..0e1490fae55df1353d847ecbe0452c62bc2741ab --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c @@ -0,0 +1,927 @@ +/* Copyright (c) 2016-2017, 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) "[dp-hdcp2p2] %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sde_hdcp.h" + +#define DP_INTR_STATUS2 (0x00000024) +#define DP_INTR_STATUS3 (0x00000028) +#define dp_read(offset) readl_relaxed((offset)) +#define dp_write(offset, data) writel_relaxed((data), (offset)) +#define DP_HDCP_RXCAPS_LENGTH 3 + +enum dp_hdcp2p2_sink_status { + SINK_DISCONNECTED, + SINK_CONNECTED +}; + +enum dp_auth_status { + DP_HDCP_AUTH_STATUS_FAILURE, + DP_HDCP_AUTH_STATUS_SUCCESS +}; + +struct dp_hdcp2p2_ctrl { + atomic_t auth_state; + enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */ + struct dp_hdcp2p2_interrupts *intr; + struct sde_hdcp_init_data init_data; + struct mutex mutex; /* mutex to protect access to ctrl */ + struct mutex msg_lock; /* mutex to protect access to msg buffer */ + struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/ + struct sde_hdcp_ops *ops; + void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */ + struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */ + enum hdcp_wakeup_cmd wakeup_cmd; + enum dp_auth_status auth_status; + + struct task_struct *thread; + struct kthread_worker worker; + struct kthread_work status; + struct kthread_work auth; + struct kthread_work send_msg; + struct kthread_work recv_msg; + struct kthread_work link; + char *msg_buf; + uint32_t send_msg_len; /* length of all parameters in msg */ + uint32_t timeout; + uint32_t num_messages; + struct hdcp_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS]; + u8 sink_rx_status; + u8 rx_status; + char abort_mask; + + bool cp_irq_done; + bool polling; +}; + +struct dp_hdcp2p2_int_set { + u32 interrupt; + char *name; + void (*func)(struct dp_hdcp2p2_ctrl *ctrl); +}; + +struct dp_hdcp2p2_interrupts { + u32 reg; + struct dp_hdcp2p2_int_set *int_set; +}; + +static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl) +{ + if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_AUTHENTICATE) + return true; + + if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) + return true; + + return false; +} + +static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl, + struct hdcp_wakeup_data *data) +{ + int i = 0; + + if (!data || !data->message_data) + return 0; + + mutex_lock(&ctrl->msg_lock); + + ctrl->timeout = data->timeout; + ctrl->num_messages = data->message_data->num_messages; + ctrl->send_msg_len = 0; /* Total len of all messages */ + + for (i = 0; i < ctrl->num_messages ; i++) + ctrl->send_msg_len += data->message_data->messages[i].length; + + memcpy(ctrl->msg_part, data->message_data->messages, + sizeof(data->message_data->messages)); + + ctrl->rx_status = data->message_data->rx_status; + ctrl->abort_mask = data->abort_mask; + + if (!data->send_msg_len) { + mutex_unlock(&ctrl->msg_lock); + return 0; + } + + kzfree(ctrl->msg_buf); + + ctrl->msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL); + + if (!ctrl->msg_buf) { + mutex_unlock(&ctrl->msg_lock); + return -ENOMEM; + } + + /* ignore first byte as it contains message id */ + memcpy(ctrl->msg_buf, data->send_msg_buf + 1, ctrl->send_msg_len); + + mutex_unlock(&ctrl->msg_lock); + + return 0; +} + +static int dp_hdcp2p2_wakeup(struct hdcp_wakeup_data *data) +{ + struct dp_hdcp2p2_ctrl *ctrl; + u32 const default_timeout_us = 500; + + if (!data) { + pr_err("invalid input\n"); + return -EINVAL; + } + + ctrl = data->context; + if (!ctrl) { + pr_err("invalid ctrl\n"); + return -EINVAL; + } + + mutex_lock(&ctrl->wakeup_mutex); + + ctrl->wakeup_cmd = data->cmd; + + if (data->timeout) + ctrl->timeout = (data->timeout) * 2; + else + ctrl->timeout = default_timeout_us; + + if (!dp_hdcp2p2_is_valid_state(ctrl)) { + pr_err("invalid state\n"); + goto exit; + } + + if (dp_hdcp2p2_copy_buf(ctrl, data)) + goto exit; + + if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_SUCCESS) + ctrl->auth_status = DP_HDCP_AUTH_STATUS_SUCCESS; + else if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_FAILED) + ctrl->auth_status = DP_HDCP_AUTH_STATUS_FAILURE; + + switch (ctrl->wakeup_cmd) { + case HDCP_WKUP_CMD_SEND_MESSAGE: + kthread_queue_work(&ctrl->worker, &ctrl->send_msg); + break; + case HDCP_WKUP_CMD_RECV_MESSAGE: + kthread_queue_work(&ctrl->worker, &ctrl->recv_msg); + break; + case HDCP_WKUP_CMD_STATUS_SUCCESS: + case HDCP_WKUP_CMD_STATUS_FAILED: + kthread_queue_work(&ctrl->worker, &ctrl->status); + break; + case HDCP_WKUP_CMD_LINK_POLL: + if (ctrl->cp_irq_done) + kthread_queue_work(&ctrl->worker, &ctrl->recv_msg); + else + ctrl->polling = true; + break; + case HDCP_WKUP_CMD_AUTHENTICATE: + kthread_queue_work(&ctrl->worker, &ctrl->auth); + break; + default: + pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd); + } +exit: + mutex_unlock(&ctrl->wakeup_mutex); + + return 0; +} + +static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, + struct hdcp_lib_wakeup_data *data) +{ + int rc = 0; + + if (ctrl && ctrl->lib && ctrl->lib->wakeup && + data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) { + rc = ctrl->lib->wakeup(data); + if (rc) + pr_err("error sending %s to lib\n", + hdcp_lib_cmd_to_str(data->cmd)); + } +} + +static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) +{ + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + ctrl->sink_status = SINK_DISCONNECTED; + atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); +} + +static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable) +{ + void __iomem *base = ctrl->init_data.dp_ahb->base; + struct dp_hdcp2p2_interrupts *intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + u32 interrupts = 0; + + while (int_set && int_set->interrupt) { + interrupts |= int_set->interrupt; + int_set++; + } + + if (enable) + dp_write(base + intr->reg, + dp_read(base + intr->reg) | interrupts); + else + dp_write(base + intr->reg, + dp_read(base + intr->reg) & ~interrupts); + intr++; + } +} + +static void dp_hdcp2p2_off(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE}; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + return; + } + + dp_hdcp2p2_set_interrupts(ctrl, false); + + dp_hdcp2p2_reset(ctrl); + + kthread_flush_worker(&ctrl->worker); + + cdata.context = input; + dp_hdcp2p2_wakeup(&cdata); +} + +static int dp_hdcp2p2_authenticate(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE}; + int rc = 0; + + kthread_flush_worker(&ctrl->worker); + + dp_hdcp2p2_set_interrupts(ctrl, true); + + ctrl->sink_status = SINK_CONNECTED; + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); + + cdata.context = input; + dp_hdcp2p2_wakeup(&cdata); + + return rc; +} + +static int dp_hdcp2p2_reauthenticate(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + + if (!ctrl) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp_hdcp2p2_reset((struct dp_hdcp2p2_ctrl *)input); + + return dp_hdcp2p2_authenticate(input); +} + +static void dp_hdcp2p2_min_level_change(void *client_ctx, + int min_enc_level) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx; + struct hdcp_lib_wakeup_data cdata = { + HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE}; + bool enc_notify = true; + int enc_lvl; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + switch (min_enc_level) { + case 0: + enc_lvl = HDCP_STATE_AUTH_ENC_NONE; + break; + case 1: + enc_lvl = HDCP_STATE_AUTH_ENC_1X; + break; + case 2: + enc_lvl = HDCP_STATE_AUTH_ENC_2P2; + break; + default: + enc_notify = false; + } + + pr_debug("enc level changed %d\n", min_enc_level); + + cdata.context = ctrl->lib_ctx; + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); + + if (enc_notify && ctrl->init_data.notify_status) + ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl); +} + +static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) +{ + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + dp_hdcp2p2_set_interrupts(ctrl, false); + + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); + + /* notify DP about HDCP failure */ + ctrl->init_data.notify_status(ctrl->init_data.cb_data, + HDCP_STATE_AUTH_FAIL); +} + +static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl, + u8 *buf, int size, int offset, u32 timeout) +{ + int const max_size = 16; + int rc = 0, read_size = 0, bytes_read = 0; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + return -EINVAL; + } + + do { + read_size = min(size, max_size); + + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + offset, buf, read_size); + if (bytes_read != read_size) { + pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", + offset, read_size, bytes_read); + break; + } + + buf += read_size; + offset += read_size; + size -= read_size; + } while (size > 0); + + return rc; +} + +static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl, + u8 *buf, int size, uint offset, uint timeout) +{ + int const max_size = 16; + int rc = 0, write_size = 0, bytes_written = 0; + + do { + write_size = min(size, max_size); + + bytes_written = drm_dp_dpcd_write(ctrl->init_data.drm_aux, + offset, buf, write_size); + if (bytes_written != write_size) { + pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", + offset, write_size, bytes_written); + break; + } + + buf += write_size; + offset += write_size; + size -= write_size; + } while (size > 0); + + return rc; +} + +static bool dp_hdcp2p2_feature_supported(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + struct hdcp_txmtr_ops *lib = NULL; + bool supported = false; + + if (!ctrl) { + pr_err("invalid input\n"); + goto end; + } + + lib = ctrl->lib; + if (!lib) { + pr_err("invalid lib ops data\n"); + goto end; + } + + if (lib->feature_supported) + supported = lib->feature_supported( + ctrl->lib_ctx); +end: + return supported; +} + +static void dp_hdcp2p2_send_msg_work(struct kthread_work *work) +{ + int rc = 0; + struct dp_hdcp2p2_ctrl *ctrl = container_of(work, + struct dp_hdcp2p2_ctrl, send_msg); + struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; + + if (!ctrl) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto exit; + } + + cdata.context = ctrl->lib_ctx; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + goto exit; + } + + mutex_lock(&ctrl->msg_lock); + + rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->msg_buf, + ctrl->send_msg_len, ctrl->msg_part->offset, + ctrl->timeout); + if (rc) { + pr_err("Error sending msg to sink %d\n", rc); + mutex_unlock(&ctrl->msg_lock); + goto exit; + } + + cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; + cdata.timeout = ctrl->timeout; + mutex_unlock(&ctrl->msg_lock); + +exit: + if (rc == -ETIMEDOUT) + cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT; + else if (rc) + cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED; + + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0; + char *recvd_msg_buf = NULL; + struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; + + cdata.context = ctrl->lib_ctx; + + recvd_msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL); + if (!recvd_msg_buf) { + rc = -ENOMEM; + goto exit; + } + + rc = dp_hdcp2p2_aux_read_message(ctrl, recvd_msg_buf, + ctrl->send_msg_len, ctrl->msg_part->offset, + ctrl->timeout); + if (rc) { + pr_err("error reading message %d\n", rc); + goto exit; + } + + cdata.recvd_msg_buf = recvd_msg_buf; + cdata.recvd_msg_len = ctrl->send_msg_len; + cdata.timeout = ctrl->timeout; +exit: + if (rc == -ETIMEDOUT) + cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT; + else if (rc) + cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED; + else + cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS; + + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); + kfree(recvd_msg_buf); + + return rc; +} + +static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work) +{ + struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; + struct dp_hdcp2p2_ctrl *ctrl = container_of(work, + struct dp_hdcp2p2_ctrl, recv_msg); + + cdata.context = ctrl->lib_ctx; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + return; + } + + if (ctrl->rx_status) { + if (!ctrl->cp_irq_done) { + pr_debug("waiting for CP_IRQ\n"); + ctrl->polling = true; + return; + } + + if (ctrl->rx_status & ctrl->sink_rx_status) { + ctrl->cp_irq_done = false; + ctrl->sink_rx_status = 0; + ctrl->rx_status = 0; + } + } + + dp_hdcp2p2_get_msg_from_sink(ctrl); +} + +static void dp_hdcp2p2_auth_status_work(struct kthread_work *work) +{ + struct dp_hdcp2p2_ctrl *ctrl = container_of(work, + struct dp_hdcp2p2_ctrl, status); + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("hdcp is off\n"); + return; + } + + if (ctrl->auth_status == DP_HDCP_AUTH_STATUS_SUCCESS) { + ctrl->init_data.notify_status(ctrl->init_data.cb_data, + HDCP_STATE_AUTHENTICATED); + + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATED); + } else { + dp_hdcp2p2_auth_failed(ctrl); + } +} + +static void dp_hdcp2p2_link_work(struct kthread_work *work) +{ + int rc = 0; + struct dp_hdcp2p2_ctrl *ctrl = container_of(work, + struct dp_hdcp2p2_ctrl, link); + struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || + atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("invalid hdcp state\n"); + return; + } + + cdata.context = ctrl->lib_ctx; + + if (ctrl->sink_rx_status & ctrl->abort_mask) { + if (ctrl->sink_rx_status & BIT(3)) + pr_err("reauth_req set by sink\n"); + + if (ctrl->sink_rx_status & BIT(4)) + pr_err("link failure reported by sink\n"); + + ctrl->sink_rx_status = 0; + ctrl->rx_status = 0; + + rc = -ENOLINK; + + cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED; + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); + goto exit; + } + + if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) { + ctrl->sink_rx_status = 0; + ctrl->rx_status = 0; + + dp_hdcp2p2_get_msg_from_sink(ctrl); + + ctrl->polling = false; + } else { + ctrl->cp_irq_done = true; + } +exit: + if (rc) + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static void dp_hdcp2p2_auth_work(struct kthread_work *work) +{ + struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; + struct dp_hdcp2p2_ctrl *ctrl = container_of(work, + struct dp_hdcp2p2_ctrl, auth); + + cdata.context = ctrl->lib_ctx; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING) + cdata.cmd = HDCP_LIB_WKUP_CMD_START; + else + cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; + + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl, + u8 *rx_status) +{ + u32 const cp_irq_dpcd_offset = 0x201; + u32 const rxstatus_dpcd_offset = 0x69493; + ssize_t const bytes_to_read = 1; + ssize_t bytes_read = 0; + u8 buf = 0; + int rc = 0; + bool cp_irq = 0; + + *rx_status = 0; + + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + cp_irq_dpcd_offset, &buf, bytes_to_read); + if (bytes_read != bytes_to_read) { + pr_err("cp irq read failed\n"); + rc = bytes_read; + goto error; + } + + cp_irq = buf & BIT(2); + pr_debug("cp_irq=0x%x\n", cp_irq); + buf = 0; + + if (cp_irq) { + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + rxstatus_dpcd_offset, &buf, bytes_to_read); + if (bytes_read != bytes_to_read) { + pr_err("rxstatus read failed\n"); + rc = bytes_read; + goto error; + } + *rx_status = buf; + pr_debug("rx_status=0x%x\n", *rx_status); + } + +error: + return rc; +} + +static int dp_hdcp2p2_cp_irq(void *input) +{ + int rc = 0; + struct dp_hdcp2p2_ctrl *ctrl = input; + + if (!ctrl) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || + atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + pr_err("invalid hdcp state\n"); + rc = -EINVAL; + goto error; + } + + ctrl->sink_rx_status = 0; + rc = dp_hdcp2p2_read_rx_status(ctrl, &ctrl->sink_rx_status); + if (rc) { + pr_err("failed to read rx status\n"); + goto error; + } + + pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status); + + if (!ctrl->sink_rx_status) { + pr_debug("not a hdcp 2.2 irq\n"); + rc = -EINVAL; + goto error; + } + + kthread_queue_work(&ctrl->worker, &ctrl->link); + + return 0; +error: + return rc; +} + +static int dp_hdcp2p2_isr(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + int rc = 0; + struct dss_io_data *io; + struct dp_hdcp2p2_interrupts *intr; + u32 hdcp_int_val = 0; + + if (!ctrl || !ctrl->init_data.dp_ahb) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + io = ctrl->init_data.dp_ahb; + intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + + hdcp_int_val = dp_read(io->base + intr->reg); + + while (int_set && int_set->interrupt) { + if (hdcp_int_val & (int_set->interrupt >> 2)) { + pr_debug("%s\n", int_set->name); + + if (int_set->func) + int_set->func(ctrl); + + dp_write(io->base + intr->reg, hdcp_int_val | + (int_set->interrupt >> 1)); + } + int_set++; + } + intr++; + } +end: + return rc; +} + +void sde_dp_hdcp2p2_deinit(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; + + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; + cdata.context = ctrl->lib_ctx; + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); + + kthread_stop(ctrl->thread); + + mutex_destroy(&ctrl->mutex); + mutex_destroy(&ctrl->msg_lock); + mutex_destroy(&ctrl->wakeup_mutex); + kzfree(ctrl->msg_buf); + kfree(ctrl); +} + +void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl; + static struct hdcp_txmtr_ops txmtr_ops; + struct hdcp_register_data register_data; + static struct sde_hdcp_ops ops = { + .isr = dp_hdcp2p2_isr, + .reauthenticate = dp_hdcp2p2_reauthenticate, + .authenticate = dp_hdcp2p2_authenticate, + .feature_supported = dp_hdcp2p2_feature_supported, + .off = dp_hdcp2p2_off, + .cp_irq = dp_hdcp2p2_cp_irq, + }; + + static struct hdcp_client_ops client_ops = { + .wakeup = dp_hdcp2p2_wakeup, + .notify_lvl_change = dp_hdcp2p2_min_level_change, + }; + static struct dp_hdcp2p2_int_set int_set1[] = { + {BIT(17), "authentication successful", NULL}, + {BIT(20), "authentication failed", NULL}, + {BIT(24), "encryption enabled", NULL}, + {BIT(27), "encryption disabled", NULL}, + {0}, + }; + static struct dp_hdcp2p2_int_set int_set2[] = { + {BIT(2), "key fifo underflow", NULL}, + {0}, + }; + static struct dp_hdcp2p2_interrupts intr[] = { + {DP_INTR_STATUS2, int_set1}, + {DP_INTR_STATUS3, int_set2}, + {0} + }; + + if (!init_data || !init_data->cb_data || + !init_data->notify_status || !init_data->drm_aux) { + pr_err("invalid input\n"); + return ERR_PTR(-EINVAL); + } + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + ctrl->init_data = *init_data; + ctrl->lib = &txmtr_ops; + ctrl->msg_buf = NULL; + + ctrl->sink_status = SINK_DISCONNECTED; + ctrl->intr = intr; + + atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); + + ctrl->ops = &ops; + mutex_init(&ctrl->mutex); + mutex_init(&ctrl->msg_lock); + mutex_init(&ctrl->wakeup_mutex); + + register_data.hdcp_ctx = &ctrl->lib_ctx; + register_data.client_ops = &client_ops; + register_data.txmtr_ops = &txmtr_ops; + register_data.device_type = HDCP_TXMTR_DP; + register_data.client_ctx = ctrl; + + rc = hdcp_library_register(®ister_data); + if (rc) { + pr_err("Unable to register with HDCP 2.2 library\n"); + goto error; + } + + kthread_init_worker(&ctrl->worker); + + kthread_init_work(&ctrl->auth, dp_hdcp2p2_auth_work); + kthread_init_work(&ctrl->send_msg, dp_hdcp2p2_send_msg_work); + kthread_init_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work); + kthread_init_work(&ctrl->status, dp_hdcp2p2_auth_status_work); + kthread_init_work(&ctrl->link, dp_hdcp2p2_link_work); + + ctrl->thread = kthread_run(kthread_worker_fn, + &ctrl->worker, "dp_hdcp2p2"); + + if (IS_ERR(ctrl->thread)) { + pr_err("unable to start DP hdcp2p2 thread\n"); + rc = PTR_ERR(ctrl->thread); + ctrl->thread = NULL; + goto error; + } + + return ctrl; +error: + kfree(ctrl); + return ERR_PTR(rc); +} + +static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl) +{ + u32 const rxcaps_dpcd_offset = 0x6921d; + ssize_t bytes_read = 0; + u8 buf[DP_HDCP_RXCAPS_LENGTH]; + + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + rxcaps_dpcd_offset, &buf, DP_HDCP_RXCAPS_LENGTH); + if (bytes_read != DP_HDCP_RXCAPS_LENGTH) { + pr_err("RxCaps read failed\n"); + goto error; + } + + pr_debug("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1); + pr_debug("VERSION=%d\n", buf[0]); + + if ((buf[2] & BIT(1)) && (buf[0] == 0x2)) + return true; + +error: + return false; +} + +struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + + pr_debug("Checking sink capability\n"); + if (dp_hdcp2p2_supported(ctrl)) + return ctrl->ops; + else + return NULL; +} + diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c new file mode 100644 index 0000000000000000000000000000000000000000..3ca247ce071c1aa9c7d2a806a7f346338991bb9c --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -0,0 +1,1547 @@ +/* + * Copyright (c) 2012-2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include "dp_link.h" +#include "dp_panel.h" + +enum dynamic_range { + DP_DYNAMIC_RANGE_RGB_VESA = 0x00, + DP_DYNAMIC_RANGE_RGB_CEA = 0x01, + DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF, +}; + +enum audio_sample_rate { + AUDIO_SAMPLE_RATE_32_KHZ = 0x00, + AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01, + AUDIO_SAMPLE_RATE_48_KHZ = 0x02, + AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03, + AUDIO_SAMPLE_RATE_96_KHZ = 0x04, + AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05, + AUDIO_SAMPLE_RATE_192_KHZ = 0x06, +}; + +enum audio_pattern_type { + AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00, + AUDIO_TEST_PATTERN_SAWTOOTH = 0x01, +}; + +struct dp_link_request { + u32 test_requested; + u32 test_link_rate; + u32 test_lane_count; +}; + +struct dp_link_private { + u32 prev_sink_count; + struct device *dev; + struct dp_aux *aux; + struct dp_link dp_link; + + struct dp_link_request request; + u8 link_status[DP_LINK_STATUS_SIZE]; +}; + +static char *dp_link_get_audio_test_pattern(u32 pattern) +{ + switch (pattern) { + case AUDIO_TEST_PATTERN_OPERATOR_DEFINED: + return DP_LINK_ENUM_STR(AUDIO_TEST_PATTERN_OPERATOR_DEFINED); + case AUDIO_TEST_PATTERN_SAWTOOTH: + return DP_LINK_ENUM_STR(AUDIO_TEST_PATTERN_SAWTOOTH); + default: + return "unknown"; + } +} + +static char *dp_link_get_audio_sample_rate(u32 rate) +{ + switch (rate) { + case AUDIO_SAMPLE_RATE_32_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_32_KHZ); + case AUDIO_SAMPLE_RATE_44_1_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_44_1_KHZ); + case AUDIO_SAMPLE_RATE_48_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_48_KHZ); + case AUDIO_SAMPLE_RATE_88_2_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_88_2_KHZ); + case AUDIO_SAMPLE_RATE_96_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_96_KHZ); + case AUDIO_SAMPLE_RATE_176_4_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_176_4_KHZ); + case AUDIO_SAMPLE_RATE_192_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_192_KHZ); + default: + return "unknown"; + } +} + +static int dp_link_get_period(struct dp_link_private *link, int const addr) +{ + int ret = 0; + u8 bp; + u8 data; + u32 const param_len = 0x1; + u32 const max_audio_period = 0xA; + + /* TEST_AUDIO_PERIOD_CH_XX */ + if (drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, + param_len) < param_len) { + pr_err("failed to read test_audio_period (0x%x)\n", addr); + ret = -EINVAL; + goto exit; + } + + data = bp; + + /* Period - Bits 3:0 */ + data = data & 0xF; + if ((int)data > max_audio_period) { + pr_err("invalid test_audio_period_ch_1 = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + ret = data; +exit: + return ret; +} + +static int dp_link_parse_audio_channel_period(struct dp_link_private *link) +{ + int ret = 0; + struct dp_link_test_audio *req = &link->dp_link.test_audio; + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_1 = ret; + pr_debug("test_audio_period_ch_1 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_2 = ret; + pr_debug("test_audio_period_ch_2 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */ + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_3 = ret; + pr_debug("test_audio_period_ch_3 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_4 = ret; + pr_debug("test_audio_period_ch_4 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_5 = ret; + pr_debug("test_audio_period_ch_5 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_6 = ret; + pr_debug("test_audio_period_ch_6 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_7 = ret; + pr_debug("test_audio_period_ch_7 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_8 = ret; + pr_debug("test_audio_period_ch_8 = 0x%x\n", ret); +exit: + return ret; +} + +static int dp_link_parse_audio_pattern_type(struct dp_link_private *link) +{ + int ret = 0; + u8 bp; + u8 data; + int rlen; + int const param_len = 0x1; + int const max_audio_pattern_type = 0x1; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, + DP_TEST_AUDIO_PATTERN_TYPE, &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read link audio mode data\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + /* Audio Pattern Type - Bits 7:0 */ + if ((int)data > max_audio_pattern_type) { + pr_err("invalid audio pattern type = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_audio.test_audio_pattern_type = data; + pr_debug("audio pattern type = %s\n", + dp_link_get_audio_test_pattern(data)); +exit: + return ret; +} + +static int dp_link_parse_audio_mode(struct dp_link_private *link) +{ + int ret = 0; + u8 bp; + u8 data; + int rlen; + int const param_len = 0x1; + int const max_audio_sampling_rate = 0x6; + int const max_audio_channel_count = 0x8; + int sampling_rate = 0x0; + int channel_count = 0x0; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_AUDIO_MODE, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read link audio mode data\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + /* Sampling Rate - Bits 3:0 */ + sampling_rate = data & 0xF; + if (sampling_rate > max_audio_sampling_rate) { + pr_err("sampling rate (0x%x) greater than max (0x%x)\n", + sampling_rate, max_audio_sampling_rate); + ret = -EINVAL; + goto exit; + } + + /* Channel Count - Bits 7:4 */ + channel_count = ((data & 0xF0) >> 4) + 1; + if (channel_count > max_audio_channel_count) { + pr_err("channel_count (0x%x) greater than max (0x%x)\n", + channel_count, max_audio_channel_count); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate; + link->dp_link.test_audio.test_audio_channel_count = channel_count; + pr_debug("sampling_rate = %s, channel_count = 0x%x\n", + dp_link_get_audio_sample_rate(sampling_rate), channel_count); +exit: + return ret; +} + +/** + * dp_parse_audio_pattern_params() - parses audio pattern parameters from DPCD + * @link: Display Port Driver data + * + * Returns 0 if it successfully parses the audio link pattern parameters. + */ +static int dp_link_parse_audio_pattern_params(struct dp_link_private *link) +{ + int ret = 0; + + ret = dp_link_parse_audio_mode(link); + if (ret) + goto exit; + + ret = dp_link_parse_audio_pattern_type(link); + if (ret) + goto exit; + + ret = dp_link_parse_audio_channel_period(link); + +exit: + return ret; +} + +/** + * dp_link_is_video_pattern_valid() - validates the video pattern + * @pattern: video pattern requested by the sink + * + * Returns true if the requested video pattern is supported. + */ +static bool dp_link_is_video_pattern_valid(u32 pattern) +{ + switch (pattern) { + case DP_NO_TEST_PATTERN: + case DP_COLOR_RAMP: + case DP_BLACK_AND_WHITE_VERTICAL_LINES: + case DP_COLOR_SQUARE: + return true; + default: + return false; + } +} + +static char *dp_link_video_pattern_to_string(u32 test_video_pattern) +{ + switch (test_video_pattern) { + case DP_NO_TEST_PATTERN: + return DP_LINK_ENUM_STR(DP_NO_TEST_PATTERN); + case DP_COLOR_RAMP: + return DP_LINK_ENUM_STR(DP_COLOR_RAMP); + case DP_BLACK_AND_WHITE_VERTICAL_LINES: + return DP_LINK_ENUM_STR(DP_BLACK_AND_WHITE_VERTICAL_LINES); + case DP_COLOR_SQUARE: + return DP_LINK_ENUM_STR(DP_COLOR_SQUARE); + default: + return "unknown"; + } +} + +/** + * dp_link_is_dynamic_range_valid() - validates the dynamic range + * @bit_depth: the dynamic range value to be checked + * + * Returns true if the dynamic range value is supported. + */ +static bool dp_link_is_dynamic_range_valid(u32 dr) +{ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_VESA: + case DP_DYNAMIC_RANGE_RGB_CEA: + return true; + default: + return false; + } +} + +static char *dp_link_dynamic_range_to_string(u32 dr) +{ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_VESA: + return DP_LINK_ENUM_STR(DP_DYNAMIC_RANGE_RGB_VESA); + case DP_DYNAMIC_RANGE_RGB_CEA: + return DP_LINK_ENUM_STR(DP_DYNAMIC_RANGE_RGB_CEA); + case DP_DYNAMIC_RANGE_UNKNOWN: + default: + return "unknown"; + } +} + +/** + * dp_link_is_bit_depth_valid() - validates the bit depth requested + * @bit_depth: bit depth requested by the sink + * + * Returns true if the requested bit depth is supported. + */ +static bool dp_link_is_bit_depth_valid(u32 tbd) +{ + /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + case DP_TEST_BIT_DEPTH_8: + case DP_TEST_BIT_DEPTH_10: + return true; + default: + return false; + } +} + +static char *dp_link_bit_depth_to_string(u32 tbd) +{ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_6); + case DP_TEST_BIT_DEPTH_8: + return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_8); + case DP_TEST_BIT_DEPTH_10: + return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_10); + case DP_TEST_BIT_DEPTH_UNKNOWN: + default: + return "unknown"; + } +} + +static int dp_link_parse_timing_params1(struct dp_link_private *link, + int const addr, int const len, u32 *val) +{ + u8 bp[2]; + int rlen; + + if (len < 2) + return -EINVAL; + + /* Read the requested video link pattern (Byte 0x221). */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len); + if (rlen < len) { + pr_err("failed to read 0x%x\n", addr); + return -EINVAL; + } + + *val = bp[1] | (bp[0] << 8); + + return 0; +} + +static int dp_link_parse_timing_params2(struct dp_link_private *link, + int const addr, int const len, u32 *val1, u32 *val2) +{ + u8 bp[2]; + int rlen; + + if (len < 2) + return -EINVAL; + + /* Read the requested video link pattern (Byte 0x221). */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len); + if (rlen < len) { + pr_err("failed to read 0x%x\n", addr); + return -EINVAL; + } + + *val1 = (bp[0] & BIT(7)) >> 7; + *val2 = bp[1] | ((bp[0] & 0x7F) << 8); + + return 0; +} + +static int dp_link_parse_timing_params3(struct dp_link_private *link, + int const addr, u32 *val) +{ + u8 bp; + u32 len = 1; + int rlen; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len); + if (rlen < 1) { + pr_err("failed to read 0x%x\n", addr); + return -EINVAL; + } + *val = bp; + + return 0; +} + +/** + * dp_parse_video_pattern_params() - parses video pattern parameters from DPCD + * @link: Display Port Driver data + * + * Returns 0 if it successfully parses the video link pattern and the link + * bit depth requested by the sink and, and if the values parsed are valid. + */ +static int dp_link_parse_video_pattern_params(struct dp_link_private *link) +{ + int ret = 0; + int rlen; + u8 bp; + u8 data; + u32 dyn_range; + int const param_len = 0x1; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PATTERN, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read link video pattern\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + if (!dp_link_is_video_pattern_valid(data)) { + pr_err("invalid link video pattern = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_video.test_video_pattern = data; + pr_debug("link video pattern = 0x%x (%s)\n", + link->dp_link.test_video.test_video_pattern, + dp_link_video_pattern_to_string( + link->dp_link.test_video.test_video_pattern)); + + /* Read the requested color bit depth and dynamic range (Byte 0x232) */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read link bit depth\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + /* Dynamic Range */ + dyn_range = (data & DP_TEST_DYNAMIC_RANGE_CEA) >> 3; + if (!dp_link_is_dynamic_range_valid(dyn_range)) { + pr_err("invalid link dynamic range = 0x%x", dyn_range); + ret = -EINVAL; + goto exit; + } + link->dp_link.test_video.test_dyn_range = dyn_range; + pr_debug("link dynamic range = 0x%x (%s)\n", + link->dp_link.test_video.test_dyn_range, + dp_link_dynamic_range_to_string( + link->dp_link.test_video.test_dyn_range)); + + /* Color bit depth */ + data &= DP_TEST_BIT_DEPTH_MASK; + if (!dp_link_is_bit_depth_valid(data)) { + pr_err("invalid link bit depth = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_video.test_bit_depth = data; + pr_debug("link bit depth = 0x%x (%s)\n", + link->dp_link.test_video.test_bit_depth, + dp_link_bit_depth_to_string( + link->dp_link.test_video.test_bit_depth)); + + /* resolution timing params */ + ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2, + &link->dp_link.test_video.test_h_total); + if (ret) { + pr_err("failed to parse test_h_total (DP_TEST_H_TOTAL_HI)\n"); + goto exit; + } + pr_debug("TEST_H_TOTAL = %d\n", link->dp_link.test_video.test_h_total); + + ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2, + &link->dp_link.test_video.test_v_total); + if (ret) { + pr_err("failed to parse test_v_total (DP_TEST_V_TOTAL_HI)\n"); + goto exit; + } + pr_debug("TEST_V_TOTAL = %d\n", link->dp_link.test_video.test_v_total); + + ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2, + &link->dp_link.test_video.test_h_start); + if (ret) { + pr_err("failed to parse test_h_start (DP_TEST_H_START_HI)\n"); + goto exit; + } + pr_debug("TEST_H_START = %d\n", link->dp_link.test_video.test_h_start); + + ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2, + &link->dp_link.test_video.test_v_start); + if (ret) { + pr_err("failed to parse test_v_start (DP_TEST_V_START_HI)\n"); + goto exit; + } + pr_debug("TEST_V_START = %d\n", link->dp_link.test_video.test_v_start); + + ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2, + &link->dp_link.test_video.test_hsync_pol, + &link->dp_link.test_video.test_hsync_width); + if (ret) { + pr_err("failed to parse (DP_TEST_HSYNC_HI)\n"); + goto exit; + } + pr_debug("TEST_HSYNC_POL = %d\n", + link->dp_link.test_video.test_hsync_pol); + pr_debug("TEST_HSYNC_WIDTH = %d\n", + link->dp_link.test_video.test_hsync_width); + + ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2, + &link->dp_link.test_video.test_vsync_pol, + &link->dp_link.test_video.test_vsync_width); + if (ret) { + pr_err("failed to parse (DP_TEST_VSYNC_HI)\n"); + goto exit; + } + pr_debug("TEST_VSYNC_POL = %d\n", + link->dp_link.test_video.test_vsync_pol); + pr_debug("TEST_VSYNC_WIDTH = %d\n", + link->dp_link.test_video.test_vsync_width); + + ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2, + &link->dp_link.test_video.test_h_width); + if (ret) { + pr_err("failed to parse test_h_width (DP_TEST_H_WIDTH_HI)\n"); + goto exit; + } + pr_debug("TEST_H_WIDTH = %d\n", link->dp_link.test_video.test_h_width); + + ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2, + &link->dp_link.test_video.test_v_height); + if (ret) { + pr_err("failed to parse test_v_height (DP_TEST_V_HEIGHT_HI)\n"); + goto exit; + } + pr_debug("TEST_V_HEIGHT = %d\n", + link->dp_link.test_video.test_v_height); + + ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1, + &link->dp_link.test_video.test_rr_d); + link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR; + if (ret) { + pr_err("failed to parse test_rr_d (DP_TEST_MISC1)\n"); + goto exit; + } + pr_debug("TEST_REFRESH_DENOMINATOR = %d\n", + link->dp_link.test_video.test_rr_d); + + ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR, + &link->dp_link.test_video.test_rr_n); + if (ret) { + pr_err("failed to parse test_rr_n (DP_TEST_REFRESH_RATE_NUMERATOR)\n"); + goto exit; + } + pr_debug("TEST_REFRESH_NUMERATOR = %d\n", + link->dp_link.test_video.test_rr_n); +exit: + return ret; +} + +/** + * dp_link_parse_link_training_params() - parses link training parameters from + * DPCD + * @link: Display Port Driver data + * + * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane + * count (Byte 0x220), and if these values parse are valid. + */ +static int dp_link_parse_link_training_params(struct dp_link_private *link) +{ + u8 bp; + u8 data; + int ret = 0; + int rlen; + int const param_len = 0x1; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read link rate\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + if (!is_link_rate_valid(data)) { + pr_err("invalid link rate = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->request.test_link_rate = data; + pr_debug("link rate = 0x%x\n", link->request.test_link_rate); + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read lane count\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + data &= 0x1F; + + if (!is_lane_count_valid(data)) { + pr_err("invalid lane count = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->request.test_lane_count = data; + pr_debug("lane count = 0x%x\n", link->request.test_lane_count); +exit: + return ret; +} + +static bool dp_link_is_phy_test_pattern_supported(u32 phy_test_pattern_sel) +{ + switch (phy_test_pattern_sel) { + case DP_TEST_PHY_PATTERN_NONE: + case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: + case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: + case DP_TEST_PHY_PATTERN_PRBS7: + case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1: + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3: + return true; + default: + return false; + } +} + +/** + * dp_parse_phy_test_params() - parses the phy link parameters + * @link: Display Port Driver data + * + * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being + * requested. + */ +static int dp_link_parse_phy_test_params(struct dp_link_private *link) +{ + u8 bp; + u8 data; + int rlen; + int const param_len = 0x1; + int ret = 0; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PHY_PATTERN, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed to read phy link pattern\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + link->dp_link.phy_params.phy_test_pattern_sel = data; + + pr_debug("phy_test_pattern_sel = %s\n", + dp_link_get_phy_test_pattern(data)); + + if (!dp_link_is_phy_test_pattern_supported(data)) + ret = -EINVAL; +end: + return ret; +} + +static char *dp_link_get_test_name(u32 test_requested) +{ + switch (test_requested) { + case DP_TEST_LINK_TRAINING: + return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING); + case DP_TEST_LINK_VIDEO_PATTERN: + return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN); + case DP_TEST_LINK_EDID_READ: + return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ); + case DP_TEST_LINK_PHY_TEST_PATTERN: + return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN); + case DP_TEST_LINK_AUDIO_PATTERN: + return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN); + default: + return "unknown"; + } +} + +/** + * dp_link_is_video_audio_test_requested() - checks for audio/video link request + * @link: link requested by the sink + * + * Returns true if the requested link is a permitted audio/video link. + */ +static bool dp_link_is_video_audio_test_requested(u32 link) +{ + return (link == DP_TEST_LINK_VIDEO_PATTERN) || + (link == (DP_TEST_LINK_AUDIO_PATTERN | + DP_TEST_LINK_VIDEO_PATTERN)) || + (link == DP_TEST_LINK_AUDIO_PATTERN) || + (link == (DP_TEST_LINK_AUDIO_PATTERN | + DP_TEST_LINK_AUDIO_DISABLED_VIDEO)); +} + +/** + * dp_link_supported() - checks if link requested by sink is supported + * @test_requested: link requested by the sink + * + * Returns true if the requested link is supported. + */ +static bool dp_link_is_test_supported(u32 test_requested) +{ + return (test_requested == DP_TEST_LINK_TRAINING) || + (test_requested == DP_TEST_LINK_EDID_READ) || + (test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) || + dp_link_is_video_audio_test_requested(test_requested); +} + +static bool dp_link_is_test_edid_read(struct dp_link_private *link) +{ + return (link->request.test_requested == DP_TEST_LINK_EDID_READ); +} + +/** + * dp_sink_parse_test_request() - parses link request parameters from sink + * @link: Display Port Driver data + * + * Parses the DPCD to check if an automated link is requested (Byte 0x201), + * and what type of link automation is being requested (Byte 0x218). + */ +static int dp_link_parse_request(struct dp_link_private *link) +{ + int ret = 0; + u8 bp; + u8 data; + int rlen; + u32 const param_len = 0x1; + + /** + * Read the device service IRQ vector (Byte 0x201) to determine + * whether an automated link has been requested by the sink. + */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, + DP_DEVICE_SERVICE_IRQ_VECTOR, &bp, param_len); + if (rlen < param_len) { + pr_err("aux read failed\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + pr_debug("device service irq vector = 0x%x\n", data); + + if (!(data & DP_AUTOMATED_TEST_REQUEST)) { + pr_debug("no test requested\n"); + return 0; + } + + /** + * Read the link request byte (Byte 0x218) to determine what type + * of automated link has been requested by the sink. + */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_REQUEST, + &bp, param_len); + if (rlen < param_len) { + pr_err("aux read failed\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + if (!dp_link_is_test_supported(data)) { + pr_debug("link 0x%x not supported\n", data); + goto end; + } + + pr_debug("%s (0x%x) requested\n", dp_link_get_test_name(data), data); + link->request.test_requested = data; + + if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) { + ret = dp_link_parse_phy_test_params(link); + if (ret) + goto end; + ret = dp_link_parse_link_training_params(link); + } + + if (link->request.test_requested == DP_TEST_LINK_TRAINING) + ret = dp_link_parse_link_training_params(link); + + if (dp_link_is_video_audio_test_requested( + link->request.test_requested)) { + ret = dp_link_parse_video_pattern_params(link); + if (ret) + goto end; + + ret = dp_link_parse_audio_pattern_params(link); + } +end: + /** + * Send a DP_TEST_ACK if all link parameters are valid, otherwise send + * a DP_TEST_NAK. + */ + if (ret) { + link->dp_link.test_response = DP_TEST_NAK; + } else { + if (!dp_link_is_test_edid_read(link)) + link->dp_link.test_response = DP_TEST_ACK; + else + link->dp_link.test_response = + DP_TEST_EDID_CHECKSUM_WRITE; + } + + return ret; +} + +/** + * dp_link_parse_sink_count() - parses the sink count + * + * Parses the DPCD to check if there is an update to the sink count + * (Byte 0x200), and whether all the sink devices connected have Content + * Protection enabled. + */ +static int dp_link_parse_sink_count(struct dp_link *dp_link) +{ + int rlen; + int const param_len = 0x1; + struct dp_link_private *link = container_of(dp_link, + struct dp_link_private, dp_link); + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT, + &link->dp_link.sink_count.count, param_len); + if (rlen < param_len) { + pr_err("failed to read sink count\n"); + return -EINVAL; + } + + link->dp_link.sink_count.cp_ready = + link->dp_link.sink_count.count & DP_SINK_CP_READY; + /* BIT 7, BIT 5:0 */ + link->dp_link.sink_count.count = + DP_GET_SINK_COUNT(link->dp_link.sink_count.count); + + pr_debug("sink_count = 0x%x, cp_ready = 0x%x\n", + link->dp_link.sink_count.count, + link->dp_link.sink_count.cp_ready); + return 0; +} + +static void dp_link_parse_sink_status_field(struct dp_link_private *link) +{ + int len = 0; + + link->prev_sink_count = link->dp_link.sink_count.count; + dp_link_parse_sink_count(&link->dp_link); + + len = drm_dp_dpcd_read_link_status(link->aux->drm_aux, + link->link_status); + if (len < DP_LINK_STATUS_SIZE) + pr_err("DP link status read failed\n"); + dp_link_parse_request(link); +} + +static bool dp_link_is_link_training_requested(struct dp_link_private *link) +{ + return (link->request.test_requested == DP_TEST_LINK_TRAINING); +} + +/** + * dp_link_process_link_training_request() - processes new training requests + * @link: Display Port link data + * + * This function will handle new link training requests that are initiated by + * the sink. In particular, it will update the requested lane count and link + * link rate, and then trigger the link retraining procedure. + * + * The function will return 0 if a link training request has been processed, + * otherwise it will return -EINVAL. + */ +static int dp_link_process_link_training_request(struct dp_link_private *link) +{ + if (!dp_link_is_link_training_requested(link)) + return -EINVAL; + + pr_debug("%s link rate = 0x%x, lane count = 0x%x\n", + dp_link_get_test_name(DP_TEST_LINK_TRAINING), + link->request.test_link_rate, + link->request.test_lane_count); + + link->dp_link.link_params.lane_count = link->request.test_lane_count; + link->dp_link.link_params.bw_code = link->request.test_link_rate; + + return 0; +} + +static void dp_link_send_test_response(struct dp_link *dp_link) +{ + struct dp_link_private *link = NULL; + u32 const response_len = 0x1; + + if (!dp_link) { + pr_err("invalid input\n"); + return; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_RESPONSE, + &dp_link->test_response, response_len); +} + +static int dp_link_psm_config(struct dp_link *dp_link, + struct drm_dp_link *link_info, bool enable) +{ + struct dp_link_private *link = NULL; + int ret = 0; + + if (!dp_link) { + pr_err("invalid params\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + if (enable) + ret = drm_dp_link_power_down(link->aux->drm_aux, link_info); + else + ret = drm_dp_link_power_up(link->aux->drm_aux, link_info); + + if (ret) + pr_err("Failed to %s low power mode\n", + (enable ? "enter" : "exit")); + + return ret; +} + +static void dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum) +{ + struct dp_link_private *link = NULL; + u32 const response_len = 0x1; + + if (!dp_link) { + pr_err("invalid input\n"); + return; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_EDID_CHECKSUM, + &checksum, response_len); +} + +static int dp_link_parse_vx_px(struct dp_link_private *link) +{ + u8 bp; + u8 data; + int const param_len = 0x1; + int ret = 0; + u32 v0, p0, v1, p1, v2, p2, v3, p3; + int rlen; + + pr_debug("\n"); + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE0_1, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed reading lanes 0/1\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + pr_debug("lanes 0/1 (Byte 0x206): 0x%x\n", data); + + v0 = data & 0x3; + data = data >> 2; + p0 = data & 0x3; + data = data >> 2; + + v1 = data & 0x3; + data = data >> 2; + p1 = data & 0x3; + data = data >> 2; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE2_3, + &bp, param_len); + if (rlen < param_len) { + pr_err("failed reading lanes 2/3\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + pr_debug("lanes 2/3 (Byte 0x207): 0x%x\n", data); + + v2 = data & 0x3; + data = data >> 2; + p2 = data & 0x3; + data = data >> 2; + + v3 = data & 0x3; + data = data >> 2; + p3 = data & 0x3; + data = data >> 2; + + pr_debug("vx: 0=%d, 1=%d, 2=%d, 3=%d\n", v0, v1, v2, v3); + pr_debug("px: 0=%d, 1=%d, 2=%d, 3=%d\n", p0, p1, p2, p3); + + /** + * Update the voltage and pre-emphasis levels as per DPCD request + * vector. + */ + pr_debug("Current: v_level = 0x%x, p_level = 0x%x\n", + link->dp_link.phy_params.v_level, + link->dp_link.phy_params.p_level); + pr_debug("Requested: v_level = 0x%x, p_level = 0x%x\n", v0, p0); + link->dp_link.phy_params.v_level = v0; + link->dp_link.phy_params.p_level = p0; + + pr_debug("Success\n"); +end: + return ret; +} + +/** + * dp_link_process_phy_test_pattern_request() - process new phy link requests + * @link: Display Port Driver data + * + * This function will handle new phy link pattern requests that are initiated + * by the sink. The function will return 0 if a phy link pattern has been + * processed, otherwise it will return -EINVAL. + */ +static int dp_link_process_phy_test_pattern_request( + struct dp_link_private *link) +{ + u32 test_link_rate = 0, test_lane_count = 0; + + if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) { + pr_debug("no phy test\n"); + return -EINVAL; + } + + test_link_rate = link->request.test_link_rate; + test_lane_count = link->request.test_lane_count; + + if (!is_link_rate_valid(test_link_rate) || + !is_lane_count_valid(test_lane_count)) { + pr_err("Invalid params: link rate = 0x%x, lane count = 0x%x\n", + test_link_rate, test_lane_count); + return -EINVAL; + } + + pr_debug("start\n"); + + pr_info("Current: bw_code = 0x%x, lane count = 0x%x\n", + link->dp_link.link_params.bw_code, + link->dp_link.link_params.lane_count); + + pr_info("Requested: bw_code = 0x%x, lane count = 0x%x\n", + test_link_rate, test_lane_count); + + link->dp_link.link_params.lane_count = link->request.test_lane_count; + link->dp_link.link_params.bw_code = link->request.test_link_rate; + + dp_link_parse_vx_px(link); + + pr_debug("end\n"); + + return 0; +} + +static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) +{ + return link_status[r - DP_LANE0_1_STATUS]; +} + +/** + * dp_link_process_link_status_update() - processes link status updates + * @link: Display Port link module data + * + * This function will check for changes in the link status, e.g. clock + * recovery done on all lanes, and trigger link training if there is a + * failure/error on the link. + * + * The function will return 0 if the a link status update has been processed, + * otherwise it will return -EINVAL. + */ +static int dp_link_process_link_status_update(struct dp_link_private *link) +{ + if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & + DP_LINK_STATUS_UPDATED) || /* link status updated */ + (drm_dp_clock_recovery_ok(link->link_status, + link->dp_link.link_params.lane_count) && + drm_dp_channel_eq_ok(link->link_status, + link->dp_link.link_params.lane_count))) + return -EINVAL; + + pr_debug("channel_eq_done = %d, clock_recovery_done = %d\n", + drm_dp_clock_recovery_ok(link->link_status, + link->dp_link.link_params.lane_count), + drm_dp_clock_recovery_ok(link->link_status, + link->dp_link.link_params.lane_count)); + + return 0; +} + +static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link) +{ + if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & + DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */ + return true; + + if (link->prev_sink_count != link->dp_link.sink_count.count) + return true; + + return false; +} + +/** + * dp_link_process_downstream_port_status_change() - process port status changes + * @link: Display Port Driver data + * + * This function will handle downstream port updates that are initiated by + * the sink. If the downstream port status has changed, the EDID is read via + * AUX. + * + * The function will return 0 if a downstream port update has been + * processed, otherwise it will return -EINVAL. + */ +static int dp_link_process_ds_port_status_change(struct dp_link_private *link) +{ + if (!dp_link_is_ds_port_status_changed(link)) + return -EINVAL; + + /* reset prev_sink_count */ + link->prev_sink_count = link->dp_link.sink_count.count; + + return 0; +} + +static bool dp_link_is_video_pattern_requested(struct dp_link_private *link) +{ + return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN) + && !(link->request.test_requested & + DP_TEST_LINK_AUDIO_DISABLED_VIDEO); +} + +static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link) +{ + return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN); +} + +/** + * dp_link_process_video_pattern_request() - process new video pattern request + * @link: Display Port link module's data + * + * This function will handle a new video pattern request that are initiated by + * the sink. This is acheieved by first sending a disconnect notification to + * the sink followed by a subsequent connect notification to the user modules, + * where it is expected that the user modules would draw the required link + * pattern. + */ +static int dp_link_process_video_pattern_request(struct dp_link_private *link) +{ + if (!dp_link_is_video_pattern_requested(link)) + goto end; + + pr_debug("%s: bit depth=%d(%d bpp) pattern=%s\n", + dp_link_get_test_name(DP_TEST_LINK_VIDEO_PATTERN), + link->dp_link.test_video.test_bit_depth, + dp_link_bit_depth_to_bpp( + link->dp_link.test_video.test_bit_depth), + dp_link_video_pattern_to_string( + link->dp_link.test_video.test_video_pattern)); + + return 0; +end: + return -EINVAL; +} + +/** + * dp_link_process_audio_pattern_request() - process new audio pattern request + * @link: Display Port link module data + * + * This function will handle a new audio pattern request that is initiated by + * the sink. This is acheieved by sending the necessary secondary data packets + * to the sink. It is expected that any simulatenous requests for video + * patterns will be handled before the audio pattern is sent to the sink. + */ +static int dp_link_process_audio_pattern_request(struct dp_link_private *link) +{ + if (!dp_link_is_audio_pattern_requested(link)) + return -EINVAL; + + pr_debug("sampling_rate=%s, channel_count=%d, pattern_type=%s\n", + dp_link_get_audio_sample_rate( + link->dp_link.test_audio.test_audio_sampling_rate), + link->dp_link.test_audio.test_audio_channel_count, + dp_link_get_audio_test_pattern( + link->dp_link.test_audio.test_audio_pattern_type)); + + pr_debug("audio_period: ch1=0x%x, ch2=0x%x, ch3=0x%x, ch4=0x%x\n", + link->dp_link.test_audio.test_audio_period_ch_1, + link->dp_link.test_audio.test_audio_period_ch_2, + link->dp_link.test_audio.test_audio_period_ch_3, + link->dp_link.test_audio.test_audio_period_ch_4); + + pr_debug("audio_period: ch5=0x%x, ch6=0x%x, ch7=0x%x, ch8=0x%x\n", + link->dp_link.test_audio.test_audio_period_ch_5, + link->dp_link.test_audio.test_audio_period_ch_6, + link->dp_link.test_audio.test_audio_period_ch_7, + link->dp_link.test_audio.test_audio_period_ch_8); + + return 0; +} + +static void dp_link_reset_data(struct dp_link_private *link) +{ + link->request = (const struct dp_link_request){ 0 }; + link->dp_link.test_video = (const struct dp_link_test_video){ 0 }; + link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN; + link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 }; + link->dp_link.phy_params.phy_test_pattern_sel = 0; + link->dp_link.sink_request = 0; + link->dp_link.test_response = 0; +} + +/** + * dp_link_process_request() - handle HPD IRQ transition to HIGH + * @link: pointer to link module data + * + * This function will handle the HPD IRQ state transitions from LOW to HIGH + * (including cases when there are back to back HPD IRQ HIGH) indicating + * the start of a new link training request or sink status update. + */ +static int dp_link_process_request(struct dp_link *dp_link) +{ + int ret = 0; + struct dp_link_private *link; + + if (!dp_link) { + pr_err("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + pr_debug("start\n"); + + dp_link_reset_data(link); + + dp_link_parse_sink_status_field(link); + + if (dp_link_is_test_edid_read(link)) { + dp_link->sink_request |= DP_TEST_LINK_EDID_READ; + goto exit; + } + + ret = dp_link_process_ds_port_status_change(link); + if (!ret) { + dp_link->sink_request |= DS_PORT_STATUS_CHANGED; + goto exit; + } + + ret = dp_link_process_link_training_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_TRAINING; + goto exit; + } + + ret = dp_link_process_phy_test_pattern_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN; + goto exit; + } + + ret = dp_link_process_link_status_update(link); + if (!ret) { + dp_link->sink_request |= DP_LINK_STATUS_UPDATED; + goto exit; + } + + ret = dp_link_process_video_pattern_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN; + goto exit; + } + + ret = dp_link_process_audio_pattern_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN; + goto exit; + } + + pr_debug("done\n"); +exit: + return ret; +} + +static int dp_link_get_colorimetry_config(struct dp_link *dp_link) +{ + u32 cc; + enum dynamic_range dr; + struct dp_link_private *link; + + if (!dp_link) { + pr_err("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + /* unless a video pattern CTS test is ongoing, use CEA_VESA */ + if (dp_link_is_video_pattern_requested(link)) + dr = link->dp_link.test_video.test_dyn_range; + else + dr = DP_DYNAMIC_RANGE_RGB_VESA; + + /* Only RGB_VESA nd RGB_CEA supported for now */ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_CEA: + cc = BIT(3); + break; + case DP_DYNAMIC_RANGE_RGB_VESA: + default: + cc = 0; + } + + return cc; +} + +static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) +{ + int i; + int max = 0; + u8 data; + struct dp_link_private *link; + + if (!dp_link) { + pr_err("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + /* use the max level across lanes */ + for (i = 0; i < dp_link->link_params.lane_count; i++) { + data = drm_dp_get_adjust_request_voltage(link_status, i); + pr_debug("lane=%d req_voltage_swing=%d\n", i, data); + if (max < data) + max = data; + } + + dp_link->phy_params.v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; + + /* use the max level across lanes */ + max = 0; + for (i = 0; i < dp_link->link_params.lane_count; i++) { + data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); + pr_debug("lane=%d req_pre_emphasis=%d\n", i, data); + if (max < data) + max = data; + } + + dp_link->phy_params.p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; + + /** + * Adjust the voltage swing and pre-emphasis level combination to within + * the allowable range. + */ + if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) { + pr_debug("Requested vSwingLevel=%d, change to %d\n", + dp_link->phy_params.v_level, DP_LINK_VOLTAGE_MAX); + dp_link->phy_params.v_level = DP_LINK_VOLTAGE_MAX; + } + + if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) { + pr_debug("Requested preEmphasisLevel=%d, change to %d\n", + dp_link->phy_params.p_level, DP_LINK_PRE_EMPHASIS_MAX); + dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_MAX; + } + + if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1) + && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) { + pr_debug("Requested preEmphasisLevel=%d, change to %d\n", + dp_link->phy_params.p_level, + DP_LINK_PRE_EMPHASIS_LEVEL_1); + dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1; + } + + pr_debug("adjusted: v_level=%d, p_level=%d\n", + dp_link->phy_params.v_level, dp_link->phy_params.p_level); + + return 0; +} + +static int dp_link_send_psm_request(struct dp_link *dp_link, bool req) +{ + struct dp_link_private *link; + + if (!dp_link) { + pr_err("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + return 0; +} + +static u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) +{ + u32 tbd; + + /* + * Few simplistic rules and assumptions made here: + * 1. Test bit depth is bit depth per color component + * 2. Assume 3 color components + */ + switch (bpp) { + case 18: + tbd = DP_TEST_BIT_DEPTH_6; + break; + case 24: + tbd = DP_TEST_BIT_DEPTH_8; + break; + case 30: + tbd = DP_TEST_BIT_DEPTH_10; + break; + default: + tbd = DP_TEST_BIT_DEPTH_UNKNOWN; + break; + } + + if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN) + tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT); + + return tbd; +} + +struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux) +{ + int rc = 0; + struct dp_link_private *link; + struct dp_link *dp_link; + + if (!dev || !aux) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); + if (!link) { + rc = -EINVAL; + goto error; + } + + link->dev = dev; + link->aux = aux; + + dp_link = &link->dp_link; + + dp_link->process_request = dp_link_process_request; + dp_link->get_test_bits_depth = dp_link_get_test_bits_depth; + dp_link->get_colorimetry_config = dp_link_get_colorimetry_config; + dp_link->adjust_levels = dp_link_adjust_levels; + dp_link->send_psm_request = dp_link_send_psm_request; + dp_link->send_test_response = dp_link_send_test_response; + dp_link->psm_config = dp_link_psm_config; + dp_link->send_edid_checksum = dp_link_send_edid_checksum; + + return dp_link; +error: + return ERR_PTR(rc); +} + +void dp_link_put(struct dp_link *dp_link) +{ + struct dp_link_private *link; + + if (!dp_link) + return; + + link = container_of(dp_link, struct dp_link_private, dp_link); + + devm_kfree(link->dev, link); +} diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h new file mode 100644 index 0000000000000000000000000000000000000000..6f79b6a71ff36810b6063e6f3febfa38e5aab9c0 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_LINK_H_ +#define _DP_LINK_H_ + +#include "dp_aux.h" + +#define DS_PORT_STATUS_CHANGED 0x200 +#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF +#define DP_LINK_ENUM_STR(x) #x + +enum dp_link_voltage_level { + DP_LINK_VOLTAGE_LEVEL_0 = 0, + DP_LINK_VOLTAGE_LEVEL_1 = 1, + DP_LINK_VOLTAGE_LEVEL_2 = 2, + DP_LINK_VOLTAGE_MAX = DP_LINK_VOLTAGE_LEVEL_2, +}; + +enum dp_link_preemaphasis_level { + DP_LINK_PRE_EMPHASIS_LEVEL_0 = 0, + DP_LINK_PRE_EMPHASIS_LEVEL_1 = 1, + DP_LINK_PRE_EMPHASIS_LEVEL_2 = 2, + DP_LINK_PRE_EMPHASIS_MAX = DP_LINK_PRE_EMPHASIS_LEVEL_2, +}; + +struct dp_link_sink_count { + u32 count; + bool cp_ready; +}; + +struct dp_link_test_video { + u32 test_video_pattern; + u32 test_bit_depth; + u32 test_dyn_range; + u32 test_h_total; + u32 test_v_total; + u32 test_h_start; + u32 test_v_start; + u32 test_hsync_pol; + u32 test_hsync_width; + u32 test_vsync_pol; + u32 test_vsync_width; + u32 test_h_width; + u32 test_v_height; + u32 test_rr_d; + u32 test_rr_n; +}; + +struct dp_link_test_audio { + u32 test_audio_sampling_rate; + u32 test_audio_channel_count; + u32 test_audio_pattern_type; + u32 test_audio_period_ch_1; + u32 test_audio_period_ch_2; + u32 test_audio_period_ch_3; + u32 test_audio_period_ch_4; + u32 test_audio_period_ch_5; + u32 test_audio_period_ch_6; + u32 test_audio_period_ch_7; + u32 test_audio_period_ch_8; +}; + +struct dp_link_phy_params { + u32 phy_test_pattern_sel; + u8 v_level; + u8 p_level; +}; + +struct dp_link_params { + u32 lane_count; + u32 bw_code; +}; + +struct dp_link { + u32 sink_request; + u32 test_response; + + struct dp_link_sink_count sink_count; + struct dp_link_test_video test_video; + struct dp_link_test_audio test_audio; + struct dp_link_phy_params phy_params; + struct dp_link_params link_params; + + u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp); + int (*process_request)(struct dp_link *dp_link); + int (*get_colorimetry_config)(struct dp_link *dp_link); + int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status); + int (*send_psm_request)(struct dp_link *dp_link, bool req); + void (*send_test_response)(struct dp_link *dp_link); + int (*psm_config)(struct dp_link *dp_link, + struct drm_dp_link *link_info, bool enable); + void (*send_edid_checksum)(struct dp_link *dp_link, u8 checksum); +}; + +static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel) +{ + switch (phy_test_pattern_sel) { + case DP_TEST_PHY_PATTERN_NONE: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE); + case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: + return DP_LINK_ENUM_STR( + DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING); + case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: + return DP_LINK_ENUM_STR( + DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT); + case DP_TEST_PHY_PATTERN_PRBS7: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7); + case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: + return DP_LINK_ENUM_STR( + DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN); + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_1); + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_2: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_2); + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_3); + default: + return "unknown"; + } +} + +/** + * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp + * @tbd: test bit depth + * + * Returns the bits per pixel (bpp) to be used corresponding to the + * git bit depth value. This function assumes that bit depth has + * already been validated. + */ +static inline u32 dp_link_bit_depth_to_bpp(u32 tbd) +{ + u32 bpp; + + /* + * Few simplistic rules and assumptions made here: + * 1. Bit depth is per color component + * 2. If bit depth is unknown return 0 + * 3. Assume 3 color components + */ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + bpp = 18; + break; + case DP_TEST_BIT_DEPTH_8: + bpp = 24; + break; + case DP_TEST_BIT_DEPTH_10: + bpp = 30; + break; + case DP_TEST_BIT_DEPTH_UNKNOWN: + default: + bpp = 0; + } + + return bpp; +} + +/** + * dp_link_get() - get the functionalities of dp test module + * + * + * return: a pointer to dp_link struct + */ +struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux); + +/** + * dp_link_put() - releases the dp test module's resources + * + * @dp_link: an instance of dp_link module + * + */ +void dp_link_put(struct dp_link *dp_link); + +#endif /* _DP_LINK_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c new file mode 100644 index 0000000000000000000000000000000000000000..e0aedc0acb56868f1683fe3c339f4e13bc6af364 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2012-2018, 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) "[drm-dp] %s: " fmt, __func__ + +#include "dp_panel.h" + +#define DP_PANEL_DEFAULT_BPP 24 +#define DP_MAX_DS_PORT_COUNT 1 + +#define DPRX_FEATURE_ENUMERATION_LIST 0x2210 +#define VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED BIT(3) +#define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) +#define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) + +enum dp_panel_hdr_pixel_encoding { + RGB, + YCbCr444, + YCbCr422, + YCbCr420, + YONLY, + RAW, +}; + +enum dp_panel_hdr_rgb_colorimetry { + sRGB, + RGB_WIDE_GAMUT_FIXED_POINT, + RGB_WIDE_GAMUT_FLOATING_POINT, + ADOBERGB, + DCI_P3, + CUSTOM_COLOR_PROFILE, + ITU_R_BT_2020_RGB, +}; + +enum dp_panel_hdr_dynamic_range { + VESA, + CEA, +}; + +enum dp_panel_hdr_content_type { + NOT_DEFINED, + GRAPHICS, + PHOTO, + VIDEO, + GAME, +}; + +enum dp_panel_hdr_state { + HDR_DISABLED, + HDR_ENABLED, +}; + +struct dp_panel_private { + struct device *dev; + struct dp_panel dp_panel; + struct dp_aux *aux; + struct dp_link *link; + struct dp_catalog_panel *catalog; + bool custom_edid; + bool custom_dpcd; + bool panel_on; + bool vsc_supported; + bool vscext_supported; + bool vscext_chaining_supported; + enum dp_panel_hdr_state hdr_state; + u8 spd_vendor_name[8]; + u8 spd_product_description[16]; + u8 major; + u8 minor; +}; + +static const struct dp_panel_info fail_safe = { + .h_active = 640, + .v_active = 480, + .h_back_porch = 48, + .h_front_porch = 16, + .h_sync_width = 96, + .h_active_low = 0, + .v_back_porch = 33, + .v_front_porch = 10, + .v_sync_width = 2, + .v_active_low = 0, + .h_skew = 0, + .refresh_rate = 60, + .pixel_clk_khz = 25200, + .bpp = 24, +}; + +/* OEM NAME */ +static const u8 vendor_name[8] = {81, 117, 97, 108, 99, 111, 109, 109}; + +/* MODEL NAME */ +static const u8 product_desc[16] = {83, 110, 97, 112, 100, 114, 97, 103, + 111, 110, 0, 0, 0, 0, 0, 0}; + +static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func) +{ + int rlen, rc = 0; + struct dp_panel_private *panel; + struct drm_dp_link *link_info; + u8 *dpcd, rx_feature; + u32 dfp_count = 0; + unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dpcd = dp_panel->dpcd; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + link_info = &dp_panel->link_info; + + if (!panel->custom_dpcd) { + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV, + dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1)); + if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { + pr_err("dpcd read failed, rlen=%d\n", rlen); + if (rlen == -ETIMEDOUT) + rc = rlen; + else + rc = -EINVAL; + + goto end; + } + + print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ", + DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); + } + + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, + DPRX_FEATURE_ENUMERATION_LIST, &rx_feature, 1); + if (rlen != 1) { + pr_debug("failed to read DPRX_FEATURE_ENUMERATION_LIST\n"); + panel->vsc_supported = false; + panel->vscext_supported = false; + panel->vscext_chaining_supported = false; + } else { + panel->vsc_supported = !!(rx_feature & + VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); + + panel->vscext_supported = !!(rx_feature & + VSC_EXT_VESA_SDP_SUPPORTED); + + panel->vscext_chaining_supported = !!(rx_feature & + VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); + } + + pr_debug("vsc=%d, vscext=%d, vscext_chaining=%d\n", + panel->vsc_supported, panel->vscext_supported, + panel->vscext_chaining_supported); + + link_info->revision = dp_panel->dpcd[DP_DPCD_REV]; + + panel->major = (link_info->revision >> 4) & 0x0f; + panel->minor = link_info->revision & 0x0f; + pr_debug("version: %d.%d\n", panel->major, panel->minor); + + link_info->rate = + drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]); + pr_debug("link_rate=%d\n", link_info->rate); + + link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] & + DP_MAX_LANE_COUNT_MASK; + + if (multi_func) + link_info->num_lanes = min_t(unsigned int, + link_info->num_lanes, 2); + + pr_debug("lane_count=%d\n", link_info->num_lanes); + + if (drm_dp_enhanced_frame_cap(dpcd)) + link_info->capabilities |= caps; + + dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & + DP_DOWN_STREAM_PORT_COUNT; + + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) + && (dpcd[DP_DPCD_REV] > 0x10)) { + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, + DP_DOWNSTREAM_PORT_0, dp_panel->ds_ports, + DP_MAX_DOWNSTREAM_PORTS); + if (rlen < DP_MAX_DOWNSTREAM_PORTS) { + pr_err("ds port status failed, rlen=%d\n", rlen); + rc = -EINVAL; + goto end; + } + } + + if (dfp_count > DP_MAX_DS_PORT_COUNT) + pr_debug("DS port count %d greater that max (%d) supported\n", + dfp_count, DP_MAX_DS_PORT_COUNT); + +end: + return rc; +} + +static int dp_panel_set_default_link_params(struct dp_panel *dp_panel) +{ + struct drm_dp_link *link_info; + const int default_bw_code = 162000; + const int default_num_lanes = 1; + + if (!dp_panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + link_info = &dp_panel->link_info; + link_info->rate = default_bw_code; + link_info->num_lanes = default_num_lanes; + pr_debug("link_rate=%d num_lanes=%d\n", + link_info->rate, link_info->num_lanes); + + return 0; +} + +static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (edid) { + dp_panel->edid_ctrl->edid = (struct edid *)edid; + panel->custom_edid = true; + } else { + panel->custom_edid = false; + } + + return 0; +} + +static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd) +{ + struct dp_panel_private *panel; + u8 *dp_dpcd; + + if (!dp_panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp_dpcd = dp_panel->dpcd; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dpcd) { + memcpy(dp_dpcd, dpcd, DP_RECEIVER_CAP_SIZE + 1); + panel->custom_dpcd = true; + } else { + panel->custom_dpcd = false; + } + + return 0; +} + +static int dp_panel_read_edid(struct dp_panel *dp_panel, + struct drm_connector *connector) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (panel->custom_edid) { + pr_debug("skip edid read in debug mode\n"); + return 0; + } + + sde_get_edid(connector, &panel->aux->drm_aux->ddc, + (void **)&dp_panel->edid_ctrl); + if (!dp_panel->edid_ctrl->edid) { + pr_err("EDID read failed\n"); + } else { + u8 *buf = (u8 *)dp_panel->edid_ctrl->edid; + u32 size = buf[0x7E] ? 256 : 128; + + print_hex_dump(KERN_DEBUG, "[drm-dp] SINK EDID: ", + DUMP_PREFIX_NONE, 16, 1, buf, size, false); + + return 0; + } + + return -EINVAL; +} + +static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, + struct drm_connector *connector, bool multi_func) +{ + int rc = 0, rlen, count, downstream_ports; + const int count_len = 1; + struct dp_panel_private *panel; + + if (!dp_panel || !connector) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + rc = dp_panel_read_dpcd(dp_panel, multi_func); + if (rc || !is_link_rate_valid(drm_dp_link_rate_to_bw_code( + dp_panel->link_info.rate)) || !is_lane_count_valid( + dp_panel->link_info.num_lanes) || + ((drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate)) > + dp_panel->max_bw_code)) { + if ((rc == -ETIMEDOUT) || (rc == -ENODEV)) { + pr_err("DPCD read failed, return early\n"); + goto end; + } + pr_err("panel dpcd read failed/incorrect, set default params\n"); + dp_panel_set_default_link_params(dp_panel); + } + + downstream_ports = dp_panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_PRESENT; + + if (downstream_ports) { + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT, + &count, count_len); + if (rlen == count_len) { + count = DP_GET_SINK_COUNT(count); + if (!count) { + pr_err("no downstream ports connected\n"); + rc = -ENOTCONN; + goto end; + } + } + } + + rc = dp_panel_read_edid(dp_panel, connector); + if (rc) { + pr_err("panel edid read failed, set failsafe mode\n"); + return rc; + } +end: + return rc; +} + +static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, + u32 mode_edid_bpp, u32 mode_pclk_khz) +{ + struct drm_dp_link *link_info; + const u32 max_supported_bpp = 30, min_supported_bpp = 18; + u32 bpp = 0, data_rate_khz = 0; + + bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); + + link_info = &dp_panel->link_info; + data_rate_khz = link_info->num_lanes * link_info->rate * 8; + + while (bpp > min_supported_bpp) { + if (mode_pclk_khz * bpp <= data_rate_khz) + break; + bpp -= 6; + } + + return bpp; +} + +static u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, + u32 mode_edid_bpp, u32 mode_pclk_khz) +{ + struct dp_panel_private *panel; + u32 bpp = mode_edid_bpp; + + if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { + pr_err("invalid input\n"); + return 0; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dp_panel->video_test) + bpp = dp_link_bit_depth_to_bpp( + panel->link->test_video.test_bit_depth); + else + bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, + mode_pclk_khz); + + return bpp; +} + +static void dp_panel_set_test_mode(struct dp_panel_private *panel, + struct dp_display_mode *mode) +{ + struct dp_panel_info *pinfo = NULL; + struct dp_link_test_video *test_info = NULL; + + if (!panel) { + pr_err("invalid params\n"); + return; + } + + pinfo = &mode->timing; + test_info = &panel->link->test_video; + + pinfo->h_active = test_info->test_h_width; + pinfo->h_sync_width = test_info->test_hsync_width; + pinfo->h_back_porch = test_info->test_h_start - + test_info->test_hsync_width; + pinfo->h_front_porch = test_info->test_h_total - + (test_info->test_h_start + test_info->test_h_width); + + pinfo->v_active = test_info->test_v_height; + pinfo->v_sync_width = test_info->test_vsync_width; + pinfo->v_back_porch = test_info->test_v_start - + test_info->test_vsync_width; + pinfo->v_front_porch = test_info->test_v_total - + (test_info->test_v_start + test_info->test_v_height); + + pinfo->bpp = dp_link_bit_depth_to_bpp(test_info->test_bit_depth); + pinfo->h_active_low = test_info->test_hsync_pol; + pinfo->v_active_low = test_info->test_vsync_pol; + + pinfo->refresh_rate = test_info->test_rr_n; + pinfo->pixel_clk_khz = test_info->test_h_total * + test_info->test_v_total * pinfo->refresh_rate; + + if (test_info->test_rr_d == 0) + pinfo->pixel_clk_khz /= 1000; + else + pinfo->pixel_clk_khz /= 1001; + + if (test_info->test_h_width == 640) + pinfo->pixel_clk_khz = 25170; +} + +static int dp_panel_get_modes(struct dp_panel *dp_panel, + struct drm_connector *connector, struct dp_display_mode *mode) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dp_panel->video_test) { + dp_panel_set_test_mode(panel, mode); + return 1; + } else if (dp_panel->edid_ctrl->edid) { + return _sde_edid_update_modes(connector, dp_panel->edid_ctrl); + } else { /* fail-safe mode */ + memcpy(&mode->timing, &fail_safe, + sizeof(fail_safe)); + return 1; + } +} + +static void dp_panel_handle_sink_request(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { + u8 checksum = sde_get_edid_checksum(dp_panel->edid_ctrl); + + panel->link->send_edid_checksum(panel->link, checksum); + panel->link->send_test_response(panel->link); + } +} + +static void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) +{ + u32 hsync_start_x, hsync_end_x; + struct dp_catalog_panel *catalog; + struct dp_panel_private *panel; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + pr_err("invalid input\n"); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + pinfo = &panel->dp_panel.pinfo; + + if (!panel->panel_on) { + pr_debug("DP panel not enabled, handle TPG on next panel on\n"); + return; + } + + if (!enable) { + panel->catalog->tpg_config(catalog, false); + return; + } + + /* TPG config */ + catalog->hsync_period = pinfo->h_sync_width + pinfo->h_back_porch + + pinfo->h_active + pinfo->h_front_porch; + catalog->vsync_period = pinfo->v_sync_width + pinfo->v_back_porch + + pinfo->v_active + pinfo->v_front_porch; + + catalog->display_v_start = ((pinfo->v_sync_width + + pinfo->v_back_porch) * catalog->hsync_period); + catalog->display_v_end = ((catalog->vsync_period - + pinfo->v_front_porch) * catalog->hsync_period) - 1; + + catalog->display_v_start += pinfo->h_sync_width + pinfo->h_back_porch; + catalog->display_v_end -= pinfo->h_front_porch; + + hsync_start_x = pinfo->h_back_porch + pinfo->h_sync_width; + hsync_end_x = catalog->hsync_period - pinfo->h_front_porch - 1; + + catalog->v_sync_width = pinfo->v_sync_width; + + catalog->hsync_ctl = (catalog->hsync_period << 16) | + pinfo->h_sync_width; + catalog->display_hctl = (hsync_end_x << 16) | hsync_start_x; + + panel->catalog->tpg_config(catalog, true); +} + +static int dp_panel_timing_cfg(struct dp_panel *dp_panel) +{ + int rc = 0; + u32 data, total_ver, total_hor; + struct dp_catalog_panel *catalog; + struct dp_panel_private *panel; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + pinfo = &panel->dp_panel.pinfo; + + pr_debug("width=%d hporch= %d %d %d\n", + pinfo->h_active, pinfo->h_back_porch, + pinfo->h_front_porch, pinfo->h_sync_width); + + pr_debug("height=%d vporch= %d %d %d\n", + pinfo->v_active, pinfo->v_back_porch, + pinfo->v_front_porch, pinfo->v_sync_width); + + total_hor = pinfo->h_active + pinfo->h_back_porch + + pinfo->h_front_porch + pinfo->h_sync_width; + + total_ver = pinfo->v_active + pinfo->v_back_porch + + pinfo->v_front_porch + pinfo->v_sync_width; + + data = total_ver; + data <<= 16; + data |= total_hor; + + catalog->total = data; + + data = (pinfo->v_back_porch + pinfo->v_sync_width); + data <<= 16; + data |= (pinfo->h_back_porch + pinfo->h_sync_width); + + catalog->sync_start = data; + + data = pinfo->v_sync_width; + data <<= 16; + data |= (pinfo->v_active_low << 31); + data |= pinfo->h_sync_width; + data |= (pinfo->h_active_low << 15); + + catalog->width_blanking = data; + + data = pinfo->v_active; + data <<= 16; + data |= pinfo->h_active; + + catalog->dp_active = data; + + panel->catalog->timing_cfg(catalog); + panel->panel_on = true; +end: + return rc; +} + +static int dp_panel_edid_register(struct dp_panel_private *panel) +{ + int rc = 0; + + panel->dp_panel.edid_ctrl = sde_edid_init(); + if (!panel->dp_panel.edid_ctrl) { + pr_err("sde edid init for DP failed\n"); + rc = -ENOMEM; + } + + return rc; +} + +static void dp_panel_edid_deregister(struct dp_panel_private *panel) +{ + sde_edid_deinit((void **)&panel->dp_panel.edid_ctrl); +} + +static int dp_panel_init_panel_info(struct dp_panel *dp_panel) +{ + int rc = 0; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + pinfo = &dp_panel->pinfo; + + /* + * print resolution info as this is a result + * of user initiated action of cable connection + */ + pr_info("SET NEW RESOLUTION:\n"); + pr_info("%dx%d@%dfps\n", pinfo->h_active, + pinfo->v_active, pinfo->refresh_rate); + pr_info("h_porches(back|front|width) = (%d|%d|%d)\n", + pinfo->h_back_porch, + pinfo->h_front_porch, + pinfo->h_sync_width); + pr_info("v_porches(back|front|width) = (%d|%d|%d)\n", + pinfo->v_back_porch, + pinfo->v_front_porch, + pinfo->v_sync_width); + pr_info("pixel clock (KHz)=(%d)\n", pinfo->pixel_clk_khz); + pr_info("bpp = %d\n", pinfo->bpp); + pr_info("active low (h|v)=(%d|%d)\n", pinfo->h_active_low, + pinfo->v_active_low); +end: + return rc; +} + +static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel) +{ + int rc = 0; + struct dp_panel_private *panel; + struct dp_catalog_hdr_data *hdr; + + if (!dp_panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + hdr = &panel->catalog->hdr_data; + + if (!panel->custom_edid) + sde_free_edid((void **)&dp_panel->edid_ctrl); + + memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo)); + memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); + panel->panel_on = false; + + return rc; +} + +static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel) +{ + const u32 encoding_factx10 = 8; + u32 min_link_rate_khz = 0, lane_cnt; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + pr_err("invalid input\n"); + goto end; + } + + lane_cnt = dp_panel->link_info.num_lanes; + pinfo = &dp_panel->pinfo; + + /* num_lanes * lane_count * 8 >= pclk * bpp * 10 */ + min_link_rate_khz = pinfo->pixel_clk_khz / + (lane_cnt * encoding_factx10); + min_link_rate_khz *= pinfo->bpp; + + pr_debug("min lclk req=%d khz for pclk=%d khz, lanes=%d, bpp=%d\n", + min_link_rate_khz, pinfo->pixel_clk_khz, lane_cnt, + pinfo->bpp); +end: + return min_link_rate_khz; +} + +static bool dp_panel_hdr_supported(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + return false; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + return panel->major >= 1 && panel->vsc_supported && + (panel->minor >= 4 || panel->vscext_supported); +} + +static int dp_panel_setup_hdr(struct dp_panel *dp_panel, + struct drm_msm_ext_hdr_metadata *hdr_meta) +{ + int rc = 0; + struct dp_panel_private *panel; + struct dp_catalog_hdr_data *hdr; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + hdr = &panel->catalog->hdr_data; + + /* use cached meta data in case meta data not provided */ + if (!hdr_meta) { + if (hdr->hdr_meta.hdr_state) + goto cached; + else + goto end; + } + + panel->hdr_state = hdr_meta->hdr_state; + + hdr->ext_header_byte0 = 0x00; + hdr->ext_header_byte1 = 0x04; + hdr->ext_header_byte2 = 0x1F; + hdr->ext_header_byte3 = 0x00; + + hdr->vsc_header_byte0 = 0x00; + hdr->vsc_header_byte1 = 0x07; + hdr->vsc_header_byte2 = 0x05; + hdr->vsc_header_byte3 = 0x13; + + hdr->vscext_header_byte0 = 0x00; + hdr->vscext_header_byte1 = 0x87; + hdr->vscext_header_byte2 = 0x1D; + hdr->vscext_header_byte3 = 0x13 << 2; + + /* VSC SDP Payload for DB16 */ + hdr->pixel_encoding = RGB; + hdr->colorimetry = ITU_R_BT_2020_RGB; + + /* VSC SDP Payload for DB17 */ + hdr->dynamic_range = CEA; + + /* VSC SDP Payload for DB18 */ + hdr->content_type = GRAPHICS; + + hdr->bpc = dp_panel->pinfo.bpp / 3; + + hdr->version = 0x01; + hdr->length = 0x1A; + + if (panel->hdr_state) + memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta)); + else + memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); +cached: + if (panel->panel_on) + panel->catalog->config_hdr(panel->catalog, panel->hdr_state); +end: + return rc; +} + +static int dp_panel_spd_config(struct dp_panel *dp_panel) +{ + int rc = 0; + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + if (!dp_panel->spd_enabled) { + pr_debug("SPD Infoframe not enabled\n"); + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + panel->catalog->spd_vendor_name = panel->spd_vendor_name; + panel->catalog->spd_product_description = + panel->spd_product_description; + panel->catalog->config_spd(panel->catalog); +end: + return rc; +} + +struct dp_panel *dp_panel_get(struct dp_panel_in *in) +{ + int rc = 0; + struct dp_panel_private *panel; + struct dp_panel *dp_panel; + + if (!in->dev || !in->catalog || !in->aux || !in->link) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL); + if (!panel) { + rc = -ENOMEM; + goto error; + } + + panel->dev = in->dev; + panel->aux = in->aux; + panel->catalog = in->catalog; + panel->link = in->link; + + dp_panel = &panel->dp_panel; + dp_panel->max_bw_code = DP_LINK_BW_8_1; + dp_panel->spd_enabled = true; + memcpy(panel->spd_vendor_name, vendor_name, (sizeof(u8) * 8)); + memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16)); + + dp_panel->init = dp_panel_init_panel_info; + dp_panel->deinit = dp_panel_deinit_panel_info; + dp_panel->timing_cfg = dp_panel_timing_cfg; + dp_panel->read_sink_caps = dp_panel_read_sink_caps; + dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate; + dp_panel->get_mode_bpp = dp_panel_get_mode_bpp; + dp_panel->get_modes = dp_panel_get_modes; + dp_panel->handle_sink_request = dp_panel_handle_sink_request; + dp_panel->set_edid = dp_panel_set_edid; + dp_panel->set_dpcd = dp_panel_set_dpcd; + dp_panel->tpg_config = dp_panel_tpg_config; + dp_panel->spd_config = dp_panel_spd_config; + dp_panel->setup_hdr = dp_panel_setup_hdr; + dp_panel->hdr_supported = dp_panel_hdr_supported; + + dp_panel_edid_register(panel); + + return dp_panel; +error: + return ERR_PTR(rc); +} + +void dp_panel_put(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + + if (!dp_panel) + return; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + dp_panel_edid_deregister(panel); + devm_kfree(panel->dev, panel); +} diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h new file mode 100644 index 0000000000000000000000000000000000000000..6c2e1862c59686bdec0007619d716236a8673660 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_PANEL_H_ +#define _DP_PANEL_H_ + +#include + +#include "dp_aux.h" +#include "dp_link.h" +#include "dp_usbpd.h" +#include "sde_edid_parser.h" + +enum dp_lane_count { + DP_LANE_COUNT_1 = 1, + DP_LANE_COUNT_2 = 2, + DP_LANE_COUNT_4 = 4, +}; + +#define DP_MAX_DOWNSTREAM_PORTS 0x10 + +struct dp_panel_info { + u32 h_active; + u32 v_active; + u32 h_back_porch; + u32 h_front_porch; + u32 h_sync_width; + u32 h_active_low; + u32 v_back_porch; + u32 v_front_porch; + u32 v_sync_width; + u32 v_active_low; + u32 h_skew; + u32 refresh_rate; + u32 pixel_clk_khz; + u32 bpp; +}; + +struct dp_display_mode { + struct dp_panel_info timing; + u32 capabilities; +}; + +struct dp_panel_in { + struct device *dev; + struct dp_aux *aux; + struct dp_link *link; + struct dp_catalog_panel *catalog; +}; + +struct dp_panel { + /* dpcd raw data */ + u8 dpcd[DP_RECEIVER_CAP_SIZE + 1]; + u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS]; + + struct drm_dp_link link_info; + struct sde_edid_ctrl *edid_ctrl; + struct dp_panel_info pinfo; + bool video_test; + bool spd_enabled; + + u32 vic; + u32 max_pclk_khz; + + /* debug */ + u32 max_bw_code; + + int (*init)(struct dp_panel *dp_panel); + int (*deinit)(struct dp_panel *dp_panel); + int (*timing_cfg)(struct dp_panel *dp_panel); + int (*read_sink_caps)(struct dp_panel *dp_panel, + struct drm_connector *connector, bool multi_func); + u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel); + u32 (*get_mode_bpp)(struct dp_panel *dp_panel, u32 mode_max_bpp, + u32 mode_pclk_khz); + int (*get_modes)(struct dp_panel *dp_panel, + struct drm_connector *connector, struct dp_display_mode *mode); + void (*handle_sink_request)(struct dp_panel *dp_panel); + int (*set_edid)(struct dp_panel *dp_panel, u8 *edid); + int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd); + int (*setup_hdr)(struct dp_panel *dp_panel, + struct drm_msm_ext_hdr_metadata *hdr_meta); + void (*tpg_config)(struct dp_panel *dp_panel, bool enable); + int (*spd_config)(struct dp_panel *dp_panel); + bool (*hdr_supported)(struct dp_panel *dp_panel); +}; + +/** + * is_link_rate_valid() - validates the link rate + * @lane_rate: link rate requested by the sink + * + * Returns true if the requested link rate is supported. + */ +static inline bool is_link_rate_valid(u32 bw_code) +{ + return ((bw_code == DP_LINK_BW_1_62) || + (bw_code == DP_LINK_BW_2_7) || + (bw_code == DP_LINK_BW_5_4) || + (bw_code == DP_LINK_BW_8_1)); +} + +/** + * dp_link_is_lane_count_valid() - validates the lane count + * @lane_count: lane count requested by the sink + * + * Returns true if the requested lane count is supported. + */ +static inline bool is_lane_count_valid(u32 lane_count) +{ + return (lane_count == DP_LANE_COUNT_1) || + (lane_count == DP_LANE_COUNT_2) || + (lane_count == DP_LANE_COUNT_4); +} + +struct dp_panel *dp_panel_get(struct dp_panel_in *in); +void dp_panel_put(struct dp_panel *dp_panel); +#endif /* _DP_PANEL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..c112cdc8c90ae8ecfdfd084ec39bd550023db83b --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2012-2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include + +#include "dp_parser.h" + +static void dp_parser_unmap_io_resources(struct dp_parser *parser) +{ + struct dp_io *io = &parser->io; + + msm_dss_iounmap(&io->dp_ahb); + msm_dss_iounmap(&io->dp_aux); + msm_dss_iounmap(&io->dp_link); + msm_dss_iounmap(&io->dp_p0); + msm_dss_iounmap(&io->phy_io); + msm_dss_iounmap(&io->ln_tx0_io); + msm_dss_iounmap(&io->ln_tx0_io); + msm_dss_iounmap(&io->dp_pll_io); + msm_dss_iounmap(&io->dp_cc_io); + msm_dss_iounmap(&io->usb3_dp_com); + msm_dss_iounmap(&io->qfprom_io); + msm_dss_iounmap(&io->hdcp_io); +} + +static int dp_parser_ctrl_res(struct dp_parser *parser) +{ + int rc = 0; + u32 index; + struct platform_device *pdev = parser->pdev; + struct device_node *of_node = parser->pdev->dev.of_node; + struct dp_io *io = &parser->io; + + rc = of_property_read_u32(of_node, "cell-index", &index); + if (rc) { + pr_err("cell-index not specified, rc=%d\n", rc); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->dp_ahb, "dp_ahb"); + if (rc) { + pr_err("unable to remap dp io resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->dp_aux, "dp_aux"); + if (rc) { + pr_err("unable to remap dp io resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->dp_link, "dp_link"); + if (rc) { + pr_err("unable to remap dp io resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->dp_p0, "dp_p0"); + if (rc) { + pr_err("unable to remap dp io resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->phy_io, "dp_phy"); + if (rc) { + pr_err("unable to remap dp PHY resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->ln_tx0_io, "dp_ln_tx0"); + if (rc) { + pr_err("unable to remap dp TX0 resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->ln_tx1_io, "dp_ln_tx1"); + if (rc) { + pr_err("unable to remap dp TX1 resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->dp_pll_io, "dp_pll"); + if (rc) { + pr_err("unable to remap DP PLL resources\n"); + goto err; + } + + rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com"); + if (rc) { + pr_err("unable to remap USB3 DP com resources\n"); + goto err; + } + + if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) { + pr_err("unable to remap dp MMSS_CC resources\n"); + goto err; + } + + if (msm_dss_ioremap_byname(pdev, &io->qfprom_io, "qfprom_physical")) + pr_warn("unable to remap dp qfprom resources\n"); + + if (msm_dss_ioremap_byname(pdev, &io->hdcp_io, "hdcp_physical")) + pr_warn("unable to remap dp hdcp resources\n"); + + return 0; +err: + dp_parser_unmap_io_resources(parser); + return rc; +} + +static const char *dp_get_phy_aux_config_property(u32 cfg_type) +{ + switch (cfg_type) { + case PHY_AUX_CFG0: + return "qcom,aux-cfg0-settings"; + case PHY_AUX_CFG1: + return "qcom,aux-cfg1-settings"; + case PHY_AUX_CFG2: + return "qcom,aux-cfg2-settings"; + case PHY_AUX_CFG3: + return "qcom,aux-cfg3-settings"; + case PHY_AUX_CFG4: + return "qcom,aux-cfg4-settings"; + case PHY_AUX_CFG5: + return "qcom,aux-cfg5-settings"; + case PHY_AUX_CFG6: + return "qcom,aux-cfg6-settings"; + case PHY_AUX_CFG7: + return "qcom,aux-cfg7-settings"; + case PHY_AUX_CFG8: + return "qcom,aux-cfg8-settings"; + case PHY_AUX_CFG9: + return "qcom,aux-cfg9-settings"; + default: + return "unknown"; + } +} + +static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser) +{ + int i = 0; + + for (i = 0; i < PHY_AUX_CFG_MAX; i++) + parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 }; +} + +static int dp_parser_aux(struct dp_parser *parser) +{ + struct device_node *of_node = parser->pdev->dev.of_node; + int len = 0, i = 0, j = 0, config_count = 0; + const char *data; + int const minimum_config_count = 1; + + for (i = 0; i < PHY_AUX_CFG_MAX; i++) { + const char *property = dp_get_phy_aux_config_property(i); + + data = of_get_property(of_node, property, &len); + if (!data) { + pr_err("Unable to read %s\n", property); + goto error; + } + + config_count = len - 1; + if ((config_count < minimum_config_count) || + (config_count > DP_AUX_CFG_MAX_VALUE_CNT)) { + pr_err("Invalid config count (%d) configs for %s\n", + config_count, property); + goto error; + } + + parser->aux_cfg[i].offset = data[0]; + parser->aux_cfg[i].cfg_cnt = config_count; + pr_debug("%s offset=0x%x, cfg_cnt=%d\n", + property, + parser->aux_cfg[i].offset, + parser->aux_cfg[i].cfg_cnt); + for (j = 1; j < len; j++) { + parser->aux_cfg[i].lut[j - 1] = data[j]; + pr_debug("%s lut[%d]=0x%x\n", + property, + i, + parser->aux_cfg[i].lut[j - 1]); + } + } + return 0; + +error: + dp_parser_phy_aux_cfg_reset(parser); + return -EINVAL; +} + +static int dp_parser_misc(struct dp_parser *parser) +{ + int rc = 0; + struct device_node *of_node = parser->pdev->dev.of_node; + + rc = of_property_read_u32(of_node, + "qcom,max-pclk-frequency-khz", &parser->max_pclk_khz); + if (rc) + parser->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; + + return 0; +} + +static int dp_parser_pinctrl(struct dp_parser *parser) +{ + int rc = 0; + struct dp_pinctrl *pinctrl = &parser->pinctrl; + + pinctrl->pin = devm_pinctrl_get(&parser->pdev->dev); + + if (IS_ERR_OR_NULL(pinctrl->pin)) { + rc = PTR_ERR(pinctrl->pin); + pr_err("failed to get pinctrl, rc=%d\n", rc); + goto error; + } + + pinctrl->state_active = pinctrl_lookup_state(pinctrl->pin, + "mdss_dp_active"); + if (IS_ERR_OR_NULL(pinctrl->state_active)) { + rc = PTR_ERR(pinctrl->state_active); + pr_err("failed to get pinctrl active state, rc=%d\n", rc); + goto error; + } + + pinctrl->state_suspend = pinctrl_lookup_state(pinctrl->pin, + "mdss_dp_sleep"); + if (IS_ERR_OR_NULL(pinctrl->state_suspend)) { + rc = PTR_ERR(pinctrl->state_suspend); + pr_err("failed to get pinctrl suspend state, rc=%d\n", rc); + goto error; + } +error: + return rc; +} + +static int dp_parser_gpio(struct dp_parser *parser) +{ + int i = 0; + struct device *dev = &parser->pdev->dev; + struct device_node *of_node = dev->of_node; + struct dss_module_power *mp = &parser->mp[DP_CORE_PM]; + static const char * const dp_gpios[] = { + "qcom,aux-en-gpio", + "qcom,aux-sel-gpio", + "qcom,usbplug-cc-gpio", + }; + + mp->gpio_config = devm_kzalloc(dev, + sizeof(struct dss_gpio) * ARRAY_SIZE(dp_gpios), GFP_KERNEL); + if (!mp->gpio_config) + return -ENOMEM; + + mp->num_gpio = ARRAY_SIZE(dp_gpios); + + for (i = 0; i < ARRAY_SIZE(dp_gpios); i++) { + mp->gpio_config[i].gpio = of_get_named_gpio(of_node, + dp_gpios[i], 0); + + if (!gpio_is_valid(mp->gpio_config[i].gpio)) { + pr_err("%s gpio not specified\n", dp_gpios[i]); + return -EINVAL; + } + + strlcpy(mp->gpio_config[i].gpio_name, dp_gpios[i], + sizeof(mp->gpio_config[i].gpio_name)); + + mp->gpio_config[i].value = 0; + } + + return 0; +} + +static const char *dp_parser_supply_node_name(enum dp_pm_type module) +{ + switch (module) { + case DP_CORE_PM: return "qcom,core-supply-entries"; + case DP_CTRL_PM: return "qcom,ctrl-supply-entries"; + case DP_PHY_PM: return "qcom,phy-supply-entries"; + default: return "???"; + } +} + +static int dp_parser_get_vreg(struct dp_parser *parser, + enum dp_pm_type module) +{ + int i = 0, rc = 0; + u32 tmp = 0; + const char *pm_supply_name = NULL; + struct device_node *supply_node = NULL; + struct device_node *of_node = parser->pdev->dev.of_node; + struct device_node *supply_root_node = NULL; + struct dss_module_power *mp = &parser->mp[module]; + + mp->num_vreg = 0; + pm_supply_name = dp_parser_supply_node_name(module); + supply_root_node = of_get_child_by_name(of_node, pm_supply_name); + if (!supply_root_node) { + pr_err("no supply entry present: %s\n", pm_supply_name); + goto novreg; + } + + mp->num_vreg = of_get_available_child_count(supply_root_node); + + if (mp->num_vreg == 0) { + pr_debug("no vreg\n"); + goto novreg; + } else { + pr_debug("vreg found. count=%d\n", mp->num_vreg); + } + + mp->vreg_config = devm_kzalloc(&parser->pdev->dev, + sizeof(struct dss_vreg) * mp->num_vreg, GFP_KERNEL); + if (!mp->vreg_config) { + rc = -ENOMEM; + goto error; + } + + for_each_child_of_node(supply_root_node, supply_node) { + const char *st = NULL; + /* vreg-name */ + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + pr_err("error reading name. rc=%d\n", + rc); + goto error; + } + snprintf(mp->vreg_config[i].vreg_name, + ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st); + /* vreg-min-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + pr_err("error reading min volt. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].min_voltage = tmp; + + /* vreg-max-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + pr_err("error reading max volt. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].max_voltage = tmp; + + /* enable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + pr_err("error reading enable load. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].enable_load = tmp; + + /* disable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + pr_err("error reading disable load. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].disable_load = tmp; + + pr_debug("%s min=%d, max=%d, enable=%d, disable=%d\n", + mp->vreg_config[i].vreg_name, + mp->vreg_config[i].min_voltage, + mp->vreg_config[i].max_voltage, + mp->vreg_config[i].enable_load, + mp->vreg_config[i].disable_load + ); + ++i; + } + + return rc; + +error: + if (mp->vreg_config) { + devm_kfree(&parser->pdev->dev, mp->vreg_config); + mp->vreg_config = NULL; + } +novreg: + mp->num_vreg = 0; + + return rc; +} + +static void dp_parser_put_vreg_data(struct device *dev, + struct dss_module_power *mp) +{ + if (!mp) { + DEV_ERR("invalid input\n"); + return; + } + + if (mp->vreg_config) { + devm_kfree(dev, mp->vreg_config); + mp->vreg_config = NULL; + } + mp->num_vreg = 0; +} + +static int dp_parser_regulator(struct dp_parser *parser) +{ + int i, rc = 0; + struct platform_device *pdev = parser->pdev; + + /* Parse the regulator information */ + for (i = DP_CORE_PM; i < DP_MAX_PM; i++) { + rc = dp_parser_get_vreg(parser, i); + if (rc) { + pr_err("get_dt_vreg_data failed for %s. rc=%d\n", + dp_parser_pm_name(i), rc); + i--; + for (; i >= DP_CORE_PM; i--) + dp_parser_put_vreg_data(&pdev->dev, + &parser->mp[i]); + break; + } + } + + return rc; +} + +static bool dp_parser_check_prefix(const char *clk_prefix, const char *clk_name) +{ + return !!strnstr(clk_name, clk_prefix, strlen(clk_name)); +} + +static void dp_parser_put_clk_data(struct device *dev, + struct dss_module_power *mp) +{ + if (!mp) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (mp->clk_config) { + devm_kfree(dev, mp->clk_config); + mp->clk_config = NULL; + } + + mp->num_clk = 0; +} + +static void dp_parser_put_gpio_data(struct device *dev, + struct dss_module_power *mp) +{ + if (!mp) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (mp->gpio_config) { + devm_kfree(dev, mp->gpio_config); + mp->gpio_config = NULL; + } + + mp->num_gpio = 0; +} + +static int dp_parser_init_clk_data(struct dp_parser *parser) +{ + int num_clk = 0, i = 0, rc = 0; + int core_clk_count = 0, ctrl_clk_count = 0; + const char *core_clk = "core"; + const char *ctrl_clk = "ctrl"; + const char *clk_name; + struct device *dev = &parser->pdev->dev; + struct dss_module_power *core_power = &parser->mp[DP_CORE_PM]; + struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM]; + + num_clk = of_property_count_strings(dev->of_node, "clock-names"); + if (num_clk <= 0) { + pr_err("no clocks are defined\n"); + rc = -EINVAL; + goto exit; + } + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(dev->of_node, + "clock-names", i, &clk_name); + + if (dp_parser_check_prefix(core_clk, clk_name)) + core_clk_count++; + + if (dp_parser_check_prefix(ctrl_clk, clk_name)) + ctrl_clk_count++; + } + + /* Initialize the CORE power module */ + if (core_clk_count <= 0) { + pr_err("no core clocks are defined\n"); + rc = -EINVAL; + goto exit; + } + + core_power->num_clk = core_clk_count; + core_power->clk_config = devm_kzalloc(dev, + sizeof(struct dss_clk) * core_power->num_clk, + GFP_KERNEL); + if (!core_power->clk_config) { + rc = -EINVAL; + goto exit; + } + + /* Initialize the CTRL power module */ + if (ctrl_clk_count <= 0) { + pr_err("no ctrl clocks are defined\n"); + rc = -EINVAL; + goto ctrl_clock_error; + } + + ctrl_power->num_clk = ctrl_clk_count; + ctrl_power->clk_config = devm_kzalloc(dev, + sizeof(struct dss_clk) * ctrl_power->num_clk, + GFP_KERNEL); + if (!ctrl_power->clk_config) { + ctrl_power->num_clk = 0; + rc = -EINVAL; + goto ctrl_clock_error; + } + + return rc; + +ctrl_clock_error: + dp_parser_put_clk_data(dev, core_power); +exit: + return rc; +} + +static int dp_parser_clock(struct dp_parser *parser) +{ + int rc = 0, i = 0; + int num_clk = 0; + int core_clk_index = 0, ctrl_clk_index = 0; + int core_clk_count = 0, ctrl_clk_count = 0; + const char *clk_name; + const char *core_clk = "core"; + const char *ctrl_clk = "ctrl"; + struct device *dev = &parser->pdev->dev; + struct dss_module_power *core_power = &parser->mp[DP_CORE_PM]; + struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM]; + + core_power = &parser->mp[DP_CORE_PM]; + ctrl_power = &parser->mp[DP_CTRL_PM]; + + rc = dp_parser_init_clk_data(parser); + if (rc) { + pr_err("failed to initialize power data\n"); + rc = -EINVAL; + goto exit; + } + + core_clk_count = core_power->num_clk; + ctrl_clk_count = ctrl_power->num_clk; + + num_clk = core_clk_count + ctrl_clk_count; + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(dev->of_node, "clock-names", + i, &clk_name); + + if (dp_parser_check_prefix(core_clk, clk_name) && + core_clk_index < core_clk_count) { + struct dss_clk *clk = + &core_power->clk_config[core_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + clk->type = DSS_CLK_AHB; + core_clk_index++; + } else if (dp_parser_check_prefix(ctrl_clk, clk_name) && + ctrl_clk_index < ctrl_clk_count) { + struct dss_clk *clk = + &ctrl_power->clk_config[ctrl_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + ctrl_clk_index++; + + if (!strcmp(clk_name, "ctrl_link_clk") || + !strcmp(clk_name, "ctrl_pixel_clk")) + clk->type = DSS_CLK_PCLK; + else + clk->type = DSS_CLK_AHB; + } + } + + pr_debug("clock parsing successful\n"); + +exit: + return rc; +} + +static int dp_parser_parse(struct dp_parser *parser) +{ + int rc = 0; + + if (!parser) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto err; + } + + rc = dp_parser_ctrl_res(parser); + if (rc) + goto err; + + rc = dp_parser_aux(parser); + if (rc) + goto err; + + rc = dp_parser_misc(parser); + if (rc) + goto err; + + rc = dp_parser_clock(parser); + if (rc) + goto err; + + rc = dp_parser_regulator(parser); + if (rc) + goto err; + + rc = dp_parser_gpio(parser); + if (rc) + goto err; + + rc = dp_parser_pinctrl(parser); +err: + return rc; +} + +struct dp_parser *dp_parser_get(struct platform_device *pdev) +{ + struct dp_parser *parser; + + parser = devm_kzalloc(&pdev->dev, sizeof(*parser), GFP_KERNEL); + if (!parser) + return ERR_PTR(-ENOMEM); + + parser->parse = dp_parser_parse; + parser->pdev = pdev; + + return parser; +} + +void dp_parser_put(struct dp_parser *parser) +{ + int i = 0; + struct dss_module_power *power = NULL; + + if (!parser) { + pr_err("invalid parser module\n"); + return; + } + + power = parser->mp; + + for (i = 0; i < DP_MAX_PM; i++) { + dp_parser_put_clk_data(&parser->pdev->dev, &power[i]); + dp_parser_put_vreg_data(&parser->pdev->dev, &power[i]); + dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]); + } + + devm_kfree(&parser->pdev->dev, parser); +} diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..72da38169c4dfbf281e15a582b36e64f968e8545 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_PARSER_H_ +#define _DP_PARSER_H_ + +#include + +#define DP_LABEL "MDSS DP DISPLAY" +#define AUX_CFG_LEN 10 +#define DP_MAX_PIXEL_CLK_KHZ 675000 + +enum dp_pm_type { + DP_CORE_PM, + DP_CTRL_PM, + DP_PHY_PM, + DP_MAX_PM +}; + +static inline const char *dp_parser_pm_name(enum dp_pm_type module) +{ + switch (module) { + case DP_CORE_PM: return "DP_CORE_PM"; + case DP_CTRL_PM: return "DP_CTRL_PM"; + case DP_PHY_PM: return "DP_PHY_PM"; + default: return "???"; + } +} + +/** + * struct dp_display_data - display related device tree data. + * + * @ctrl_node: referece to controller device + * @phy_node: reference to phy device + * @is_active: is the controller currently active + * @name: name of the display + * @display_type: type of the display + */ +struct dp_display_data { + struct device_node *ctrl_node; + struct device_node *phy_node; + bool is_active; + const char *name; + const char *display_type; +}; + +/** + * struct dp_ctrl_resource - controller's IO related data + * + * @dp_ahb: controller's ahb mapped memory address + * @dp_aux: controller's aux mapped memory address + * @dp_link: controller's link mapped memory address + * @dp_p0: controller's p0 mapped memory address + * @phy_io: phy's mapped memory address + * @ln_tx0_io: USB-DP lane TX0's mapped memory address + * @ln_tx1_io: USB-DP lane TX1's mapped memory address + * @dp_cc_io: DP cc's mapped memory address + * @qfprom_io: qfprom's mapped memory address + * @dp_pll_io: DP PLL mapped memory address + * @usb3_dp_com: USB3 DP PHY combo mapped memory address + * @hdcp_io: hdcp's mapped memory address + */ +struct dp_io { + struct dss_io_data ctrl_io; + struct dss_io_data dp_ahb; + struct dss_io_data dp_aux; + struct dss_io_data dp_link; + struct dss_io_data dp_p0; + struct dss_io_data phy_io; + struct dss_io_data ln_tx0_io; + struct dss_io_data ln_tx1_io; + struct dss_io_data dp_cc_io; + struct dss_io_data qfprom_io; + struct dss_io_data dp_pll_io; + struct dss_io_data usb3_dp_com; + struct dss_io_data hdcp_io; +}; + +/** + * struct dp_pinctrl - DP's pin control + * + * @pin: pin-controller's instance + * @state_active: active state pin control + * @state_hpd_active: hpd active state pin control + * @state_suspend: suspend state pin control + */ +struct dp_pinctrl { + struct pinctrl *pin; + struct pinctrl_state *state_active; + struct pinctrl_state *state_hpd_active; + struct pinctrl_state *state_suspend; +}; + +#define DP_ENUM_STR(x) #x +#define DP_AUX_CFG_MAX_VALUE_CNT 3 +/** + * struct dp_aux_cfg - DP's AUX configuration settings + * + * @cfg_cnt: count of the configurable settings for the AUX register + * @current_index: current index of the AUX config lut + * @offset: register offset of the AUX config register + * @lut: look up table for the AUX config values for this register + */ +struct dp_aux_cfg { + u32 cfg_cnt; + u32 current_index; + u32 offset; + u32 lut[DP_AUX_CFG_MAX_VALUE_CNT]; +}; + +/* PHY AUX config registers */ +enum dp_phy_aux_config_type { + PHY_AUX_CFG0, + PHY_AUX_CFG1, + PHY_AUX_CFG2, + PHY_AUX_CFG3, + PHY_AUX_CFG4, + PHY_AUX_CFG5, + PHY_AUX_CFG6, + PHY_AUX_CFG7, + PHY_AUX_CFG8, + PHY_AUX_CFG9, + PHY_AUX_CFG_MAX, +}; + +static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) +{ + switch (cfg_type) { + case PHY_AUX_CFG0: + return DP_ENUM_STR(PHY_AUX_CFG0); + case PHY_AUX_CFG1: + return DP_ENUM_STR(PHY_AUX_CFG1); + case PHY_AUX_CFG2: + return DP_ENUM_STR(PHY_AUX_CFG2); + case PHY_AUX_CFG3: + return DP_ENUM_STR(PHY_AUX_CFG3); + case PHY_AUX_CFG4: + return DP_ENUM_STR(PHY_AUX_CFG4); + case PHY_AUX_CFG5: + return DP_ENUM_STR(PHY_AUX_CFG5); + case PHY_AUX_CFG6: + return DP_ENUM_STR(PHY_AUX_CFG6); + case PHY_AUX_CFG7: + return DP_ENUM_STR(PHY_AUX_CFG7); + case PHY_AUX_CFG8: + return DP_ENUM_STR(PHY_AUX_CFG8); + case PHY_AUX_CFG9: + return DP_ENUM_STR(PHY_AUX_CFG9); + default: + return "unknown"; + } +} + +/** + * struct dp_parser - DP parser's data exposed to clients + * + * @pdev: platform data of the client + * @mp: gpio, regulator and clock related data + * @pinctrl: pin-control related data + * @ctrl_resouce: controller's register address realated data + * @disp_data: controller's display related data + * @parse: function to be called by client to parse device tree. + */ +struct dp_parser { + struct platform_device *pdev; + struct dss_module_power mp[DP_MAX_PM]; + struct dp_pinctrl pinctrl; + struct dp_io io; + struct dp_display_data disp_data; + + u8 l_map[4]; + struct dp_aux_cfg aux_cfg[AUX_CFG_LEN]; + u32 max_pclk_khz; + + int (*parse)(struct dp_parser *parser); +}; + +/** + * dp_parser_get() - get the DP's device tree parser module + * + * @pdev: platform data of the client + * return: pointer to dp_parser structure. + * + * This function provides client capability to parse the + * device tree and populate the data structures. The data + * related to clock, regulators, pin-control and other + * can be parsed using this module. + */ +struct dp_parser *dp_parser_get(struct platform_device *pdev); + +/** + * dp_parser_put() - cleans the dp_parser module + * + * @parser: pointer to the parser's data. + */ +void dp_parser_put(struct dp_parser *parser); +#endif diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c new file mode 100644 index 0000000000000000000000000000000000000000..d793365f3c3611f73004eddddc571984a5e8689a --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_power.c @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2012-2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include +#include "dp_power.h" + +#define DP_CLIENT_NAME_SIZE 20 + +struct dp_power_private { + struct dp_parser *parser; + struct platform_device *pdev; + struct clk *pixel_clk_rcg; + struct clk *pixel_parent; + + struct dp_power dp_power; + struct sde_power_client *dp_core_client; + struct sde_power_handle *phandle; + + bool core_clks_on; + bool link_clks_on; +}; + +static int dp_power_regulator_init(struct dp_power_private *power) +{ + int rc = 0, i = 0, j = 0; + struct platform_device *pdev; + struct dp_parser *parser; + + parser = power->parser; + pdev = power->pdev; + + for (i = DP_CORE_PM; !rc && (i < DP_MAX_PM); i++) { + rc = msm_dss_config_vreg(&pdev->dev, + parser->mp[i].vreg_config, + parser->mp[i].num_vreg, 1); + if (rc) { + pr_err("failed to init vregs for %s\n", + dp_parser_pm_name(i)); + for (j = i - 1; j >= DP_CORE_PM; j--) { + msm_dss_config_vreg(&pdev->dev, + parser->mp[j].vreg_config, + parser->mp[j].num_vreg, 0); + } + + goto error; + } + } +error: + return rc; +} + +static void dp_power_regulator_deinit(struct dp_power_private *power) +{ + int rc = 0, i = 0; + struct platform_device *pdev; + struct dp_parser *parser; + + parser = power->parser; + pdev = power->pdev; + + for (i = DP_CORE_PM; (i < DP_MAX_PM); i++) { + rc = msm_dss_config_vreg(&pdev->dev, + parser->mp[i].vreg_config, + parser->mp[i].num_vreg, 0); + if (rc) + pr_err("failed to deinit vregs for %s\n", + dp_parser_pm_name(i)); + } +} + +static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable) +{ + int rc = 0, i = 0, j = 0; + struct dp_parser *parser; + + parser = power->parser; + + for (i = DP_CORE_PM; i < DP_MAX_PM; i++) { + rc = msm_dss_enable_vreg( + parser->mp[i].vreg_config, + parser->mp[i].num_vreg, enable); + if (rc) { + pr_err("failed to '%s' vregs for %s\n", + enable ? "enable" : "disable", + dp_parser_pm_name(i)); + if (enable) { + for (j = i-1; j >= DP_CORE_PM; j--) { + msm_dss_enable_vreg( + parser->mp[j].vreg_config, + parser->mp[j].num_vreg, 0); + } + } + goto error; + } + } +error: + return rc; +} + +static int dp_power_pinctrl_set(struct dp_power_private *power, bool active) +{ + int rc = -EFAULT; + struct pinctrl_state *pin_state; + struct dp_parser *parser; + + parser = power->parser; + + if (IS_ERR_OR_NULL(parser->pinctrl.pin)) + return PTR_ERR(parser->pinctrl.pin); + + pin_state = active ? parser->pinctrl.state_active + : parser->pinctrl.state_suspend; + if (!IS_ERR_OR_NULL(pin_state)) { + rc = pinctrl_select_state(parser->pinctrl.pin, + pin_state); + if (rc) + pr_err("can not set %s pins\n", + active ? "dp_active" + : "dp_sleep"); + } else { + pr_err("invalid '%s' pinstate\n", + active ? "dp_active" + : "dp_sleep"); + } + + return rc; +} + +static int dp_power_clk_init(struct dp_power_private *power, bool enable) +{ + int rc = 0; + struct dss_module_power *core, *ctrl; + struct device *dev; + + core = &power->parser->mp[DP_CORE_PM]; + ctrl = &power->parser->mp[DP_CTRL_PM]; + + dev = &power->pdev->dev; + + if (!core || !ctrl) { + pr_err("invalid power_data\n"); + rc = -EINVAL; + goto exit; + } + + if (enable) { + rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk); + if (rc) { + pr_err("failed to get %s clk. err=%d\n", + dp_parser_pm_name(DP_CORE_PM), rc); + goto exit; + } + + rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk); + if (rc) { + pr_err("failed to get %s clk. err=%d\n", + dp_parser_pm_name(DP_CTRL_PM), rc); + goto ctrl_get_error; + } + + power->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg"); + if (IS_ERR(power->pixel_clk_rcg)) { + pr_debug("Unable to get DP pixel clk RCG\n"); + power->pixel_clk_rcg = NULL; + } + + power->pixel_parent = devm_clk_get(dev, "pixel_parent"); + if (IS_ERR(power->pixel_parent)) { + pr_debug("Unable to get DP pixel RCG parent\n"); + power->pixel_parent = NULL; + } + } else { + if (power->pixel_parent) + devm_clk_put(dev, power->pixel_parent); + + if (power->pixel_clk_rcg) + devm_clk_put(dev, power->pixel_clk_rcg); + + msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk); + msm_dss_put_clk(core->clk_config, core->num_clk); + } + + return rc; + +ctrl_get_error: + msm_dss_put_clk(core->clk_config, core->num_clk); +exit: + return rc; +} + +static int dp_power_clk_set_rate(struct dp_power_private *power, + enum dp_pm_type module, bool enable) +{ + int rc = 0; + struct dss_module_power *mp; + + if (!power) { + pr_err("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + mp = &power->parser->mp[module]; + + if (enable) { + rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); + if (rc) { + pr_err("failed to set clks rate.\n"); + goto exit; + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 1); + if (rc) { + pr_err("failed to enable clks\n"); + goto exit; + } + } else { + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 0); + if (rc) { + pr_err("failed to disable clks\n"); + goto exit; + } + } +exit: + return rc; +} + +static int dp_power_clk_enable(struct dp_power *dp_power, + enum dp_pm_type pm_type, bool enable) +{ + int rc = 0; + struct dss_module_power *mp; + struct dp_power_private *power; + + if (!dp_power) { + pr_err("invalid power data\n"); + rc = -EINVAL; + goto error; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + mp = &power->parser->mp[pm_type]; + + if ((pm_type != DP_CORE_PM) && (pm_type != DP_CTRL_PM)) { + pr_err("unsupported power module: %s\n", + dp_parser_pm_name(pm_type)); + return -EINVAL; + } + + if (enable) { + if ((pm_type == DP_CORE_PM) + && (power->core_clks_on)) { + pr_debug("core clks already enabled\n"); + return 0; + } + + if ((pm_type == DP_CTRL_PM) + && (power->link_clks_on)) { + pr_debug("links clks already enabled\n"); + return 0; + } + + if ((pm_type == DP_CTRL_PM) && (!power->core_clks_on)) { + pr_debug("Need to enable core clks before link clks\n"); + + rc = dp_power_clk_set_rate(power, pm_type, enable); + if (rc) { + pr_err("failed to enable clks: %s. err=%d\n", + dp_parser_pm_name(DP_CORE_PM), rc); + goto error; + } else { + power->core_clks_on = true; + } + } + } + + rc = dp_power_clk_set_rate(power, pm_type, enable); + if (rc) { + pr_err("failed to '%s' clks for: %s. err=%d\n", + enable ? "enable" : "disable", + dp_parser_pm_name(pm_type), rc); + goto error; + } + + if (pm_type == DP_CORE_PM) + power->core_clks_on = enable; + else + power->link_clks_on = enable; + + pr_debug("%s clocks for %s\n", + enable ? "enable" : "disable", + dp_parser_pm_name(pm_type)); + pr_debug("link_clks:%s core_clks:%s\n", + power->link_clks_on ? "on" : "off", + power->core_clks_on ? "on" : "off"); +error: + return rc; +} + +static int dp_power_request_gpios(struct dp_power_private *power) +{ + int rc = 0, i; + struct device *dev; + struct dss_module_power *mp; + static const char * const gpio_names[] = { + "aux_enable", "aux_sel", "usbplug_cc", + }; + + if (!power) { + pr_err("invalid power data\n"); + return -EINVAL; + } + + dev = &power->pdev->dev; + mp = &power->parser->mp[DP_CORE_PM]; + + for (i = 0; i < ARRAY_SIZE(gpio_names); i++) { + unsigned int gpio = mp->gpio_config[i].gpio; + + if (gpio_is_valid(gpio)) { + rc = devm_gpio_request(dev, gpio, gpio_names[i]); + if (rc) { + pr_err("request %s gpio failed, rc=%d\n", + gpio_names[i], rc); + goto error; + } + } + } + return 0; +error: + for (i = 0; i < ARRAY_SIZE(gpio_names); i++) { + unsigned int gpio = mp->gpio_config[i].gpio; + + if (gpio_is_valid(gpio)) + gpio_free(gpio); + } + return rc; +} + +static bool dp_power_find_gpio(const char *gpio1, const char *gpio2) +{ + return !!strnstr(gpio1, gpio2, strlen(gpio1)); +} + +static void dp_power_set_gpio(struct dp_power_private *power, bool flip) +{ + int i; + struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM]; + struct dss_gpio *config = mp->gpio_config; + + for (i = 0; i < mp->num_gpio; i++) { + if (dp_power_find_gpio(config->gpio_name, "aux-sel")) + config->value = flip; + + if (gpio_is_valid(config->gpio)) { + pr_debug("gpio %s, value %d\n", config->gpio_name, + config->value); + + if (dp_power_find_gpio(config->gpio_name, "aux-en") || + dp_power_find_gpio(config->gpio_name, "aux-sel")) + gpio_direction_output(config->gpio, + config->value); + else + gpio_set_value(config->gpio, config->value); + + } + config++; + } +} + +static int dp_power_config_gpios(struct dp_power_private *power, bool flip, + bool enable) +{ + int rc = 0, i; + struct dss_module_power *mp; + struct dss_gpio *config; + + mp = &power->parser->mp[DP_CORE_PM]; + config = mp->gpio_config; + + if (enable) { + rc = dp_power_request_gpios(power); + if (rc) { + pr_err("gpio request failed\n"); + return rc; + } + + dp_power_set_gpio(power, flip); + } else { + for (i = 0; i < mp->num_gpio; i++) { + gpio_set_value(config[i].gpio, 0); + gpio_free(config[i].gpio); + } + } + + return 0; +} + +static int dp_power_client_init(struct dp_power *dp_power, + struct sde_power_handle *phandle) +{ + int rc = 0; + struct dp_power_private *power; + char dp_client_name[DP_CLIENT_NAME_SIZE]; + + if (!dp_power) { + pr_err("invalid power data\n"); + return -EINVAL; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + rc = dp_power_regulator_init(power); + if (rc) { + pr_err("failed to init regulators\n"); + goto error_power; + } + + rc = dp_power_clk_init(power, true); + if (rc) { + pr_err("failed to init clocks\n"); + goto error_clk; + } + + power->phandle = phandle; + snprintf(dp_client_name, DP_CLIENT_NAME_SIZE, "dp_core_client"); + power->dp_core_client = sde_power_client_create(phandle, + dp_client_name); + if (IS_ERR_OR_NULL(power->dp_core_client)) { + pr_err("[%s] client creation failed for DP", dp_client_name); + rc = -EINVAL; + goto error_client; + } + return 0; + +error_client: + dp_power_clk_init(power, false); +error_clk: + dp_power_regulator_deinit(power); +error_power: + return rc; +} + +static void dp_power_client_deinit(struct dp_power *dp_power) +{ + struct dp_power_private *power; + + if (!dp_power) { + pr_err("invalid power data\n"); + return; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + sde_power_client_destroy(power->phandle, power->dp_core_client); + dp_power_clk_init(power, false); + dp_power_regulator_deinit(power); +} + +static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power) { + pr_err("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + if (power->pixel_clk_rcg && power->pixel_parent) + clk_set_parent(power->pixel_clk_rcg, power->pixel_parent); +exit: + return rc; +} + +static int dp_power_init(struct dp_power *dp_power, bool flip) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power) { + pr_err("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + rc = dp_power_regulator_ctrl(power, true); + if (rc) { + pr_err("failed to enable regulators\n"); + goto exit; + } + + rc = dp_power_pinctrl_set(power, true); + if (rc) { + pr_err("failed to set pinctrl state\n"); + goto err_pinctrl; + } + + rc = dp_power_config_gpios(power, flip, true); + if (rc) { + pr_err("failed to enable gpios\n"); + goto err_gpio; + } + + rc = sde_power_resource_enable(power->phandle, + power->dp_core_client, true); + if (rc) { + pr_err("Power resource enable failed\n"); + goto err_sde_power; + } + + rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); + if (rc) { + pr_err("failed to enable DP core clocks\n"); + goto err_clk; + } + + return 0; + +err_clk: + sde_power_resource_enable(power->phandle, power->dp_core_client, false); +err_sde_power: + dp_power_config_gpios(power, flip, false); +err_gpio: + dp_power_pinctrl_set(power, false); +err_pinctrl: + dp_power_regulator_ctrl(power, false); +exit: + return rc; +} + +static int dp_power_deinit(struct dp_power *dp_power) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power) { + pr_err("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + dp_power_clk_enable(dp_power, DP_CORE_PM, false); + /* + * If the display power on event was not successful, for example if + * there was a link training failure, then the link clocks could + * possibly still be on. In this scenario, we need to turn off the + * link clocks as soon as the cable is disconnected so that the clock + * state is cleaned up before subsequent connection events. + */ + if (power->link_clks_on) + dp_power_clk_enable(dp_power, DP_CTRL_PM, false); + rc = sde_power_resource_enable(power->phandle, + power->dp_core_client, false); + if (rc) { + pr_err("Power resource enable failed, rc=%d\n", rc); + goto exit; + } + dp_power_config_gpios(power, false, false); + dp_power_pinctrl_set(power, false); + dp_power_regulator_ctrl(power, false); +exit: + return rc; +} + +struct dp_power *dp_power_get(struct dp_parser *parser) +{ + int rc = 0; + struct dp_power_private *power; + struct dp_power *dp_power; + + if (!parser) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL); + if (!power) { + rc = -ENOMEM; + goto error; + } + + power->parser = parser; + power->pdev = parser->pdev; + + dp_power = &power->dp_power; + + dp_power->init = dp_power_init; + dp_power->deinit = dp_power_deinit; + dp_power->clk_enable = dp_power_clk_enable; + dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent; + dp_power->power_client_init = dp_power_client_init; + dp_power->power_client_deinit = dp_power_client_deinit; + + return dp_power; +error: + return ERR_PTR(rc); +} + +void dp_power_put(struct dp_power *dp_power) +{ + struct dp_power_private *power = NULL; + + if (!dp_power) + return; + + power = container_of(dp_power, struct dp_power_private, dp_power); + + devm_kfree(&power->pdev->dev, power); +} diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h new file mode 100644 index 0000000000000000000000000000000000000000..e6e990080e53a5680f71ed3eae58eccb9b43fe7a --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_power.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_POWER_H_ +#define _DP_POWER_H_ + +#include "dp_parser.h" +#include "sde_power_handle.h" + +/** + * sruct dp_power - DisplayPort's power related data + * + * @init: initializes the regulators/core clocks/GPIOs/pinctrl + * @deinit: turns off the regulators/core clocks/GPIOs/pinctrl + * @clk_enable: enable/disable the DP clocks + * @set_pixel_clk_parent: set the parent of DP pixel clock + */ +struct dp_power { + int (*init)(struct dp_power *power, bool flip); + int (*deinit)(struct dp_power *power); + int (*clk_enable)(struct dp_power *power, enum dp_pm_type pm_type, + bool enable); + int (*set_pixel_clk_parent)(struct dp_power *power); + int (*power_client_init)(struct dp_power *power, + struct sde_power_handle *phandle); + void (*power_client_deinit)(struct dp_power *power); +}; + +/** + * dp_power_get() - configure and get the DisplayPort power module data + * + * @parser: instance of parser module + * return: pointer to allocated power module data + * + * This API will configure the DisplayPort's power module and provides + * methods to be called by the client to configure the power related + * modueles. + */ +struct dp_power *dp_power_get(struct dp_parser *parser); + +/** + * dp_power_put() - release the power related resources + * + * @power: pointer to the power module's data + */ +void dp_power_put(struct dp_power *power); +#endif /* _DP_POWER_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..4e2194e155b4e771c3c5719020b0f767c7b89621 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_reg.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2017, 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 _DP_REG_H_ +#define _DP_REG_H_ + +/* DP_TX Registers */ +#define DP_HW_VERSION (0x00000000) +#define DP_SW_RESET (0x00000010) +#define DP_PHY_CTRL (0x00000014) +#define DP_CLK_CTRL (0x00000018) +#define DP_CLK_ACTIVE (0x0000001C) +#define DP_INTR_STATUS (0x00000020) +#define DP_INTR_STATUS2 (0x00000024) +#define DP_INTR_STATUS3 (0x00000028) + +#define DP_DP_HPD_CTRL (0x00000000) +#define DP_DP_HPD_INT_STATUS (0x00000004) +#define DP_DP_HPD_INT_ACK (0x00000008) +#define DP_DP_HPD_INT_MASK (0x0000000C) +#define DP_DP_HPD_REFTIMER (0x00000018) +#define DP_DP_HPD_EVENT_TIME_0 (0x0000001C) +#define DP_DP_HPD_EVENT_TIME_1 (0x00000020) +#define DP_AUX_CTRL (0x00000030) +#define DP_AUX_DATA (0x00000034) +#define DP_AUX_TRANS_CTRL (0x00000038) +#define DP_TIMEOUT_COUNT (0x0000003C) +#define DP_AUX_LIMITS (0x00000040) +#define DP_AUX_STATUS (0x00000044) + +#define DP_DPCD_CP_IRQ (0x201) +#define DP_DPCD_RXSTATUS (0x69493) + +#define DP_INTERRUPT_TRANS_NUM (0x000000A0) + +#define DP_MAINLINK_CTRL (0x00000000) +#define DP_STATE_CTRL (0x00000004) +#define DP_CONFIGURATION_CTRL (0x00000008) +#define DP_SOFTWARE_MVID (0x00000010) +#define DP_SOFTWARE_NVID (0x00000018) +#define DP_TOTAL_HOR_VER (0x0000001C) +#define DP_START_HOR_VER_FROM_SYNC (0x00000020) +#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000024) +#define DP_ACTIVE_HOR_VER (0x00000028) +#define DP_MISC1_MISC0 (0x0000002C) +#define DP_VALID_BOUNDARY (0x00000030) +#define DP_VALID_BOUNDARY_2 (0x00000034) +#define DP_LOGICAL2PHYSICAL_LANE_MAPPING (0x00000038) + +#define DP_MAINLINK_READY (0x00000040) +#define DP_MAINLINK_LEVELS (0x00000044) +#define DP_TU (0x0000004C) + +#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000054) +#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000000C0) +#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000000C4) +#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000000C8) + +#define MMSS_DP_MISC1_MISC0 (0x0000002C) +#define MMSS_DP_AUDIO_TIMING_GEN (0x00000080) +#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000084) +#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000088) +#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000008C) +#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000090) +#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000094) +#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000098) + +#define MMSS_DP_PSR_CRC_RG (0x00000154) +#define MMSS_DP_PSR_CRC_B (0x00000158) + +#define DP_COMPRESSION_MODE_CTRL (0x00000180) + +#define MMSS_DP_AUDIO_CFG (0x00000200) +#define MMSS_DP_AUDIO_STATUS (0x00000204) +#define MMSS_DP_AUDIO_PKT_CTRL (0x00000208) +#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000020C) +#define MMSS_DP_AUDIO_ACR_CTRL (0x00000210) +#define MMSS_DP_AUDIO_CTRL_RESET (0x00000214) + +#define MMSS_DP_SDP_CFG (0x00000228) +#define MMSS_DP_SDP_CFG2 (0x0000022C) +#define MMSS_DP_SDP_CFG3 (0x0000024C) +#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000230) +#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000234) + +#define MMSS_DP_AUDIO_STREAM_0 (0x00000240) +#define MMSS_DP_AUDIO_STREAM_1 (0x00000244) + +#define MMSS_DP_EXTENSION_0 (0x00000250) +#define MMSS_DP_EXTENSION_1 (0x00000254) +#define MMSS_DP_EXTENSION_2 (0x00000258) +#define MMSS_DP_EXTENSION_3 (0x0000025C) +#define MMSS_DP_EXTENSION_4 (0x00000260) +#define MMSS_DP_EXTENSION_5 (0x00000264) +#define MMSS_DP_EXTENSION_6 (0x00000268) +#define MMSS_DP_EXTENSION_7 (0x0000026C) +#define MMSS_DP_EXTENSION_8 (0x00000270) +#define MMSS_DP_EXTENSION_9 (0x00000274) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000278) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000027C) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000280) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000284) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000288) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000028C) +#define MMSS_DP_AUDIO_ISRC_0 (0x00000290) +#define MMSS_DP_AUDIO_ISRC_1 (0x00000294) +#define MMSS_DP_AUDIO_ISRC_2 (0x00000298) +#define MMSS_DP_AUDIO_ISRC_3 (0x0000029C) +#define MMSS_DP_AUDIO_ISRC_4 (0x000002A0) +#define MMSS_DP_AUDIO_ISRC_5 (0x000002A4) +#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000002A8) +#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000002AC) +#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000002B0) + +#define MMSS_DP_GENERIC0_0 (0x00000300) +#define MMSS_DP_GENERIC0_1 (0x00000304) +#define MMSS_DP_GENERIC0_2 (0x00000308) +#define MMSS_DP_GENERIC0_3 (0x0000030C) +#define MMSS_DP_GENERIC0_4 (0x00000310) +#define MMSS_DP_GENERIC0_5 (0x00000314) +#define MMSS_DP_GENERIC0_6 (0x00000318) +#define MMSS_DP_GENERIC0_7 (0x0000031C) +#define MMSS_DP_GENERIC0_8 (0x00000320) +#define MMSS_DP_GENERIC0_9 (0x00000324) +#define MMSS_DP_GENERIC1_0 (0x00000328) +#define MMSS_DP_GENERIC1_1 (0x0000032C) +#define MMSS_DP_GENERIC1_2 (0x00000330) +#define MMSS_DP_GENERIC1_3 (0x00000334) +#define MMSS_DP_GENERIC1_4 (0x00000338) +#define MMSS_DP_GENERIC1_5 (0x0000033C) +#define MMSS_DP_GENERIC1_6 (0x00000340) +#define MMSS_DP_GENERIC1_7 (0x00000344) +#define MMSS_DP_GENERIC1_8 (0x00000348) +#define MMSS_DP_GENERIC1_9 (0x0000034C) + +#define MMSS_DP_VSCEXT_0 (0x000002D0) +#define MMSS_DP_VSCEXT_1 (0x000002D4) +#define MMSS_DP_VSCEXT_2 (0x000002D8) +#define MMSS_DP_VSCEXT_3 (0x000002DC) +#define MMSS_DP_VSCEXT_4 (0x000002E0) +#define MMSS_DP_VSCEXT_5 (0x000002E4) +#define MMSS_DP_VSCEXT_6 (0x000002E8) +#define MMSS_DP_VSCEXT_7 (0x000002EC) +#define MMSS_DP_VSCEXT_8 (0x000002F0) +#define MMSS_DP_VSCEXT_9 (0x000002F4) + +#define MMSS_DP_BIST_ENABLE (0x00000000) +#define MMSS_DP_TIMING_ENGINE_EN (0x00000010) +#define MMSS_DP_INTF_CONFIG (0x00000014) +#define MMSS_DP_INTF_HSYNC_CTL (0x00000018) +#define MMSS_DP_INTF_VSYNC_PERIOD_F0 (0x0000001C) +#define MMSS_DP_INTF_VSYNC_PERIOD_F1 (0x00000020) +#define MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0 (0x00000024) +#define MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1 (0x00000028) +#define MMSS_INTF_DISPLAY_V_START_F0 (0x0000002C) +#define MMSS_INTF_DISPLAY_V_START_F1 (0x00000030) +#define MMSS_DP_INTF_DISPLAY_V_END_F0 (0x00000034) +#define MMSS_DP_INTF_DISPLAY_V_END_F1 (0x00000038) +#define MMSS_DP_INTF_ACTIVE_V_START_F0 (0x0000003C) +#define MMSS_DP_INTF_ACTIVE_V_START_F1 (0x00000040) +#define MMSS_DP_INTF_ACTIVE_V_END_F0 (0x00000044) +#define MMSS_DP_INTF_ACTIVE_V_END_F1 (0x00000048) +#define MMSS_DP_INTF_DISPLAY_HCTL (0x0000004C) +#define MMSS_DP_INTF_ACTIVE_HCTL (0x00000050) +#define MMSS_DP_INTF_POLARITY_CTL (0x00000058) +#define MMSS_DP_TPG_MAIN_CONTROL (0x00000060) +#define MMSS_DP_TPG_VIDEO_CONFIG (0x00000064) +#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000088) + +/*DP PHY Register offsets */ +#define DP_PHY_REVISION_ID0 (0x00000000) +#define DP_PHY_REVISION_ID1 (0x00000004) +#define DP_PHY_REVISION_ID2 (0x00000008) +#define DP_PHY_REVISION_ID3 (0x0000000C) + +#define DP_PHY_CFG (0x00000010) +#define DP_PHY_PD_CTL (0x00000018) +#define DP_PHY_MODE (0x0000001C) + +#define DP_PHY_AUX_CFG0 (0x00000020) +#define DP_PHY_AUX_CFG1 (0x00000024) +#define DP_PHY_AUX_CFG2 (0x00000028) +#define DP_PHY_AUX_CFG3 (0x0000002C) +#define DP_PHY_AUX_CFG4 (0x00000030) +#define DP_PHY_AUX_CFG5 (0x00000034) +#define DP_PHY_AUX_CFG6 (0x00000038) +#define DP_PHY_AUX_CFG7 (0x0000003C) +#define DP_PHY_AUX_CFG8 (0x00000040) +#define DP_PHY_AUX_CFG9 (0x00000044) +#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048) +#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C) +#define DP_PHY_AUX_INTERRUPT_STATUS (0x000000BC) + +#define DP_PHY_SPARE0 (0x00AC) + +#define TXn_TX_EMP_POST1_LVL (0x000C) +#define TXn_TX_DRV_LVL (0x001C) + +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004) + +/* DP MMSS_CC registers */ +#define MMSS_DP_LINK_CMD_RCGR (0x0138) +#define MMSS_DP_LINK_CFG_RCGR (0x013C) +#define MMSS_DP_PIXEL_M (0x0174) +#define MMSS_DP_PIXEL_N (0x0178) + +/* DP HDCP 1.3 registers */ +#define DP_HDCP_CTRL (0x0A0) +#define DP_HDCP_STATUS (0x0A4) +#define DP_HDCP_SW_UPPER_AKSV (0x098) +#define DP_HDCP_SW_LOWER_AKSV (0x09C) +#define DP_HDCP_ENTROPY_CTRL0 (0x350) +#define DP_HDCP_ENTROPY_CTRL1 (0x35C) +#define DP_HDCP_SHA_STATUS (0x0C8) +#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0) +#define DP_HDCP_RCVPORT_DATA3 (0x0A4) +#define DP_HDCP_RCVPORT_DATA4 (0x0A8) +#define DP_HDCP_RCVPORT_DATA5 (0x0C0) +#define DP_HDCP_RCVPORT_DATA6 (0x0C4) + +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020) + +/* USB3 DP COM registers */ +#define USB3_DP_COM_RESET_OVRD_CTRL (0x1C) +#define USB3_DP_COM_PHY_MODE_CTRL (0x00) +#define USB3_DP_COM_SW_RESET (0x04) +#define USB3_DP_COM_TYPEC_CTRL (0x10) +#define USB3_DP_COM_SWI_CTRL (0x0c) +#define USB3_DP_COM_POWER_DOWN_CTRL (0x08) + + + +#endif /* _DP_REG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c new file mode 100644 index 0000000000000000000000000000000000000000..2bd3bd42912c181fa6361f51d6a0377fda4d76c5 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2012-2017, 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) "[drm-dp] %s: " fmt, __func__ + +#include +#include + +#include "dp_usbpd.h" + +/* DP specific VDM commands */ +#define DP_USBPD_VDM_STATUS 0x10 +#define DP_USBPD_VDM_CONFIGURE 0x11 + +/* USBPD-TypeC specific Macros */ +#define VDM_VERSION 0x0 +#define USB_C_DP_SID 0xFF01 + +enum dp_usbpd_pin_assignment { + DP_USBPD_PIN_A, + DP_USBPD_PIN_B, + DP_USBPD_PIN_C, + DP_USBPD_PIN_D, + DP_USBPD_PIN_E, + DP_USBPD_PIN_F, + DP_USBPD_PIN_MAX, +}; + +enum dp_usbpd_events { + DP_USBPD_EVT_DISCOVER, + DP_USBPD_EVT_ENTER, + DP_USBPD_EVT_STATUS, + DP_USBPD_EVT_CONFIGURE, + DP_USBPD_EVT_CC_PIN_POLARITY, + DP_USBPD_EVT_EXIT, + DP_USBPD_EVT_ATTENTION, +}; + +enum dp_usbpd_alt_mode { + DP_USBPD_ALT_MODE_NONE = 0, + DP_USBPD_ALT_MODE_INIT = BIT(0), + DP_USBPD_ALT_MODE_DISCOVER = BIT(1), + DP_USBPD_ALT_MODE_ENTER = BIT(2), + DP_USBPD_ALT_MODE_STATUS = BIT(3), + DP_USBPD_ALT_MODE_CONFIGURE = BIT(4), +}; + +struct dp_usbpd_capabilities { + enum dp_usbpd_port port; + bool receptacle_state; + u8 ulink_pin_config; + u8 dlink_pin_config; +}; + +struct dp_usbpd_private { + bool forced_disconnect; + u32 vdo; + struct device *dev; + struct usbpd *pd; + struct usbpd_svid_handler svid_handler; + struct dp_usbpd_cb *dp_cb; + struct dp_usbpd_capabilities cap; + struct dp_usbpd dp_usbpd; + enum dp_usbpd_alt_mode alt_mode; + u32 dp_usbpd_config; +}; + +static const char *dp_usbpd_pin_name(u8 pin) +{ + switch (pin) { + case DP_USBPD_PIN_A: return "DP_USBPD_PIN_ASSIGNMENT_A"; + case DP_USBPD_PIN_B: return "DP_USBPD_PIN_ASSIGNMENT_B"; + case DP_USBPD_PIN_C: return "DP_USBPD_PIN_ASSIGNMENT_C"; + case DP_USBPD_PIN_D: return "DP_USBPD_PIN_ASSIGNMENT_D"; + case DP_USBPD_PIN_E: return "DP_USBPD_PIN_ASSIGNMENT_E"; + case DP_USBPD_PIN_F: return "DP_USBPD_PIN_ASSIGNMENT_F"; + default: return "UNKNOWN"; + } +} + +static const char *dp_usbpd_port_name(enum dp_usbpd_port port) +{ + switch (port) { + case DP_USBPD_PORT_NONE: return "DP_USBPD_PORT_NONE"; + case DP_USBPD_PORT_UFP_D: return "DP_USBPD_PORT_UFP_D"; + case DP_USBPD_PORT_DFP_D: return "DP_USBPD_PORT_DFP_D"; + case DP_USBPD_PORT_D_UFP_D: return "DP_USBPD_PORT_D_UFP_D"; + default: return "DP_USBPD_PORT_NONE"; + } +} + +static const char *dp_usbpd_cmd_name(u8 cmd) +{ + switch (cmd) { + case USBPD_SVDM_DISCOVER_MODES: return "USBPD_SVDM_DISCOVER_MODES"; + case USBPD_SVDM_ENTER_MODE: return "USBPD_SVDM_ENTER_MODE"; + case USBPD_SVDM_ATTENTION: return "USBPD_SVDM_ATTENTION"; + case DP_USBPD_VDM_STATUS: return "DP_USBPD_VDM_STATUS"; + case DP_USBPD_VDM_CONFIGURE: return "DP_USBPD_VDM_CONFIGURE"; + default: return "DP_USBPD_VDM_ERROR"; + } +} + +static void dp_usbpd_init_port(enum dp_usbpd_port *port, u32 in_port) +{ + switch (in_port) { + case 0: + *port = DP_USBPD_PORT_NONE; + break; + case 1: + *port = DP_USBPD_PORT_UFP_D; + break; + case 2: + *port = DP_USBPD_PORT_DFP_D; + break; + case 3: + *port = DP_USBPD_PORT_D_UFP_D; + break; + default: + *port = DP_USBPD_PORT_NONE; + } + pr_debug("port:%s\n", dp_usbpd_port_name(*port)); +} + +static void dp_usbpd_get_capabilities(struct dp_usbpd_private *pd) +{ + struct dp_usbpd_capabilities *cap = &pd->cap; + u32 buf = pd->vdo; + int port = buf & 0x3; + + cap->receptacle_state = (buf & BIT(6)) ? true : false; + cap->dlink_pin_config = (buf >> 8) & 0xff; + cap->ulink_pin_config = (buf >> 16) & 0xff; + + dp_usbpd_init_port(&cap->port, port); +} + +static void dp_usbpd_get_status(struct dp_usbpd_private *pd) +{ + struct dp_usbpd *status = &pd->dp_usbpd; + u32 buf = pd->vdo; + int port = buf & 0x3; + + status->low_pow_st = (buf & BIT(2)) ? true : false; + status->adaptor_dp_en = (buf & BIT(3)) ? true : false; + status->multi_func = (buf & BIT(4)) ? true : false; + status->usb_config_req = (buf & BIT(5)) ? true : false; + status->exit_dp_mode = (buf & BIT(6)) ? true : false; + status->hpd_high = (buf & BIT(7)) ? true : false; + status->hpd_irq = (buf & BIT(8)) ? true : false; + + pr_debug("low_pow_st = %d, adaptor_dp_en = %d, multi_func = %d\n", + status->low_pow_st, status->adaptor_dp_en, + status->multi_func); + pr_debug("usb_config_req = %d, exit_dp_mode = %d, hpd_high =%d\n", + status->usb_config_req, + status->exit_dp_mode, status->hpd_high); + pr_debug("hpd_irq = %d\n", status->hpd_irq); + + dp_usbpd_init_port(&status->port, port); +} + +static u32 dp_usbpd_gen_config_pkt(struct dp_usbpd_private *pd) +{ + u8 pin_cfg, pin; + u32 config = 0; + const u32 ufp_d_config = 0x2, dp_ver = 0x1; + + if (pd->cap.receptacle_state) + pin_cfg = pd->cap.ulink_pin_config; + else + pin_cfg = pd->cap.dlink_pin_config; + + for (pin = DP_USBPD_PIN_A; pin < DP_USBPD_PIN_MAX; pin++) { + if (pin_cfg & BIT(pin)) { + if (pd->dp_usbpd.multi_func) { + if (pin == DP_USBPD_PIN_D) + break; + } else { + break; + } + } + } + + if (pin == DP_USBPD_PIN_MAX) + pin = DP_USBPD_PIN_C; + + pr_debug("pin assignment: %s\n", dp_usbpd_pin_name(pin)); + + config |= BIT(pin) << 8; + + config |= (dp_ver << 2); + config |= ufp_d_config; + + pr_debug("config = 0x%x\n", config); + return config; +} + +static void dp_usbpd_send_event(struct dp_usbpd_private *pd, + enum dp_usbpd_events event) +{ + u32 config; + + switch (event) { + case DP_USBPD_EVT_DISCOVER: + usbpd_send_svdm(pd->pd, USB_C_DP_SID, + USBPD_SVDM_DISCOVER_MODES, + SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0); + break; + case DP_USBPD_EVT_ENTER: + usbpd_send_svdm(pd->pd, USB_C_DP_SID, + USBPD_SVDM_ENTER_MODE, + SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); + break; + case DP_USBPD_EVT_EXIT: + usbpd_send_svdm(pd->pd, USB_C_DP_SID, + USBPD_SVDM_EXIT_MODE, + SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); + break; + case DP_USBPD_EVT_STATUS: + config = 0x1; /* DFP_D connected */ + usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_STATUS, + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); + break; + case DP_USBPD_EVT_CONFIGURE: + config = dp_usbpd_gen_config_pkt(pd); + usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_CONFIGURE, + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); + break; + default: + pr_err("unknown event:%d\n", event); + } +} + +static void dp_usbpd_connect_cb(struct usbpd_svid_handler *hdlr) +{ + struct dp_usbpd_private *pd; + + pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); + if (!pd) { + pr_err("get_usbpd phandle failed\n"); + return; + } + + pr_debug("\n"); + dp_usbpd_send_event(pd, DP_USBPD_EVT_DISCOVER); +} + +static void dp_usbpd_disconnect_cb(struct usbpd_svid_handler *hdlr) +{ + struct dp_usbpd_private *pd; + + pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); + if (!pd) { + pr_err("get_usbpd phandle failed\n"); + return; + } + + pd->alt_mode = DP_USBPD_ALT_MODE_NONE; + pd->dp_usbpd.alt_mode_cfg_done = false; + pr_debug("\n"); + + if (pd->dp_cb && pd->dp_cb->disconnect) + pd->dp_cb->disconnect(pd->dev); +} + +static int dp_usbpd_validate_callback(u8 cmd, + enum usbpd_svdm_cmd_type cmd_type, int num_vdos) +{ + int ret = 0; + + if (cmd_type == SVDM_CMD_TYPE_RESP_NAK) { + pr_err("error: NACK\n"); + ret = -EINVAL; + goto end; + } + + if (cmd_type == SVDM_CMD_TYPE_RESP_BUSY) { + pr_err("error: BUSY\n"); + ret = -EBUSY; + goto end; + } + + if (cmd == USBPD_SVDM_ATTENTION) { + if (cmd_type != SVDM_CMD_TYPE_INITIATOR) { + pr_err("error: invalid cmd type for attention\n"); + ret = -EINVAL; + goto end; + } + + if (!num_vdos) { + pr_err("error: no vdo provided\n"); + ret = -EINVAL; + goto end; + } + } else { + if (cmd_type != SVDM_CMD_TYPE_RESP_ACK) { + pr_err("error: invalid cmd type\n"); + ret = -EINVAL; + } + } +end: + return ret; +} + +static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd, + enum usbpd_svdm_cmd_type cmd_type, + const u32 *vdos, int num_vdos) +{ + struct dp_usbpd_private *pd; + + pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); + + pr_debug("callback -> cmd: %s, *vdos = 0x%x, num_vdos = %d\n", + dp_usbpd_cmd_name(cmd), *vdos, num_vdos); + + if (dp_usbpd_validate_callback(cmd, cmd_type, num_vdos)) { + pr_debug("invalid callback received\n"); + return; + } + + switch (cmd) { + case USBPD_SVDM_DISCOVER_MODES: + pd->vdo = *vdos; + dp_usbpd_get_capabilities(pd); + + pd->alt_mode |= DP_USBPD_ALT_MODE_DISCOVER; + + if (pd->cap.port & BIT(0)) + dp_usbpd_send_event(pd, DP_USBPD_EVT_ENTER); + break; + case USBPD_SVDM_ENTER_MODE: + pd->alt_mode |= DP_USBPD_ALT_MODE_ENTER; + + dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS); + break; + case USBPD_SVDM_ATTENTION: + if (pd->forced_disconnect) + break; + + pd->vdo = *vdos; + dp_usbpd_get_status(pd); + + if (!pd->dp_usbpd.alt_mode_cfg_done) { + if (pd->dp_usbpd.port & BIT(1)) + dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE); + break; + } + + if (pd->dp_cb && pd->dp_cb->attention) + pd->dp_cb->attention(pd->dev); + + break; + case DP_USBPD_VDM_STATUS: + pd->vdo = *vdos; + dp_usbpd_get_status(pd); + + if (!(pd->alt_mode & DP_USBPD_ALT_MODE_CONFIGURE)) { + pd->alt_mode |= DP_USBPD_ALT_MODE_STATUS; + + if (pd->dp_usbpd.port & BIT(1)) + dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE); + } + break; + case DP_USBPD_VDM_CONFIGURE: + pd->alt_mode |= DP_USBPD_ALT_MODE_CONFIGURE; + pd->dp_usbpd.alt_mode_cfg_done = true; + dp_usbpd_get_status(pd); + + pd->dp_usbpd.orientation = usbpd_get_plug_orientation(pd->pd); + + /* + * By default, USB reserves two lanes for Super Speed. + * Which means DP has remaining two lanes to operate on. + * If multi-function is not supported, request USB to + * release the Super Speed lanes so that DP can use + * all four lanes in case DPCD indicates support for + * four lanes. + */ + if (!pd->dp_usbpd.multi_func) + pd->svid_handler.request_usb_ss_lane(pd->pd, + &pd->svid_handler); + + if (pd->dp_cb && pd->dp_cb->configure) + pd->dp_cb->configure(pd->dev); + break; + default: + pr_err("unknown cmd: %d\n", cmd); + break; + } +} + +static int dp_usbpd_simulate_connect(struct dp_usbpd *dp_usbpd, bool hpd) +{ + int rc = 0; + struct dp_usbpd_private *pd; + + if (!dp_usbpd) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + dp_usbpd->hpd_high = hpd; + pd->forced_disconnect = !hpd; + + if (hpd) + pd->dp_cb->configure(pd->dev); + else + pd->dp_cb->disconnect(pd->dev); + +error: + return rc; +} + +struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb) +{ + int rc = 0; + const char *pd_phandle = "qcom,dp-usbpd-detection"; + struct usbpd *pd = NULL; + struct dp_usbpd_private *usbpd; + struct dp_usbpd *dp_usbpd; + struct usbpd_svid_handler svid_handler = { + .svid = USB_C_DP_SID, + .vdm_received = NULL, + .connect = &dp_usbpd_connect_cb, + .svdm_received = &dp_usbpd_response_cb, + .disconnect = &dp_usbpd_disconnect_cb, + }; + + if (!cb) { + pr_err("invalid cb data\n"); + rc = -EINVAL; + goto error; + } + + pd = devm_usbpd_get_by_phandle(dev, pd_phandle); + if (IS_ERR(pd)) { + pr_err("usbpd phandle failed (%ld)\n", PTR_ERR(pd)); + rc = PTR_ERR(pd); + goto error; + } + + usbpd = devm_kzalloc(dev, sizeof(*usbpd), GFP_KERNEL); + if (!usbpd) { + rc = -ENOMEM; + goto error; + } + + usbpd->dev = dev; + usbpd->pd = pd; + usbpd->svid_handler = svid_handler; + usbpd->dp_cb = cb; + + rc = usbpd_register_svid(pd, &usbpd->svid_handler); + if (rc) { + pr_err("pd registration failed\n"); + rc = -ENODEV; + devm_kfree(dev, usbpd); + goto error; + } + + dp_usbpd = &usbpd->dp_usbpd; + dp_usbpd->simulate_connect = dp_usbpd_simulate_connect; + + return dp_usbpd; +error: + return ERR_PTR(rc); +} + +void dp_usbpd_put(struct dp_usbpd *dp_usbpd) +{ + struct dp_usbpd_private *usbpd; + + if (!dp_usbpd) + return; + + usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + usbpd_unregister_svid(usbpd->pd, &usbpd->svid_handler); + + devm_kfree(usbpd->dev, usbpd); +} diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h new file mode 100644 index 0000000000000000000000000000000000000000..e70ad7d4430fe8bd07209abd98958998af087a14 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012-2017, 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 _DP_USBPD_H_ +#define _DP_USBPD_H_ + +#include + +#include +#include + +/** + * enum dp_usbpd_port - usb/dp port type + * @DP_USBPD_PORT_NONE: port not configured + * @DP_USBPD_PORT_UFP_D: Upstream Facing Port - DisplayPort + * @DP_USBPD_PORT_DFP_D: Downstream Facing Port - DisplayPort + * @DP_USBPD_PORT_D_UFP_D: Both UFP & DFP - DisplayPort + */ + +enum dp_usbpd_port { + DP_USBPD_PORT_NONE, + DP_USBPD_PORT_UFP_D, + DP_USBPD_PORT_DFP_D, + DP_USBPD_PORT_D_UFP_D, +}; + +/** + * struct dp_usbpd - DisplayPort status + * + * @port: port configured + * orientation: plug orientation configuration + * @low_pow_st: low power state + * @adaptor_dp_en: adaptor functionality enabled + * @multi_func: multi-function preferred + * @usb_config_req: request to switch to usb + * @exit_dp_mode: request exit from displayport mode + * @hpd_high: Hot Plug Detect signal is high. + * @hpd_irq: Change in the status since last message + * @alt_mode_cfg_done: bool to specify alt mode status + * @debug_en: bool to specify debug mode + * @simulate_connect: simulate disconnect or connect for debug mode + */ +struct dp_usbpd { + enum dp_usbpd_port port; + enum plug_orientation orientation; + bool low_pow_st; + bool adaptor_dp_en; + bool multi_func; + bool usb_config_req; + bool exit_dp_mode; + bool hpd_high; + bool hpd_irq; + bool alt_mode_cfg_done; + bool debug_en; + + int (*simulate_connect)(struct dp_usbpd *dp_usbpd, bool hpd); +}; + +/** + * struct dp_usbpd_cb - callback functions provided by the client + * + * @configure: called by usbpd module when PD communication has + * been completed and the usb peripheral has been configured on + * dp mode. + * @disconnect: notify the cable disconnect issued by usb. + * @attention: notify any attention message issued by usb. + */ +struct dp_usbpd_cb { + int (*configure)(struct device *dev); + int (*disconnect)(struct device *dev); + int (*attention)(struct device *dev); +}; + +/** + * dp_usbpd_get() - setup usbpd module + * + * @dev: device instance of the caller + * @cb: struct containing callback function pointers. + * + * This function allows the client to initialize the usbpd + * module. The module will communicate with usb driver and + * handles the power delivery (PD) communication with the + * sink/usb device. This module will notify the client using + * the callback functions about the connection and status. + */ +struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb); + +void dp_usbpd_put(struct dp_usbpd *pd); +#endif /* _DP_USBPD_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c index 3625ed08168a27195d9ec940b4211b03d7f2abde..f2c29852f49d5fb9c753e404b264c5aa2edc24c6 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c @@ -28,6 +28,7 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.video_engine_en = dsi_ctrl_hw_cmn_video_engine_en; ctrl->ops.video_engine_setup = dsi_ctrl_hw_cmn_video_engine_setup; ctrl->ops.set_video_timing = dsi_ctrl_hw_cmn_set_video_timing; + ctrl->ops.set_timing_db = dsi_ctrl_hw_cmn_set_timing_db; ctrl->ops.cmd_engine_setup = dsi_ctrl_hw_cmn_cmd_engine_setup; ctrl->ops.setup_cmd_stream = dsi_ctrl_hw_cmn_setup_cmd_stream; ctrl->ops.ctrl_en = dsi_ctrl_hw_cmn_ctrl_en; @@ -56,6 +57,16 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, dsi_ctrl_hw_cmn_trigger_cmd_test_pattern; ctrl->ops.clear_phy0_ln_err = dsi_ctrl_hw_dln0_phy_err; ctrl->ops.phy_reset_config = dsi_ctrl_hw_cmn_phy_reset_config; + ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr; + ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr; + ctrl->ops.debug_bus = dsi_ctrl_hw_cmn_debug_bus; + ctrl->ops.get_cmd_read_data = dsi_ctrl_hw_cmn_get_cmd_read_data; + ctrl->ops.clear_rdbk_register = dsi_ctrl_hw_cmn_clear_rdbk_reg; + ctrl->ops.ctrl_reset = dsi_ctrl_hw_cmn_ctrl_reset; + ctrl->ops.mask_error_intr = dsi_ctrl_hw_cmn_mask_error_intr; + ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl; + ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask; + ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version; switch (version) { case DSI_CTRL_VERSION_1_4: @@ -70,6 +81,9 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.clamp_disable = dsi_ctrl_hw_14_clamp_disable; ctrl->ops.reg_dump_to_buffer = dsi_ctrl_hw_14_reg_dump_to_buffer; + ctrl->ops.schedule_dma_cmd = NULL; + ctrl->ops.get_cont_splash_status = NULL; + ctrl->ops.kickoff_command_non_embedded_mode = NULL; break; case DSI_CTRL_VERSION_2_0: ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map; @@ -82,9 +96,14 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL; ctrl->ops.clamp_enable = NULL; ctrl->ops.clamp_disable = NULL; + ctrl->ops.schedule_dma_cmd = NULL; + ctrl->ops.get_cont_splash_status = NULL; + ctrl->ops.kickoff_command_non_embedded_mode = NULL; break; case DSI_CTRL_VERSION_2_2: ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config; + ctrl->ops.get_cont_splash_status = + dsi_ctrl_hw_22_get_cont_splash_status; ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map; ctrl->ops.wait_for_lane_idle = dsi_ctrl_hw_20_wait_for_lane_idle; @@ -95,6 +114,9 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL; ctrl->ops.clamp_enable = NULL; ctrl->ops.clamp_disable = NULL; + ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd; + ctrl->ops.kickoff_command_non_embedded_mode = + dsi_ctrl_hw_kickoff_non_embedded_mode; break; default: break; @@ -106,14 +128,16 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, * @ctrl: Pointer to DSI controller hw object. * @version: DSI controller version. * @index: DSI controller instance ID. + * @phy_isolation_enabled: DSI controller works isolated from phy. + * @null_insertion_enabled: DSI controller inserts null packet. * * This function setups the catalog information in the dsi_ctrl_hw object. * * return: error code for failure and 0 for success. */ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_ctrl_version version, - u32 index) + enum dsi_ctrl_version version, u32 index, + bool phy_isolation_enabled, bool null_insertion_enabled) { int rc = 0; @@ -124,6 +148,7 @@ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, } ctrl->index = index; + ctrl->null_insertion_enabled = null_insertion_enabled; set_bit(DSI_CTRL_VIDEO_TPG, ctrl->feature_map); set_bit(DSI_CTRL_CMD_TPG, ctrl->feature_map); set_bit(DSI_CTRL_VARIABLE_REFRESH_RATE, ctrl->feature_map); @@ -133,8 +158,11 @@ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, switch (version) { case DSI_CTRL_VERSION_1_4: + dsi_catalog_cmn_init(ctrl, version); + break; case DSI_CTRL_VERSION_2_0: case DSI_CTRL_VERSION_2_2: + ctrl->phy_isolation_enabled = phy_isolation_enabled; dsi_catalog_cmn_init(ctrl, version); break; default: @@ -184,6 +212,7 @@ static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy) phy->ops.ulps_ops.is_lanes_in_ulps = dsi_phy_hw_v3_0_is_lanes_in_ulps; phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0; + phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset; } /** diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h index 5dcdf467faa4b86076317b932bfb0d62c243d05b..f7756dcb6d6e2d494a8f237c7ed03b9577c03b7a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h @@ -23,14 +23,16 @@ * @ctrl: Pointer to DSI controller hw object. * @version: DSI controller version. * @index: DSI controller instance ID. + * @phy_isolation_enabled: DSI controller works isolated from phy. + * @null_insertion_enabled: DSI controller inserts null packet. * * This function setups the catalog information in the dsi_ctrl_hw object. * * return: error code for failure and 0 for success. */ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, - enum dsi_ctrl_version version, - u32 index); + enum dsi_ctrl_version version, u32 index, + bool phy_isolation_enabled, bool null_insertion_enabled); /** * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware @@ -100,9 +102,11 @@ u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy); bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes); int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg, u32 *timing_val, u32 size); +int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy); /* DSI controller common ops */ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl); void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints); void dsi_ctrl_hw_cmn_enable_status_interrupts(struct dsi_ctrl_hw *ctrl, u32 ints); @@ -131,7 +135,8 @@ void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl, struct dsi_video_engine_cfg *cfg); void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode); - +void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl, + bool enable); void dsi_ctrl_hw_cmn_cmd_engine_setup(struct dsi_ctrl_hw *ctrl, struct dsi_host_common_cfg *common_cfg, struct dsi_cmd_engine_cfg *cfg); @@ -142,10 +147,17 @@ void dsi_ctrl_hw_cmn_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on); void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode, u32 h_stride, - u32 vc_id); + u32 vc_id, + struct dsi_rect *roi); void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl); void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode, + bool enable, u32 frame_count); +u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode); + void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl, struct dsi_ctrl_cmd_dma_info *cmd, u32 flags); @@ -160,6 +172,20 @@ void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl, bool enable); void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl, bool enable); +u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, + u8 *rd_buf, + u32 read_offset, + u32 rx_byte, + u32 pkt_size, u32 *hw_read_cnt); +void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_on); +int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl, + int mask); +void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, + bool en); +void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en); +u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl); +u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl); /* Definitions specific to 1.4 DSI controller hardware */ int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); @@ -187,5 +213,11 @@ int dsi_ctrl_hw_20_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, char *buf, u32 size); +void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags); + +/* Definitions specific to 2.2 DSI controller hardware */ +bool dsi_ctrl_hw_22_get_cont_splash_status(struct dsi_ctrl_hw *ctrl); #endif /* _DSI_CATALOG_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h index 2a84a2d93847529c86c5e83f99deddfcb832ee2c..1fd10d990c03173c8a7b555cbfaad219e00e6a09 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h @@ -197,6 +197,13 @@ struct dsi_clk_link_set { struct clk *pixel_clk; }; +/** + * dsi_display_clk_mngr_update_splash_status() - Update splash stattus + * @clk_mngr: Structure containing DSI clock information + * @status: Splash status + */ +void dsi_display_clk_mngr_update_splash_status(void *clk_mgr, bool status); + /** * dsi_display_clk_mgr_register() - Register DSI clock manager * @info: Structure containing DSI clock information diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c index 560964e670d0438af116d51def3bf79b68f10ea2..38eba8de48dd45c267f4f5e14698f4b34b8f9bcd 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c @@ -46,6 +46,7 @@ struct dsi_clk_mngr { post_clockon_cb post_clkon_cb; pre_clockon_cb pre_clkon_cb; + bool is_cont_splash_enabled; void *priv_data; }; @@ -284,10 +285,25 @@ int dsi_core_clk_stop(struct dsi_core_clks *c_clks) return rc; } -static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) +static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index) { int rc = 0; + struct dsi_clk_mngr *mngr; + if (index >= MAX_DSI_CTRL) { + pr_err("Invalid DSI ctrl index\n"); + return -EINVAL; + } + + mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]); + if (mngr->is_cont_splash_enabled) + return 0; + /* + * In an ideal world, cont_splash_enabled should not be required inside + * the clock manager. But, in the current driver cont_splash_enabled + * flag is set inside mdp driver and there is no interface event + * associated with this flag setting. + */ rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->freq.esc_clk_rate); if (rc) { pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); @@ -431,11 +447,16 @@ static void dsi_link_clk_disable(struct dsi_link_clks *l_clks) /** * dsi_link_clk_start() - enable dsi link clocks */ -int dsi_link_clk_start(struct dsi_link_clks *clks) +static int dsi_link_clk_start(struct dsi_link_clks *clks, int index) { int rc = 0; - rc = dsi_link_clk_set_rate(clks); + if (index >= MAX_DSI_CTRL) { + pr_err("Invalid DSI ctrl index\n"); + return -EINVAL; + } + + rc = dsi_link_clk_set_rate(clks, index); if (rc) { pr_err("failed to set clk rates, rc = %d\n", rc); goto error; @@ -549,7 +570,7 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, m_clks = &clks[master_ndx]; - rc = dsi_link_clk_start(m_clks); + rc = dsi_link_clk_start(m_clks, master_ndx); if (rc) { pr_err("failed to turn on master clocks, rc=%d\n", rc); goto error; @@ -561,7 +582,7 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, if (!clk || (clk == m_clks)) continue; - rc = dsi_link_clk_start(clk); + rc = dsi_link_clk_start(clk, i); if (rc) { pr_err("failed to turn on clocks, rc=%d\n", rc); goto error_disable_master; @@ -1143,6 +1164,19 @@ int dsi_deregister_clk_handle(void *client) return rc; } +void dsi_display_clk_mngr_update_splash_status(void *clk_mgr, bool status) +{ + struct dsi_clk_mngr *mngr; + + if (!clk_mgr) { + pr_err("Invalid params\n"); + return; + } + + mngr = (struct dsi_clk_mngr *)clk_mgr; + mngr->is_cont_splash_enabled = status; +} + void *dsi_display_clk_mngr_register(struct dsi_clk_info *info) { struct dsi_clk_mngr *mngr; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 9a71ea029681e998e11f5346581cb82bf1345af8..bfbcf5457b482dc3efc34a90a1cbda8c100231e0 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -9,7 +9,6 @@ * 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) "dsi-ctrl:[%s] " fmt, __func__ @@ -25,17 +24,22 @@ #include "msm_drv.h" #include "msm_kms.h" #include "msm_gpu.h" +#include "msm_mmu.h" #include "dsi_ctrl.h" #include "dsi_ctrl_hw.h" #include "dsi_clk.h" #include "dsi_pwr.h" #include "dsi_catalog.h" +#include "sde_dbg.h" + #define DSI_CTRL_DEFAULT_LABEL "MDSS DSI CTRL" #define DSI_CTRL_TX_TO_MS 200 #define TO_ON_OFF(x) ((x) ? "ON" : "OFF") + +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) /** * enum dsi_ctrl_driver_ops - controller driver ops */ @@ -199,6 +203,7 @@ static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, { int rc = 0; struct dentry *dir, *state_file, *reg_dump; + char dbg_name[DSI_DEBUG_NAME_LEN]; dir = debugfs_create_dir(dsi_ctrl->name, parent); if (IS_ERR_OR_NULL(dir)) { @@ -233,6 +238,11 @@ static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, } dsi_ctrl->debugfs_root = dir; + + snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl", + dsi_ctrl->cell_index); + sde_dbg_reg_register_base(dbg_name, dsi_ctrl->hw.base, + msm_iomap_size(dsi_ctrl->pdev, "dsi_ctrl")); error_remove_dir: debugfs_remove(dir); error: @@ -245,6 +255,16 @@ static int dsi_ctrl_debugfs_deinit(struct dsi_ctrl *dsi_ctrl) return 0; } +static inline struct msm_gem_address_space* +dsi_ctrl_get_aspace(struct dsi_ctrl *dsi_ctrl, + int domain) +{ + if (!dsi_ctrl || !dsi_ctrl->drm_dev) + return NULL; + + return msm_gem_smmu_address_space_get(dsi_ctrl->drm_dev, domain); +} + static int dsi_ctrl_check_state(struct dsi_ctrl *dsi_ctrl, enum dsi_ctrl_driver_ops op, u32 op_state) @@ -259,15 +279,11 @@ static int dsi_ctrl_check_state(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->cell_index, op_state); rc = -EINVAL; } else if (state->power_state == DSI_CTRL_POWER_VREG_ON) { - if ((state->cmd_engine_state == DSI_CTRL_ENGINE_ON) || - (state->vid_engine_state == DSI_CTRL_ENGINE_ON) || - (state->controller_state == DSI_CTRL_ENGINE_ON)) { - pr_debug("[%d]State error: op=%d: %d, %d, %d\n", + if (state->vid_engine_state == DSI_CTRL_ENGINE_ON) { + pr_debug("[%d]State error: op=%d: %d\n", dsi_ctrl->cell_index, op_state, - state->cmd_engine_state, - state->vid_engine_state, - state->controller_state); + state->vid_engine_state); rc = -EINVAL; } } @@ -701,7 +717,7 @@ static int dsi_ctrl_axi_bus_client_init(struct platform_device *pdev, bus->bus_scale_table = msm_bus_cl_get_pdata(pdev); if (IS_ERR_OR_NULL(bus->bus_scale_table)) { rc = PTR_ERR(bus->bus_scale_table); - pr_err("msm_bus_cl_get_pdata() failed, rc = %d\n", rc); + pr_debug("msm_bus_cl_get_pdata() failed, rc = %d\n", rc); bus->bus_scale_table = NULL; return rc; } @@ -769,10 +785,14 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, if (host_cfg->data_lanes & DSI_DATA_LANE_3) num_of_lanes++; - h_period = DSI_H_TOTAL_DSC(timing); - v_period = DSI_V_TOTAL(timing); + if (config->bit_clk_rate_hz == 0) { + h_period = DSI_H_TOTAL_DSC(timing); + v_period = DSI_V_TOTAL(timing); + bit_rate = h_period * v_period * timing->refresh_rate * bpp * 8; + } else { + bit_rate = config->bit_clk_rate_hz * num_of_lanes; + } - bit_rate = h_period * v_period * timing->refresh_rate * bpp * 8; bit_rate_per_lane = bit_rate; do_div(bit_rate_per_lane, num_of_lanes); pclk_rate = bit_rate; @@ -869,45 +889,203 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl, if (packet->payload_length > 0) buf[3] |= BIT(6); - buf[3] |= BIT(7); + + /* send embedded BTA for read commands */ + if ((buf[2] & 0x3f) == MIPI_DSI_DCS_READ) + buf[3] |= BIT(5); + *buffer = buf; *size = len; return rc; } +static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl) +{ + u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret; + struct dsi_mode_info *timing; + + /** + * No need to wait if the panel is not video mode or + * if DSI controller supports command DMA scheduling or + * if we are sending init commands. + */ + if ((dsi_ctrl->host_config.panel_mode != DSI_OP_VIDEO_MODE) || + (dsi_ctrl->version >= DSI_CTRL_VERSION_2_2) || + (dsi_ctrl->current_state.vid_engine_state != + DSI_CTRL_ENGINE_ON)) + return; + + dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, + DSI_VIDEO_MODE_FRAME_DONE); + + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_VIDEO_MODE_FRAME_DONE, NULL); + reinit_completion(&dsi_ctrl->irq_info.vid_frame_done); + ret = wait_for_completion_timeout( + &dsi_ctrl->irq_info.vid_frame_done, + msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); + if (ret <= 0) + pr_debug("wait for video done failed\n"); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_VIDEO_MODE_FRAME_DONE); + + timing = &(dsi_ctrl->host_config.video_timing); + v_total = timing->v_sync_width + timing->v_back_porch + + timing->v_front_porch + timing->v_active; + v_blank = timing->v_sync_width + timing->v_back_porch; + fps = timing->refresh_rate; + + sleep_ms = CEIL((v_blank * 1000), (v_total * fps)) + 1; + udelay(sleep_ms * 1000); +} + +void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, + u32 cmd_len, + u32 *flags) +{ + /** + * Setup the mode of transmission + * override cmd fetch mode during secure session + */ + if (dsi_ctrl->secure_mode) { + *flags &= ~DSI_CTRL_CMD_FETCH_MEMORY; + *flags |= DSI_CTRL_CMD_FIFO_STORE; + pr_debug("[%s] override to TPG during secure session\n", + dsi_ctrl->name); + return; + } + + /* Check to see if cmd len plus header is greater than fifo size */ + if ((cmd_len + 4) > DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES) { + *flags |= DSI_CTRL_CMD_NON_EMBEDDED_MODE; + pr_debug("[%s] override to non-embedded mode,cmd len =%d\n", + dsi_ctrl->name, cmd_len); + return; + } +} + +int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, + u32 cmd_len, + u32 *flags) +{ + int rc = 0; + + if (*flags & DSI_CTRL_CMD_FIFO_STORE) { + /* if command size plus header is greater than fifo size */ + if ((cmd_len + 4) > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE) { + pr_err("Cannot transfer Cmd in FIFO config\n"); + return -ENOTSUPP; + } + if (!dsi_ctrl->hw.ops.kickoff_fifo_command) { + pr_err("Cannot transfer command,ops not defined\n"); + return -ENOTSUPP; + } + } + + if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + if (*flags & DSI_CTRL_CMD_BROADCAST) { + pr_err("Non embedded not supported with broadcast\n"); + return -ENOTSUPP; + } + if (!dsi_ctrl->hw.ops.kickoff_command_non_embedded_mode) { + pr_err(" Cannot transfer command,ops not defined\n"); + return -ENOTSUPP; + } + } + return rc; +} + static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, u32 flags) { - int rc = 0; + int rc = 0, ret = 0; struct mipi_dsi_packet packet; struct dsi_ctrl_cmd_dma_fifo_info cmd; + struct dsi_ctrl_cmd_dma_info cmd_mem; u32 hw_flags = 0; u32 length = 0; u8 *buffer = NULL; + u32 cnt = 0, line_no = 0x1; + u8 *cmdbuf; + struct dsi_mode_info *timing; + + /* Select the tx mode to transfer the command */ + dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, &flags); - if (!(flags & DSI_CTRL_CMD_FIFO_STORE)) { - pr_err("Memory DMA is not supported, use FIFO\n"); + /* Validate the mode before sending the command */ + rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, &flags); + if (rc) { + pr_err(" Cmd tx validation failed, cannot transfer cmd\n"); + rc = -ENOTSUPP; goto error; } + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; + cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ? + true : false; + cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + true : false; + cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? + true : false; + cmd_mem.datatype = msg->type; + cmd_mem.length = msg->tx_len; + + dsi_ctrl->cmd_len = msg->tx_len; + memcpy(dsi_ctrl->vaddr, msg->tx_buf, msg->tx_len); + pr_debug(" non-embedded mode , size of command =%zd\n", + msg->tx_len); + + goto kickoff; + } + rc = mipi_dsi_create_packet(&packet, msg); if (rc) { pr_err("Failed to create message packet, rc=%d\n", rc); goto error; } - if (flags & DSI_CTRL_CMD_FIFO_STORE) { - rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl, - &packet, - &buffer, - &length); - if (rc) { - pr_err("[%s] failed to copy message, rc=%d\n", - dsi_ctrl->name, rc); + rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl, + &packet, + &buffer, + &length); + if (rc) { + pr_err("[%s] failed to copy message, rc=%d\n", + dsi_ctrl->name, rc); + goto error; + } + + if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) + buffer[3] |= BIT(7);//set the last cmd bit in header. + + if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { + /* Embedded mode config is selected */ + cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; + cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ? + true : false; + cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + true : false; + cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? + true : false; + + cmdbuf = (u8 *)(dsi_ctrl->vaddr); + + for (cnt = 0; cnt < length; cnt++) + cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt]; + + msm_gem_sync(dsi_ctrl->tx_cmd_buf); + dsi_ctrl->cmd_len += length; + + if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) { goto error; + } else { + cmd_mem.length = dsi_ctrl->cmd_len; + dsi_ctrl->cmd_len = 0; } + + } else if (flags & DSI_CTRL_CMD_FIFO_STORE) { cmd.command = (u32 *)buffer; cmd.size = length; cmd.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ? @@ -918,42 +1096,115 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, true : false; } +kickoff: + timing = &(dsi_ctrl->host_config.video_timing); + if (timing) + line_no += timing->v_back_porch + timing->v_sync_width + + timing->v_active; + if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && + dsi_ctrl->hw.ops.schedule_dma_cmd && + (dsi_ctrl->current_state.vid_engine_state == + DSI_CTRL_ENGINE_ON)) + dsi_ctrl->hw.ops.schedule_dma_cmd(&dsi_ctrl->hw, + line_no); + hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ? DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0; - if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER)) - reinit_completion(&dsi_ctrl->int_info.cmd_dma_done); + if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) + hw_flags |= DSI_CTRL_CMD_LAST_COMMAND; - if (flags & DSI_CTRL_CMD_FIFO_STORE) - dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw, - &cmd, - hw_flags); + if (flags & DSI_CTRL_CMD_DEFER_TRIGGER) { + if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + dsi_ctrl->hw.ops. + kickoff_command_non_embedded_mode( + &dsi_ctrl->hw, + &cmd_mem, + hw_flags); + } else { + dsi_ctrl->hw.ops.kickoff_command( + &dsi_ctrl->hw, + &cmd_mem, + hw_flags); + } + } else if (flags & DSI_CTRL_CMD_FIFO_STORE) { + dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw, + &cmd, + hw_flags); + } + } if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER)) { - u32 retry = 10; - u32 status = 0; - u64 error = 0; - u32 mask = (DSI_CMD_MODE_DMA_DONE); + dsi_ctrl_wait_for_video_done(dsi_ctrl); + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE, NULL); + if (dsi_ctrl->hw.ops.mask_error_intr) + dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, + BIT(DSI_FIFO_OVERFLOW), true); + reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); + + if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + dsi_ctrl->hw.ops. + kickoff_command_non_embedded_mode( + &dsi_ctrl->hw, + &cmd_mem, + hw_flags); + } else { + dsi_ctrl->hw.ops.kickoff_command( + &dsi_ctrl->hw, + &cmd_mem, + hw_flags); + } + } else if (flags & DSI_CTRL_CMD_FIFO_STORE) { + dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw, + &cmd, + hw_flags); + } - while ((status == 0) && (retry > 0)) { - udelay(1000); - status = dsi_ctrl->hw.ops.get_interrupt_status( - &dsi_ctrl->hw); - error = dsi_ctrl->hw.ops.get_error_status( + ret = wait_for_completion_timeout( + &dsi_ctrl->irq_info.cmd_dma_done, + msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); + + if (ret == 0) { + u32 status = dsi_ctrl->hw.ops.get_interrupt_status( &dsi_ctrl->hw); - status &= mask; - retry--; - dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, + u32 mask = DSI_CMD_MODE_DMA_DONE; + + if (status & mask) { + status |= (DSI_CMD_MODE_DMA_DONE | + DSI_BTA_DONE); + dsi_ctrl->hw.ops.clear_interrupt_status( + &dsi_ctrl->hw, status); - dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, - error); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + complete_all(&dsi_ctrl->irq_info.cmd_dma_done); + pr_warn("dma_tx done but irq not triggered\n"); + } else { + rc = -ETIMEDOUT; + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + pr_err("[DSI_%d]Command transfer failed\n", + dsi_ctrl->cell_index); + } } - pr_debug("INT STATUS = %x, retry = %d\n", status, retry); - if (retry == 0) - pr_err("[DSI_%d]Command transfer failed\n", - dsi_ctrl->cell_index); + if (dsi_ctrl->hw.ops.mask_error_intr) + dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, + BIT(DSI_FIFO_OVERFLOW), false); dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw); + + /* + * DSI 2.2 needs a soft reset whenever we send non-embedded + * mode command followed by embedded mode. Otherwise it will + * result in smmu write faults with DSI as client. + */ + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw); + dsi_ctrl->cmd_len = 0; + } } error: if (buffer) @@ -967,6 +1218,7 @@ static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl, { int rc = 0; u8 tx[2] = { (u8)(size & 0xFF), (u8)(size >> 8) }; + u32 flags = DSI_CTRL_CMD_FETCH_MEMORY; struct mipi_dsi_msg msg = { .channel = rx_msg->channel, .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, @@ -974,24 +1226,77 @@ static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl, .tx_buf = tx, }; - rc = dsi_message_tx(dsi_ctrl, &msg, 0x0); + rc = dsi_message_tx(dsi_ctrl, &msg, flags); if (rc) pr_err("failed to send max return size packet, rc=%d\n", rc); return rc; } +/* Helper functions to support DCS read operation */ +static int dsi_parse_short_read1_resp(const struct mipi_dsi_msg *msg, + unsigned char *buff) +{ + u8 *data = msg->rx_buf; + int read_len = 1; + + if (!data) + return 0; + + /* remove dcs type */ + if (msg->rx_len >= 1) + data[0] = buff[1]; + else + read_len = 0; + + return read_len; +} + +static int dsi_parse_short_read2_resp(const struct mipi_dsi_msg *msg, + unsigned char *buff) +{ + u8 *data = msg->rx_buf; + int read_len = 2; + + if (!data) + return 0; + + /* remove dcs type */ + if (msg->rx_len >= 2) { + data[0] = buff[1]; + data[1] = buff[2]; + } else { + read_len = 0; + } + + return read_len; +} + +static int dsi_parse_long_read_resp(const struct mipi_dsi_msg *msg, + unsigned char *buff) +{ + if (!msg->rx_buf) + return 0; + + /* remove dcs type */ + if (msg->rx_buf && msg->rx_len) + memcpy(msg->rx_buf, buff + 4, msg->rx_len); + + return msg->rx_len; +} + static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg, u32 flags) { int rc = 0; - u32 rd_pkt_size; - u32 total_read_len; - u32 bytes_read = 0, tot_bytes_read = 0; - u32 current_read_len; + u32 rd_pkt_size, total_read_len, hw_read_cnt; + u32 current_read_len = 0, total_bytes_read = 0; bool short_resp = false; bool read_done = false; + u32 dlen, diff, rlen = msg->rx_len; + unsigned char *buff; + char cmd; if (msg->rx_len <= 2) { short_resp = true; @@ -1007,6 +1312,7 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, total_read_len = current_read_len + 6; } + buff = msg->rx_buf; while (!read_done) { rc = dsi_set_max_return_size(dsi_ctrl, msg, rd_pkt_size); @@ -1016,24 +1322,79 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, goto error; } + /* clear RDBK_DATA registers before proceeding */ + dsi_ctrl->hw.ops.clear_rdbk_register(&dsi_ctrl->hw); + rc = dsi_message_tx(dsi_ctrl, msg, flags); if (rc) { pr_err("Message transmission failed, rc=%d\n", rc); goto error; } + dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw, + buff, total_bytes_read, + total_read_len, rd_pkt_size, + &hw_read_cnt); + if (!dlen) + goto error; - tot_bytes_read += bytes_read; if (short_resp) + break; + + if (rlen <= current_read_len) { + diff = current_read_len - rlen; read_done = true; - else if (msg->rx_len <= tot_bytes_read) - read_done = true; + } else { + diff = 0; + rlen -= current_read_len; + } + + dlen -= 2; /* 2 bytes of CRC */ + dlen -= diff; + buff += dlen; + total_bytes_read += dlen; + if (!read_done) { + current_read_len = 14; /* Not first read */ + if (rlen < current_read_len) + rd_pkt_size += rlen; + else + rd_pkt_size += current_read_len; + } + } + + if (hw_read_cnt < 16 && !short_resp) + buff = msg->rx_buf + (16 - hw_read_cnt); + else + buff = msg->rx_buf; + + /* parse the data read from panel */ + cmd = buff[0]; + switch (cmd) { + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: + pr_err("Rx ACK_ERROR\n"); + rc = 0; + break; + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: + rc = dsi_parse_short_read1_resp(msg, buff); + break; + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: + rc = dsi_parse_short_read2_resp(msg, buff); + break; + case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: + case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: + rc = dsi_parse_long_read_resp(msg, buff); + break; + default: + pr_warn("Invalid response\n"); + rc = 0; } + error: return rc; } - static int dsi_enable_ulps(struct dsi_ctrl *dsi_ctrl) { int rc = 0; @@ -1120,21 +1481,23 @@ static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl) return rc; } -int dsi_ctrl_intr_deinit(struct dsi_ctrl *dsi_ctrl) -{ - struct dsi_ctrl_interrupts *ints = &dsi_ctrl->int_info; - - devm_free_irq(&dsi_ctrl->pdev->dev, ints->irq, dsi_ctrl); - - return 0; -} - static int dsi_ctrl_buffer_deinit(struct dsi_ctrl *dsi_ctrl) { + struct msm_gem_address_space *aspace = NULL; + if (dsi_ctrl->tx_cmd_buf) { - msm_gem_put_iova(dsi_ctrl->tx_cmd_buf, 0); + aspace = dsi_ctrl_get_aspace(dsi_ctrl, + MSM_SMMU_DOMAIN_UNSECURE); + if (!aspace) { + pr_err("failed to get address space\n"); + return -ENOMEM; + } + msm_gem_put_iova(dsi_ctrl->tx_cmd_buf, aspace); + + mutex_lock(&dsi_ctrl->drm_dev->struct_mutex); msm_gem_free_object(dsi_ctrl->tx_cmd_buf); + mutex_unlock(&dsi_ctrl->drm_dev->struct_mutex); dsi_ctrl->tx_cmd_buf = NULL; } @@ -1145,6 +1508,13 @@ int dsi_ctrl_buffer_init(struct dsi_ctrl *dsi_ctrl) { int rc = 0; u32 iova = 0; + struct msm_gem_address_space *aspace = NULL; + + aspace = dsi_ctrl_get_aspace(dsi_ctrl, MSM_SMMU_DOMAIN_UNSECURE); + if (!aspace) { + pr_err("failed to get address space\n"); + return -ENOMEM; + } dsi_ctrl->tx_cmd_buf = msm_gem_new(dsi_ctrl->drm_dev, SZ_4K, @@ -1159,7 +1529,7 @@ int dsi_ctrl_buffer_init(struct dsi_ctrl *dsi_ctrl) dsi_ctrl->cmd_buffer_size = SZ_4K; - rc = msm_gem_get_iova(dsi_ctrl->tx_cmd_buf, 0, &iova); + rc = msm_gem_get_iova(dsi_ctrl->tx_cmd_buf, aspace, &iova); if (rc) { pr_err("failed to get iova, rc=%d\n", rc); (void)dsi_ctrl_buffer_deinit(dsi_ctrl); @@ -1196,13 +1566,44 @@ static int dsi_enable_io_clamp(struct dsi_ctrl *dsi_ctrl, return 0; } +static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl, + struct device_node *of_node) +{ + u32 index = 0; + int rc = 0; + + if (!dsi_ctrl || !of_node) { + pr_err("invalid dsi_ctrl:%d or of_node:%d\n", + dsi_ctrl != NULL, of_node != NULL); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, "cell-index", &index); + if (rc) { + pr_debug("cell index not set, default to 0\n"); + index = 0; + } + + dsi_ctrl->cell_index = index; + dsi_ctrl->name = of_get_property(of_node, "label", NULL); + if (!dsi_ctrl->name) + dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL; + + dsi_ctrl->phy_isolation_enabled = of_property_read_bool(of_node, + "qcom,dsi-phy-isolation-enabled"); + + dsi_ctrl->null_insertion_enabled = of_property_read_bool(of_node, + "qcom,null-insertion-enabled"); + + return 0; +} + static int dsi_ctrl_dev_probe(struct platform_device *pdev) { struct dsi_ctrl *dsi_ctrl; struct dsi_ctrl_list_item *item; const struct of_device_id *id; enum dsi_ctrl_version version; - u32 index = 0; int rc = 0; id = of_match_node(msm_dsi_of_match, pdev->dev.of_node); @@ -1219,18 +1620,18 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) if (!dsi_ctrl) return -ENOMEM; - rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index); - if (rc) { - pr_debug("cell index not set, default to 0\n"); - index = 0; - } - - dsi_ctrl->cell_index = index; dsi_ctrl->version = version; + dsi_ctrl->irq_info.irq_num = -1; + dsi_ctrl->irq_info.irq_stat_mask = 0x0; - dsi_ctrl->name = of_get_property(pdev->dev.of_node, "label", NULL); - if (!dsi_ctrl->name) - dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL; + spin_lock_init(&dsi_ctrl->irq_info.irq_lock); + + rc = dsi_ctrl_dts_parse(dsi_ctrl, pdev->dev.of_node); + if (rc) { + pr_err("ctrl:%d dts parse failed, rc = %d\n", + dsi_ctrl->cell_index, rc); + goto fail; + } rc = dsi_ctrl_init_regmap(pdev, dsi_ctrl); if (rc) { @@ -1251,7 +1652,8 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) } rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version, - dsi_ctrl->cell_index); + dsi_ctrl->cell_index, dsi_ctrl->phy_isolation_enabled, + dsi_ctrl->null_insertion_enabled); if (rc) { pr_err("Catalog does not support version (%d)\n", dsi_ctrl->version); @@ -1260,7 +1662,7 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) rc = dsi_ctrl_axi_bus_client_init(pdev, dsi_ctrl); if (rc) - pr_err("failed to init axi bus client, rc = %d\n", rc); + pr_debug("failed to init axi bus client, rc = %d\n", rc); item->ctrl = dsi_ctrl; @@ -1269,11 +1671,11 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev) mutex_unlock(&dsi_ctrl_list_lock); mutex_init(&dsi_ctrl->ctrl_lock); + dsi_ctrl->secure_mode = false; dsi_ctrl->pdev = pdev; platform_set_drvdata(pdev, dsi_ctrl); - - pr_debug("Probe successful for %s\n", dsi_ctrl->name); + pr_info("Probe successful for %s\n", dsi_ctrl->name); return 0; @@ -1336,6 +1738,26 @@ static struct platform_driver dsi_ctrl_driver = { }, }; +#if defined(CONFIG_DEBUG_FS) + +void dsi_ctrl_debug_dump(void) +{ + struct list_head *pos, *tmp; + struct dsi_ctrl *ctrl = NULL; + + mutex_lock(&dsi_ctrl_list_lock); + list_for_each_safe(pos, tmp, &dsi_ctrl_list) { + struct dsi_ctrl_list_item *n; + + n = list_entry(pos, struct dsi_ctrl_list_item, list); + ctrl = n->ctrl; + pr_err("dsi ctrl:%d\n", ctrl->cell_index); + ctrl->hw.ops.debug_bus(&ctrl->hw); + } + mutex_unlock(&dsi_ctrl_list_lock); +} + +#endif /** * dsi_ctrl_get() - get a dsi_ctrl handle from an of_node * @of_node: of_node of the DSI controller. @@ -1372,7 +1794,9 @@ struct dsi_ctrl *dsi_ctrl_get(struct device_node *of_node) mutex_lock(&ctrl->ctrl_lock); if (ctrl->refcount == 1) { pr_err("[%s] Device in use\n", ctrl->name); + mutex_unlock(&ctrl->ctrl_lock); ctrl = ERR_PTR(-EBUSY); + return ctrl; } else { ctrl->refcount++; } @@ -1552,7 +1976,7 @@ int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl, host_mode = &dsi_ctrl->host_config.video_timing; memcpy(host_mode, timing, sizeof(*host_mode)); - + dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, true); dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, host_mode); exit: @@ -1561,16 +1985,52 @@ int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl, } /** - * dsi_ctrl_setup() - Setup DSI host hardware while coming out of idle screen. - * @dsi_ctrl: DSI controller handle. + * dsi_ctrl_timing_db_update() - update only controller Timing DB + * @dsi_ctrl: DSI controller handle. + * @enable: Enable/disable Timing DB register * - * Initializes DSI controller hardware with host configuration provided by - * dsi_ctrl_update_host_config(). Initialization can be performed only during - * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been - * performed. + * Update timing db register value during dfps usecases * * Return: error code. */ +int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl, + bool enable) +{ + int rc = 0; + + if (!dsi_ctrl) { + pr_err("Invalid dsi_ctrl\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_ASYNC_TIMING, + DSI_CTRL_ENGINE_ON); + if (rc) { + pr_err("[DSI_%d] Controller state check failed, rc=%d\n", + dsi_ctrl->cell_index, rc); + goto exit; + } + + /* + * Add HW recommended delay for dfps feature. + * When prefetch is enabled, MDSS HW works on 2 vsync + * boundaries i.e. mdp_vsync and panel_vsync. + * In the current implementation we are only waiting + * for mdp_vsync. We need to make sure that interface + * flush is after panel_vsync. So, added the recommended + * delays after dfps update. + */ + usleep_range(2000, 2010); + + dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, enable); + +exit: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) { int rc = 0; @@ -1596,7 +2056,8 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, dsi_ctrl->host_config.video_timing.h_active * 3, - 0x0); + 0x0, + &dsi_ctrl->roi); dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true); } else { dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw, @@ -1608,13 +2069,33 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0); + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } +int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, + bool *changed) +{ + int rc = 0; + + if (!dsi_ctrl || !roi || !changed) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + if (!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) { + *changed = true; + memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi)); + } else + *changed = false; + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + /** * dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal * to DSI PHY hardware. @@ -1636,9 +2117,313 @@ int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable) return 0; } +static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl, + unsigned long int error) +{ + struct dsi_event_cb_info cb_info; + + cb_info = dsi_ctrl->irq_info.irq_err_cb; + + /* disable error interrupts */ + if (dsi_ctrl->hw.ops.error_intr_ctrl) + dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false); + + /* clear error interrupts first */ + if (dsi_ctrl->hw.ops.clear_error_status) + dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, + error); + + /* DTLN PHY error */ + if (error & 0x3000E00) + pr_err("dsi PHY contention error: 0x%lx\n", error); + + /* TX timeout error */ + if (error & 0xE0) { + if (error & 0xA0) { + if (cb_info.event_cb) { + cb_info.event_idx = DSI_LP_Rx_TIMEOUT; + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + 0, 0, 0, 0); + } + } + pr_err("tx timeout error: 0x%lx\n", error); + } + + /* DSI FIFO OVERFLOW error */ + if (error & 0xF0000) { + u32 mask = 0; + + if (dsi_ctrl->hw.ops.get_error_mask) + mask = dsi_ctrl->hw.ops.get_error_mask(&dsi_ctrl->hw); + /* no need to report FIFO overflow if already masked */ + if (cb_info.event_cb && !(mask & 0xf0000)) { + cb_info.event_idx = DSI_FIFO_OVERFLOW; + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + 0, 0, 0, 0); + pr_err("dsi FIFO OVERFLOW error: 0x%lx\n", error); + } + } + + /* DSI FIFO UNDERFLOW error */ + if (error & 0xF00000) { + if (cb_info.event_cb) { + cb_info.event_idx = DSI_FIFO_UNDERFLOW; + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + 0, 0, 0, 0); + } + pr_err("dsi FIFO UNDERFLOW error: 0x%lx\n", error); + } + + /* DSI PLL UNLOCK error */ + if (error & BIT(8)) + pr_err("dsi PLL unlock error: 0x%lx\n", error); + + /* ACK error */ + if (error & 0xF) + pr_err("ack error: 0x%lx\n", error); + + /* enable back DSI interrupts */ + if (dsi_ctrl->hw.ops.error_intr_ctrl) + dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, true); +} + +/** + * dsi_ctrl_isr - interrupt service routine for DSI CTRL component + * @irq: Incoming IRQ number + * @ptr: Pointer to user data structure (struct dsi_ctrl) + * Returns: IRQ_HANDLED if no further action required + */ +static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) +{ + struct dsi_ctrl *dsi_ctrl; + struct dsi_event_cb_info cb_info; + unsigned long flags; + uint32_t status = 0x0, i; + uint64_t errors = 0x0; + + if (!ptr) + return IRQ_NONE; + dsi_ctrl = ptr; + + /* check status interrupts */ + if (dsi_ctrl->hw.ops.get_interrupt_status) + status = dsi_ctrl->hw.ops.get_interrupt_status(&dsi_ctrl->hw); + + /* check error interrupts */ + if (dsi_ctrl->hw.ops.get_error_status) + errors = dsi_ctrl->hw.ops.get_error_status(&dsi_ctrl->hw); + + /* clear interrupts */ + if (dsi_ctrl->hw.ops.clear_interrupt_status) + dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, 0x0); + + SDE_EVT32_IRQ(dsi_ctrl->cell_index, status, errors); + + /* handle DSI error recovery */ + if (status & DSI_ERROR) + dsi_ctrl_handle_error_status(dsi_ctrl, errors); + + if (status & DSI_CMD_MODE_DMA_DONE) { + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + complete_all(&dsi_ctrl->irq_info.cmd_dma_done); + } + + if (status & DSI_CMD_FRAME_DONE) { + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_FRAME_DONE); + complete_all(&dsi_ctrl->irq_info.cmd_frame_done); + } + + if (status & DSI_VIDEO_MODE_FRAME_DONE) { + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_VIDEO_MODE_FRAME_DONE); + complete_all(&dsi_ctrl->irq_info.vid_frame_done); + } + + if (status & DSI_BTA_DONE) { + u32 fifo_overflow_mask = (DSI_DLN0_HS_FIFO_OVERFLOW | + DSI_DLN1_HS_FIFO_OVERFLOW | + DSI_DLN2_HS_FIFO_OVERFLOW | + DSI_DLN3_HS_FIFO_OVERFLOW); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_BTA_DONE); + complete_all(&dsi_ctrl->irq_info.bta_done); + if (dsi_ctrl->hw.ops.clear_error_status) + dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, + fifo_overflow_mask); + } + + for (i = 0; status && i < DSI_STATUS_INTERRUPT_COUNT; ++i) { + if (status & 0x1) { + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); + cb_info = dsi_ctrl->irq_info.irq_stat_cb[i]; + spin_unlock_irqrestore( + &dsi_ctrl->irq_info.irq_lock, flags); + + if (cb_info.event_cb) + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + irq, 0, 0, 0); + } + status >>= 1; + } + + return IRQ_HANDLED; +} + +/** + * _dsi_ctrl_setup_isr - register ISR handler + * @dsi_ctrl: Pointer to associated dsi_ctrl structure + * Returns: Zero on success + */ +static int _dsi_ctrl_setup_isr(struct dsi_ctrl *dsi_ctrl) +{ + int irq_num, rc; + + if (!dsi_ctrl) + return -EINVAL; + if (dsi_ctrl->irq_info.irq_num != -1) + return 0; + + init_completion(&dsi_ctrl->irq_info.cmd_dma_done); + init_completion(&dsi_ctrl->irq_info.vid_frame_done); + init_completion(&dsi_ctrl->irq_info.cmd_frame_done); + init_completion(&dsi_ctrl->irq_info.bta_done); + + irq_num = platform_get_irq(dsi_ctrl->pdev, 0); + if (irq_num < 0) { + pr_err("[DSI_%d] Failed to get IRQ number, %d\n", + dsi_ctrl->cell_index, irq_num); + rc = irq_num; + } else { + rc = devm_request_threaded_irq(&dsi_ctrl->pdev->dev, irq_num, + dsi_ctrl_isr, NULL, 0, "dsi_ctrl", dsi_ctrl); + if (rc) { + pr_err("[DSI_%d] Failed to request IRQ, %d\n", + dsi_ctrl->cell_index, rc); + } else { + dsi_ctrl->irq_info.irq_num = irq_num; + disable_irq_nosync(irq_num); + + pr_info("[DSI_%d] IRQ %d registered\n", + dsi_ctrl->cell_index, irq_num); + } + } + return rc; +} + +/** + * _dsi_ctrl_destroy_isr - unregister ISR handler + * @dsi_ctrl: Pointer to associated dsi_ctrl structure + */ +static void _dsi_ctrl_destroy_isr(struct dsi_ctrl *dsi_ctrl) +{ + if (!dsi_ctrl || !dsi_ctrl->pdev || dsi_ctrl->irq_info.irq_num < 0) + return; + + if (dsi_ctrl->irq_info.irq_num != -1) { + devm_free_irq(&dsi_ctrl->pdev->dev, + dsi_ctrl->irq_info.irq_num, dsi_ctrl); + dsi_ctrl->irq_info.irq_num = -1; + } +} + +void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl, + uint32_t intr_idx, struct dsi_event_cb_info *event_info) +{ + unsigned long flags; + + if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 || + intr_idx >= DSI_STATUS_INTERRUPT_COUNT) + return; + + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); + + if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx] == 0) { + /* enable irq on first request */ + if (dsi_ctrl->irq_info.irq_stat_mask == 0) + enable_irq(dsi_ctrl->irq_info.irq_num); + + /* update hardware mask */ + dsi_ctrl->irq_info.irq_stat_mask |= BIT(intr_idx); + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, + dsi_ctrl->irq_info.irq_stat_mask); + } + ++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]); + + if (event_info) + dsi_ctrl->irq_info.irq_stat_cb[intr_idx] = *event_info; + + spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags); +} + +void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl, + uint32_t intr_idx) +{ + unsigned long flags; + + if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 || + intr_idx >= DSI_STATUS_INTERRUPT_COUNT) + return; + + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); + + if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) + if (--(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) == 0) { + dsi_ctrl->irq_info.irq_stat_mask &= ~BIT(intr_idx); + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, + dsi_ctrl->irq_info.irq_stat_mask); + + /* don't need irq if no lines are enabled */ + if (dsi_ctrl->irq_info.irq_stat_mask == 0) + disable_irq_nosync(dsi_ctrl->irq_info.irq_num); + } + + spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags); +} + +int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl) +{ + if (!dsi_ctrl) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + if (dsi_ctrl->hw.ops.host_setup) + dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config); + + if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) { + if (dsi_ctrl->hw.ops.cmd_engine_setup) + dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config, + &dsi_ctrl->host_config.u.cmd_engine); + + if (dsi_ctrl->hw.ops.setup_cmd_stream) + dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, + &dsi_ctrl->host_config.video_timing, + dsi_ctrl->host_config.video_timing.h_active * 3, + 0x0, NULL); + } else { + pr_err("invalid panel mode for resolution switch\n"); + return -EINVAL; + } + + return 0; +} + /** * dsi_ctrl_host_init() - Initialize DSI host hardware. * @dsi_ctrl: DSI controller handle. + * @is_splash_enabled: boolean signifying splash status. * * Initializes DSI controller hardware with host configuration provided by * dsi_ctrl_update_host_config(). Initialization can be performed only during @@ -1647,7 +2432,7 @@ int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable) * * Return: error code. */ -int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl) +int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled) { int rc = 0; @@ -1664,44 +2449,65 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl) goto error; } - dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw, + /* For Splash usecases we omit hw operations as bootloader + * already takes care of them + */ + if (!is_splash_enabled) { + dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw, &dsi_ctrl->host_config.lane_map); - dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw, + dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw, &dsi_ctrl->host_config.common_config); - if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) { - dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw, + if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) { + dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw, &dsi_ctrl->host_config.common_config, &dsi_ctrl->host_config.u.cmd_engine); - dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, + dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, dsi_ctrl->host_config.video_timing.h_active * 3, - 0x0); - } else { - dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw, + 0x0, + NULL); + } else { + dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw, &dsi_ctrl->host_config.common_config, &dsi_ctrl->host_config.u.video_engine); - dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, + dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing); + } } - - dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0); + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); - /* Perform a soft reset before enabling dsi controller */ - dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw); - pr_debug("[DSI_%d]Host initialization complete\n", - dsi_ctrl->cell_index); + pr_debug("[DSI_%d]Host initialization complete, continuous splash status:%d\n", + dsi_ctrl->cell_index, is_splash_enabled); dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1); error: mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } +/** + * dsi_ctrl_isr_configure() - API to register/deregister dsi isr + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control register/deregister isr + */ +void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + if (enable) + _dsi_ctrl_setup_isr(dsi_ctrl); + else + _dsi_ctrl_destroy_isr(dsi_ctrl); + + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl) { if (!dsi_ctrl) @@ -1715,6 +2521,48 @@ int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl) return 0; } +int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask) +{ + int rc = 0; + + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl->hw.ops.ctrl_reset(&dsi_ctrl->hw, mask); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl->hw.ops.get_hw_version(&dsi_ctrl->hw); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on) +{ + int rc = 0; + + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, on); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + /** * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware. * @dsi_ctrl: DSI controller handle. @@ -1782,7 +2630,7 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, goto error; } - if (!(flags & DSI_MODE_FLAG_SEAMLESS)) { + if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR))) { rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle); if (rc) { pr_err("[%s] failed to update link frequencies, rc=%d\n", @@ -1793,6 +2641,13 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, pr_debug("[DSI_%d]Host config updated\n", ctrl->cell_index); memcpy(&ctrl->host_config, config, sizeof(ctrl->host_config)); + ctrl->mode_bounds.x = ctrl->host_config.video_timing.h_active * + ctrl->horiz_index; + ctrl->mode_bounds.y = 0; + ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active; + ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active; + memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds)); + ctrl->roi.x = 0; error: mutex_unlock(&ctrl->ctrl_lock); return rc; @@ -1860,8 +2715,8 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, if (flags & DSI_CTRL_CMD_READ) { rc = dsi_message_rx(dsi_ctrl, msg, flags); - if (rc) - pr_err("read message failed, rc=%d\n", rc); + if (rc <= 0) + pr_err("read message failed read length, rc=%d\n", rc); } else { rc = dsi_message_tx(dsi_ctrl, msg, flags); if (rc) @@ -1884,7 +2739,7 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, */ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) { - int rc = 0; + int rc = 0, ret = 0; u32 status = 0; u32 mask = (DSI_CMD_MODE_DMA_DONE); @@ -1893,31 +2748,143 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) return -EINVAL; } - mutex_lock(&dsi_ctrl->ctrl_lock); + /* Dont trigger the command if this is not the last ocmmand */ + if (!(flags & DSI_CTRL_CMD_LAST_COMMAND)) + return rc; - reinit_completion(&dsi_ctrl->int_info.cmd_dma_done); + mutex_lock(&dsi_ctrl->ctrl_lock); - dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw); + if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) + dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw); if ((flags & DSI_CTRL_CMD_BROADCAST) && - (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { - u32 retry = 10; - - while ((status == 0) && (retry > 0)) { - udelay(1000); + (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { + dsi_ctrl_wait_for_video_done(dsi_ctrl); + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE, NULL); + if (dsi_ctrl->hw.ops.mask_error_intr) + dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, + BIT(DSI_FIFO_OVERFLOW), true); + reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); + + /* trigger command */ + dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw); + + ret = wait_for_completion_timeout( + &dsi_ctrl->irq_info.cmd_dma_done, + msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); + + if (ret == 0) { status = dsi_ctrl->hw.ops.get_interrupt_status( &dsi_ctrl->hw); - status &= mask; - retry--; - dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, + if (status & mask) { + status |= (DSI_CMD_MODE_DMA_DONE | + DSI_BTA_DONE); + dsi_ctrl->hw.ops.clear_interrupt_status( + &dsi_ctrl->hw, status); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + complete_all(&dsi_ctrl->irq_info.cmd_dma_done); + pr_warn("dma_tx done but irq not triggered\n"); + } else { + rc = -ETIMEDOUT; + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + pr_err("[DSI_%d]Command transfer failed\n", + dsi_ctrl->cell_index); + } } - pr_debug("INT STATUS = %x, retry = %d\n", status, retry); - if (retry == 0) - pr_err("[DSI_%d]Command transfer failed\n", - dsi_ctrl->cell_index); + if (dsi_ctrl->hw.ops.mask_error_intr) + dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, + BIT(DSI_FIFO_OVERFLOW), false); + + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw); + dsi_ctrl->cmd_len = 0; + } + } + + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * _dsi_ctrl_cache_misr - Cache frame MISR value + * @dsi_ctrl: Pointer to associated dsi_ctrl structure + */ +static void _dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl) +{ + u32 misr; + + if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr) + return; + + misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw, + dsi_ctrl->host_config.panel_mode); + + if (misr) + dsi_ctrl->misr_cache = misr; + + pr_debug("DSI_%d misr_cache = %x\n", dsi_ctrl->cell_index, + dsi_ctrl->misr_cache); + +} +/** + * dsi_ctrl_get_host_engine_init_state() - Return host init state + * @dsi_ctrl: DSI controller handle. + * @state: Controller initialization state + * + * Return: error code. + */ +int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, + bool *state) +{ + if (!dsi_ctrl || !state) { + pr_err("Invalid Params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + *state = dsi_ctrl->current_state.host_initialized; + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return 0; +} + +/** + * dsi_ctrl_update_host_engine_state_for_cont_splash() - + * set engine state for dsi controller during continuous splash + * @dsi_ctrl: DSI controller handle. + * @state: Engine state. + * + * Set host engine state for DSI controller during continuous splash. + * + * Return: error code. + */ +int dsi_ctrl_update_host_engine_state_for_cont_splash(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state) +{ + int rc = 0; + + if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state); + if (rc) { + pr_err("[DSI_%d] Controller state check failed, rc=%d\n", + dsi_ctrl->cell_index, rc); + goto error; } + pr_debug("[DSI_%d] Set host engine state = %d\n", dsi_ctrl->cell_index, + state); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state); +error: mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } @@ -1960,6 +2927,9 @@ int dsi_ctrl_set_power_state(struct dsi_ctrl *dsi_ctrl, goto error; } } else if (state == DSI_CTRL_POWER_VREG_OFF) { + if (dsi_ctrl->misr_enable) + _dsi_ctrl_cache_misr(dsi_ctrl); + rc = dsi_ctrl_enable_supplies(dsi_ctrl, false); if (rc) { pr_err("[%d]failed to disable vreg supplies, rc=%d\n", @@ -2089,8 +3059,6 @@ int dsi_ctrl_set_cmd_engine_state(struct dsi_ctrl *dsi_ctrl, return -EINVAL; } - mutex_lock(&dsi_ctrl->ctrl_lock); - rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_CMD_ENGINE, state); if (rc) { pr_err("[DSI_%d] Controller state check failed, rc=%d\n", @@ -2107,7 +3075,6 @@ int dsi_ctrl_set_cmd_engine_state(struct dsi_ctrl *dsi_ctrl, state); dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_ENGINE, state); error: - mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } @@ -2157,14 +3124,14 @@ int dsi_ctrl_set_vid_engine_state(struct dsi_ctrl *dsi_ctrl, } /** - * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. - * @dsi_ctrl: DSI controller handle. - * @enable: enable/disable ULPS. - * - * ULPS can be enabled/disabled after DSI host engine is turned on. - * - * Return: error code. - */ + * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable ULPS. + * + * ULPS can be enabled/disabled after DSI host engine is turned on. + * + * Return: error code. + */ int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable) { int rc = 0; @@ -2273,6 +3240,81 @@ int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl, return rc; } +/** + * dsi_ctrl_setup_misr() - Setup frame MISR + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + * + * Return: error code. + */ +int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl, + bool enable, + u32 frame_count) +{ + if (!dsi_ctrl) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + if (!dsi_ctrl->hw.ops.setup_misr) + return 0; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->misr_enable = enable; + dsi_ctrl->hw.ops.setup_misr(&dsi_ctrl->hw, + dsi_ctrl->host_config.panel_mode, + enable, frame_count); + mutex_unlock(&dsi_ctrl->ctrl_lock); + return 0; +} + +/** + * dsi_ctrl_collect_misr() - Read frame MISR + * @dsi_ctrl: DSI controller handle. + * + * Return: MISR value. + */ +u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl) +{ + u32 misr; + + if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr) + return 0; + + misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw, + dsi_ctrl->host_config.panel_mode); + if (!misr) + misr = dsi_ctrl->misr_cache; + + pr_debug("DSI_%d cached misr = %x, final = %x\n", + dsi_ctrl->cell_index, dsi_ctrl->misr_cache, misr); + + return misr; +} + +/** + * dsi_ctrl_irq_update() - Put a irq vote to process DSI error + * interrupts at any time. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to enable/disable irq + */ +void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + if (enable) + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_ERROR, NULL); + else + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_ERROR); + + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + /** * dsi_ctrl_drv_register() - register platform driver for dsi controller */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index f8adbea71f0c573f093c5dce027144f9468a4aa2..ca5889638c51f83c98a195d08f505221d00b7ad1 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, 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 @@ -33,12 +33,28 @@ * @DSI_CTRL_CMD_DEFER_TRIGGER: Defer the command trigger to later. * @DSI_CTRL_CMD_FIFO_STORE: Use FIFO for command transfer in place of * reading data from memory. + * @DSI_CTRL_CMD_FETCH_MEMORY: Fetch command from memory through AXI bus + * and transfer it. + * @DSI_CTRL_CMD_LAST_COMMAND: Trigger the DMA cmd transfer if this is last + * command in the batch. + * @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Trasfer cmd packets in non embedded mode. */ #define DSI_CTRL_CMD_READ 0x1 #define DSI_CTRL_CMD_BROADCAST 0x2 #define DSI_CTRL_CMD_BROADCAST_MASTER 0x4 #define DSI_CTRL_CMD_DEFER_TRIGGER 0x8 #define DSI_CTRL_CMD_FIFO_STORE 0x10 +#define DSI_CTRL_CMD_FETCH_MEMORY 0x20 +#define DSI_CTRL_CMD_LAST_COMMAND 0x40 +#define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80 + +/* DSI embedded mode fifo size + * If the command is greater than 256 bytes it is sent in non-embedded mode. + */ +#define DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES 256 + +/* max size supported for dsi cmd transfer using TPG */ +#define DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE 64 /** * enum dsi_power_state - defines power states for dsi controller. @@ -135,39 +151,35 @@ struct dsi_ctrl_state_info { /** * struct dsi_ctrl_interrupts - define interrupt information - * @irq: IRQ id for the DSI controller. - * @intr_lock: Spinlock to protect access to interrupt registers. - * @interrupt_status: Status interrupts which need to be serviced. - * @error_status: Error interurpts which need to be serviced. - * @interrupts_enabled: Status interrupts which are enabled. - * @errors_enabled: Error interrupts which are enabled. + * @irq_lock: Spinlock for ISR handler. + * @irq_num: Linux interrupt number associated with device. + * @irq_stat_mask: Hardware mask of currently enabled interrupts. + * @irq_stat_refcount: Number of times each interrupt has been requested. + * @irq_stat_cb: Status IRQ callback definitions. + * @irq_err_cb: IRQ callback definition to handle DSI ERRORs. * @cmd_dma_done: Completion signal for DSI_CMD_MODE_DMA_DONE interrupt * @vid_frame_done: Completion signal for DSI_VIDEO_MODE_FRAME_DONE int. * @cmd_frame_done: Completion signal for DSI_CMD_FRAME_DONE interrupt. - * @interrupt_done_work: Work item for servicing status interrupts. - * @error_status_work: Work item for servicing error interrupts. */ struct dsi_ctrl_interrupts { - u32 irq; - spinlock_t intr_lock; /* protects access to interrupt registers */ - u32 interrupt_status; - u64 error_status; - - u32 interrupts_enabled; - u64 errors_enabled; + spinlock_t irq_lock; + int irq_num; + uint32_t irq_stat_mask; + int irq_stat_refcount[DSI_STATUS_INTERRUPT_COUNT]; + struct dsi_event_cb_info irq_stat_cb[DSI_STATUS_INTERRUPT_COUNT]; + struct dsi_event_cb_info irq_err_cb; struct completion cmd_dma_done; struct completion vid_frame_done; struct completion cmd_frame_done; - - struct work_struct interrupt_done_work; - struct work_struct error_status_work; + struct completion bta_done; }; /** * struct dsi_ctrl - DSI controller object * @pdev: Pointer to platform device. * @cell_index: Instance cell id. + * @horiz_index: Index in physical horizontal CTRL layout, 0 = leftmost * @name: Name of the controller instance. * @refcount: ref counter. * @ctrl_lock: Mutex for hardware and object access. @@ -176,19 +188,34 @@ struct dsi_ctrl_interrupts { * @hw: DSI controller hardware object. * @current_state: Current driver and hardware state. * @clk_cb: Callback for DSI clock control. - * @int_info: Interrupt information. + * @irq_info: Interrupt information. + * @recovery_cb: Recovery call back to SDE. * @clk_info: Clock information. * @clk_freq: DSi Link clock frequency information. * @pwr_info: Power information. * @axi_bus_info: AXI bus information. * @host_config: Current host configuration. + * @mode_bounds: Boundaries of the default mode ROI. + * Origin is at top left of all CTRLs. + * @roi: Partial update region of interest. + * Origin is top left of this CTRL. * @tx_cmd_buf: Tx command buffer. + * @cmd_buffer_iova: cmd buffer mapped address. * @cmd_buffer_size: Size of command buffer. + * @vaddr: CPU virtual address of cmd buffer. + * @secure_mode: Indicates if secure-session is in progress * @debugfs_root: Root for debugfs entries. + * @misr_enable: Frame MISR enable/disable + * @misr_cache: Cached Frame MISR value + * @phy_isolation_enabled: A boolean property allows to isolate the phy from + * dsi controller and run only dsi controller. + * @null_insertion_enabled: A boolean property to allow dsi controller to + * insert null packet. */ struct dsi_ctrl { struct platform_device *pdev; u32 cell_index; + u32 horiz_index; const char *name; u32 refcount; struct mutex ctrl_lock; @@ -201,7 +228,9 @@ struct dsi_ctrl { struct dsi_ctrl_state_info current_state; struct clk_ctrl_cb clk_cb; - struct dsi_ctrl_interrupts int_info; + struct dsi_ctrl_interrupts irq_info; + struct dsi_event_cb_info recovery_cb; + /* Clock and power states */ struct dsi_ctrl_clk_info clk_info; struct link_clk_freq clk_freq; @@ -209,13 +238,26 @@ struct dsi_ctrl { struct dsi_ctrl_bus_scale_info axi_bus_info; struct dsi_host_config host_config; + struct dsi_rect mode_bounds; + struct dsi_rect roi; + /* Command tx and rx */ struct drm_gem_object *tx_cmd_buf; u32 cmd_buffer_size; + u32 cmd_buffer_iova; + u32 cmd_len; + void *vaddr; + bool secure_mode; /* Debug Information */ struct dentry *debugfs_root; + /* MISR */ + bool misr_enable; + u32 misr_cache; + + bool phy_isolation_enabled; + bool null_insertion_enabled; }; /** @@ -291,6 +333,18 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *dsi_ctrl, struct dsi_host_config *config, int flags, void *clk_handle); +/** + * dsi_ctrl_timing_db_update() - update only controller Timing DB + * @dsi_ctrl: DSI controller handle. + * @enable: Enable/disable Timing DB register + * + * Update timing db register value during dfps usecases + * + * Return: error code. + */ +int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl, + bool enable); + /** * dsi_ctrl_async_timing_update() - update only controller timing * @dsi_ctrl: DSI controller handle. @@ -343,9 +397,21 @@ int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable); */ int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl); +/** + * dsi_ctrl_host_timing_update - reinitialize host with new timing values + * @dsi_ctrl: DSI controller handle. + * + * Reinitialize DSI controller hardware with new display timing values + * when resolution is switched dynamically. + * + * Return: error code + */ +int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl); + /** * dsi_ctrl_host_init() - Initialize DSI host hardware. * @dsi_ctrl: DSI controller handle. + * @is_splash_enabled: boolean signifying splash status. * * Initializes DSI controller hardware with host configuration provided by * dsi_ctrl_update_host_config(). Initialization can be performed only during @@ -354,7 +420,7 @@ int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl); * * Return: error code. */ -int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl); +int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled); /** * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware. @@ -368,14 +434,14 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl); int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl); /** - * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. - * @dsi_ctrl: DSI controller handle. - * @enable: enable/disable ULPS. - * - * ULPS can be enabled/disabled after DSI host engine is turned on. - * - * Return: error code. - */ + * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable ULPS. + * + * ULPS can be enabled/disabled after DSI host engine is turned on. + * + * Return: error code. + */ int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable); /** @@ -387,10 +453,24 @@ int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable); * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been * performed. * + * Also used to program the video mode timing values. + * * Return: error code. */ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); +/** + * dsi_ctrl_set_roi() - Set DSI controller's region of interest + * @dsi_ctrl: DSI controller handle. + * @roi: Region of interest rectangle, must be less than mode bounds + * @changed: Output parameter, set to true of the controller's ROI was + * dirtied by setting the new ROI, and DCS cmd update needed + * + * Return: error code. + */ +int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, + bool *changed); + /** * dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller * @dsi_ctrl: DSI controller handle. @@ -401,7 +481,6 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); * * Return: error code. */ - int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on); /** @@ -430,6 +509,17 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, */ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags); +/** + * dsi_ctrl_update_host_engine_state_for_cont_splash() - update engine + * states for cont splash usecase + * @dsi_ctrl: DSI controller handle. + * @state: DSI engine state + * + * Return: error code. + */ +int dsi_ctrl_update_host_engine_state_for_cont_splash(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state); + /** * dsi_ctrl_set_power_state() - set power state for dsi controller * @dsi_ctrl: DSI controller handle. @@ -530,6 +620,43 @@ int dsi_ctrl_set_clamp_state(struct dsi_ctrl *dsi_Ctrl, int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl, struct dsi_clk_link_set *source_clks); +/** + * dsi_ctrl_enable_status_interrupt() - enable status interrupts + * @dsi_ctrl: DSI controller handle. + * @intr_idx: Index interrupt to disable. + * @event_info: Pointer to event callback definition + */ +void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl, + uint32_t intr_idx, struct dsi_event_cb_info *event_info); + +/** + * dsi_ctrl_disable_status_interrupt() - disable status interrupts + * @dsi_ctrl: DSI controller handle. + * @intr_idx: Index interrupt to disable. + */ +void dsi_ctrl_disable_status_interrupt( + struct dsi_ctrl *dsi_ctrl, uint32_t intr_idx); + +/** + * dsi_ctrl_setup_misr() - Setup frame MISR + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + * + * Return: error code. + */ +int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl, + bool enable, + u32 frame_count); + +/** + * dsi_ctrl_collect_misr() - Read frame MISR + * @dsi_ctrl: DSI controller handle. + * + * Return: MISR value. + */ +u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl); + /** * dsi_ctrl_drv_register() - register platform driver for dsi controller */ @@ -540,4 +667,61 @@ void dsi_ctrl_drv_register(void); */ void dsi_ctrl_drv_unregister(void); +/** + * dsi_ctrl_reset() - Reset DSI PHY CLK/DATA lane + * @dsi_ctrl: DSI controller handle. + * @mask: Mask to indicate if CLK and/or DATA lane needs reset. + */ +int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask); + +/** + * dsi_ctrl_get_hw_version() - read dsi controller hw revision + * @dsi_ctrl: DSI controller handle. + */ +int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_vid_engine_en() - Control DSI video engine HW state + * @dsi_ctrl: DSI controller handle. + * @on: variable to control video engine ON/OFF. + */ +int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on); + +/** + * @dsi_ctrl: DSI controller handle. + * cmd_len: Length of command. + * flags: Config mode flags. + */ +void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len, + u32 *flags); + +/** + * @dsi_ctrl: DSI controller handle. + * cmd_len: Length of command. + * flags: Config mode flags. + */ +int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len, + u32 *flags); + +/** + * dsi_ctrl_isr_configure() - API to register/deregister dsi isr + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control register/deregister isr + */ +void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_irq_update() - Put a irq vote to process DSI error + * interrupts at any time. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control enable/disable irq line + */ +void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_get_host_engine_init_state() - Return host init state + */ +int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, + bool *state); + #endif /* _DSI_CTRL_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h index 859d707e0927978f3de5f2475f1aabc735bc43aa..567f28990f74cb756a2608336ffff7f5a5f9d12c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h @@ -9,7 +9,6 @@ * 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 _DSI_CTRL_HW_H_ @@ -83,6 +82,38 @@ enum dsi_test_pattern { DSI_TEST_PATTERN_MAX }; +/** + * enum dsi_status_int_index - index of interrupts generated by DSI controller + * @DSI_SINT_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out. + * @DSI_SINT_CMD_STREAM0_FRAME_DONE: A frame of cmd mode stream0 is sent out. + * @DSI_SINT_CMD_STREAM1_FRAME_DONE: A frame of cmd mode stream1 is sent out. + * @DSI_SINT_CMD_STREAM2_FRAME_DONE: A frame of cmd mode stream2 is sent out. + * @DSI_SINT_VIDEO_MODE_FRAME_DONE: A frame of video mode stream is sent out. + * @DSI_SINT_BTA_DONE: A BTA is completed. + * @DSI_SINT_CMD_FRAME_DONE: A frame of selected cmd mode stream is + * sent out by MDP. + * @DSI_SINT_DYN_REFRESH_DONE: The dynamic refresh operation completed. + * @DSI_SINT_DESKEW_DONE: The deskew calibration operation done. + * @DSI_SINT_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has + * completed. + * @DSI_SINT_ERROR: DSI error has happened. + */ +enum dsi_status_int_index { + DSI_SINT_CMD_MODE_DMA_DONE = 0, + DSI_SINT_CMD_STREAM0_FRAME_DONE = 1, + DSI_SINT_CMD_STREAM1_FRAME_DONE = 2, + DSI_SINT_CMD_STREAM2_FRAME_DONE = 3, + DSI_SINT_VIDEO_MODE_FRAME_DONE = 4, + DSI_SINT_BTA_DONE = 5, + DSI_SINT_CMD_FRAME_DONE = 6, + DSI_SINT_DYN_REFRESH_DONE = 7, + DSI_SINT_DESKEW_DONE = 8, + DSI_SINT_DYN_BLANK_DMA_DONE = 9, + DSI_SINT_ERROR = 10, + + DSI_STATUS_INTERRUPT_COUNT +}; + /** * enum dsi_status_int_type - status interrupts generated by DSI controller * @DSI_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out. @@ -97,18 +128,95 @@ enum dsi_test_pattern { * @DSI_DESKEW_DONE: The deskew calibration operation has completed * @DSI_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has * completed. + * @DSI_ERROR: DSI error has happened. */ enum dsi_status_int_type { - DSI_CMD_MODE_DMA_DONE = BIT(0), - DSI_CMD_STREAM0_FRAME_DONE = BIT(1), - DSI_CMD_STREAM1_FRAME_DONE = BIT(2), - DSI_CMD_STREAM2_FRAME_DONE = BIT(3), - DSI_VIDEO_MODE_FRAME_DONE = BIT(4), - DSI_BTA_DONE = BIT(5), - DSI_CMD_FRAME_DONE = BIT(6), - DSI_DYN_REFRESH_DONE = BIT(7), - DSI_DESKEW_DONE = BIT(8), - DSI_DYN_BLANK_DMA_DONE = BIT(9) + DSI_CMD_MODE_DMA_DONE = BIT(DSI_SINT_CMD_MODE_DMA_DONE), + DSI_CMD_STREAM0_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM0_FRAME_DONE), + DSI_CMD_STREAM1_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM1_FRAME_DONE), + DSI_CMD_STREAM2_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM2_FRAME_DONE), + DSI_VIDEO_MODE_FRAME_DONE = BIT(DSI_SINT_VIDEO_MODE_FRAME_DONE), + DSI_BTA_DONE = BIT(DSI_SINT_BTA_DONE), + DSI_CMD_FRAME_DONE = BIT(DSI_SINT_CMD_FRAME_DONE), + DSI_DYN_REFRESH_DONE = BIT(DSI_SINT_DYN_REFRESH_DONE), + DSI_DESKEW_DONE = BIT(DSI_SINT_DESKEW_DONE), + DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE), + DSI_ERROR = BIT(DSI_SINT_ERROR) +}; + +/** + * enum dsi_error_int_index - index of error interrupts from DSI controller + * @DSI_EINT_RDBK_SINGLE_ECC_ERR: Single bit ECC error in read packet. + * @DSI_EINT_RDBK_MULTI_ECC_ERR: Multi bit ECC error in read packet. + * @DSI_EINT_RDBK_CRC_ERR: CRC error in read packet. + * @DSI_EINT_RDBK_INCOMPLETE_PKT: Incomplete read packet. + * @DSI_EINT_PERIPH_ERROR_PKT: Error packet returned from peripheral, + * @DSI_EINT_LP_RX_TIMEOUT: Low power reverse transmission timeout. + * @DSI_EINT_HS_TX_TIMEOUT: High speed fwd transmission timeout. + * @DSI_EINT_BTA_TIMEOUT: BTA timeout. + * @DSI_EINT_PLL_UNLOCK: PLL has unlocked. + * @DSI_EINT_DLN0_ESC_ENTRY_ERR: Incorrect LP Rx escape entry. + * @DSI_EINT_DLN0_ESC_SYNC_ERR: LP Rx data is not byte aligned. + * @DSI_EINT_DLN0_LP_CONTROL_ERR: Incorrect LP Rx state sequence. + * @DSI_EINT_PENDING_HS_TX_TIMEOUT: Pending High-speed transfer timeout. + * @DSI_EINT_INTERLEAVE_OP_CONTENTION: Interleave operation contention. + * @DSI_EINT_CMD_DMA_FIFO_UNDERFLOW: Command mode DMA FIFO underflow. + * @DSI_EINT_CMD_MDP_FIFO_UNDERFLOW: Command MDP FIFO underflow (failed to + * receive one complete line from MDP). + * @DSI_EINT_DLN0_HS_FIFO_OVERFLOW: High speed FIFO data lane 0 overflows. + * @DSI_EINT_DLN1_HS_FIFO_OVERFLOW: High speed FIFO data lane 1 overflows. + * @DSI_EINT_DLN2_HS_FIFO_OVERFLOW: High speed FIFO data lane 2 overflows. + * @DSI_EINT_DLN3_HS_FIFO_OVERFLOW: High speed FIFO data lane 3 overflows. + * @DSI_EINT_DLN0_HS_FIFO_UNDERFLOW: High speed FIFO data lane 0 underflows. + * @DSI_EINT_DLN1_HS_FIFO_UNDERFLOW: High speed FIFO data lane 1 underflows. + * @DSI_EINT_DLN2_HS_FIFO_UNDERFLOW: High speed FIFO data lane 2 underflows. + * @DSI_EINT_DLN3_HS_FIFO_UNDERFLOW: High speed FIFO data lane 3 undeflows. + * @DSI_EINT_DLN0_LP0_CONTENTION: PHY level contention while lane 0 low. + * @DSI_EINT_DLN1_LP0_CONTENTION: PHY level contention while lane 1 low. + * @DSI_EINT_DLN2_LP0_CONTENTION: PHY level contention while lane 2 low. + * @DSI_EINT_DLN3_LP0_CONTENTION: PHY level contention while lane 3 low. + * @DSI_EINT_DLN0_LP1_CONTENTION: PHY level contention while lane 0 high. + * @DSI_EINT_DLN1_LP1_CONTENTION: PHY level contention while lane 1 high. + * @DSI_EINT_DLN2_LP1_CONTENTION: PHY level contention while lane 2 high. + * @DSI_EINT_DLN3_LP1_CONTENTION: PHY level contention while lane 3 high. + * @DSI_EINT_PANEL_SPECIFIC_ERR: DSI Protocol violation error. + */ +enum dsi_error_int_index { + DSI_EINT_RDBK_SINGLE_ECC_ERR = 0, + DSI_EINT_RDBK_MULTI_ECC_ERR = 1, + DSI_EINT_RDBK_CRC_ERR = 2, + DSI_EINT_RDBK_INCOMPLETE_PKT = 3, + DSI_EINT_PERIPH_ERROR_PKT = 4, + DSI_EINT_LP_RX_TIMEOUT = 5, + DSI_EINT_HS_TX_TIMEOUT = 6, + DSI_EINT_BTA_TIMEOUT = 7, + DSI_EINT_PLL_UNLOCK = 8, + DSI_EINT_DLN0_ESC_ENTRY_ERR = 9, + DSI_EINT_DLN0_ESC_SYNC_ERR = 10, + DSI_EINT_DLN0_LP_CONTROL_ERR = 11, + DSI_EINT_PENDING_HS_TX_TIMEOUT = 12, + DSI_EINT_INTERLEAVE_OP_CONTENTION = 13, + DSI_EINT_CMD_DMA_FIFO_UNDERFLOW = 14, + DSI_EINT_CMD_MDP_FIFO_UNDERFLOW = 15, + DSI_EINT_DLN0_HS_FIFO_OVERFLOW = 16, + DSI_EINT_DLN1_HS_FIFO_OVERFLOW = 17, + DSI_EINT_DLN2_HS_FIFO_OVERFLOW = 18, + DSI_EINT_DLN3_HS_FIFO_OVERFLOW = 19, + DSI_EINT_DLN0_HS_FIFO_UNDERFLOW = 20, + DSI_EINT_DLN1_HS_FIFO_UNDERFLOW = 21, + DSI_EINT_DLN2_HS_FIFO_UNDERFLOW = 22, + DSI_EINT_DLN3_HS_FIFO_UNDERFLOW = 23, + DSI_EINT_DLN0_LP0_CONTENTION = 24, + DSI_EINT_DLN1_LP0_CONTENTION = 25, + DSI_EINT_DLN2_LP0_CONTENTION = 26, + DSI_EINT_DLN3_LP0_CONTENTION = 27, + DSI_EINT_DLN0_LP1_CONTENTION = 28, + DSI_EINT_DLN1_LP1_CONTENTION = 29, + DSI_EINT_DLN2_LP1_CONTENTION = 30, + DSI_EINT_DLN3_LP1_CONTENTION = 31, + DSI_EINT_PANEL_SPECIFIC_ERR = 32, + + DSI_ERROR_INTERRUPT_COUNT }; /** @@ -146,46 +254,49 @@ enum dsi_status_int_type { * @DSI_DLN1_LP1_CONTENTION: PHY level contention while lane 1 is high. * @DSI_DLN2_LP1_CONTENTION: PHY level contention while lane 2 is high. * @DSI_DLN3_LP1_CONTENTION: PHY level contention while lane 3 is high. + * @DSI_PANEL_SPECIFIC_ERR: DSI Protocol violation. */ enum dsi_error_int_type { - DSI_RDBK_SINGLE_ECC_ERR = BIT(0), - DSI_RDBK_MULTI_ECC_ERR = BIT(1), - DSI_RDBK_CRC_ERR = BIT(2), - DSI_RDBK_INCOMPLETE_PKT = BIT(3), - DSI_PERIPH_ERROR_PKT = BIT(4), - DSI_LP_RX_TIMEOUT = BIT(5), - DSI_HS_TX_TIMEOUT = BIT(6), - DSI_BTA_TIMEOUT = BIT(7), - DSI_PLL_UNLOCK = BIT(8), - DSI_DLN0_ESC_ENTRY_ERR = BIT(9), - DSI_DLN0_ESC_SYNC_ERR = BIT(10), - DSI_DLN0_LP_CONTROL_ERR = BIT(11), - DSI_PENDING_HS_TX_TIMEOUT = BIT(12), - DSI_INTERLEAVE_OP_CONTENTION = BIT(13), - DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(14), - DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(15), - DSI_DLN0_HS_FIFO_OVERFLOW = BIT(16), - DSI_DLN1_HS_FIFO_OVERFLOW = BIT(17), - DSI_DLN2_HS_FIFO_OVERFLOW = BIT(18), - DSI_DLN3_HS_FIFO_OVERFLOW = BIT(19), - DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(20), - DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(21), - DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(22), - DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(23), - DSI_DLN0_LP0_CONTENTION = BIT(24), - DSI_DLN1_LP0_CONTENTION = BIT(25), - DSI_DLN2_LP0_CONTENTION = BIT(26), - DSI_DLN3_LP0_CONTENTION = BIT(27), - DSI_DLN0_LP1_CONTENTION = BIT(28), - DSI_DLN1_LP1_CONTENTION = BIT(29), - DSI_DLN2_LP1_CONTENTION = BIT(30), - DSI_DLN3_LP1_CONTENTION = BIT(31), + DSI_RDBK_SINGLE_ECC_ERR = BIT(DSI_EINT_RDBK_SINGLE_ECC_ERR), + DSI_RDBK_MULTI_ECC_ERR = BIT(DSI_EINT_RDBK_MULTI_ECC_ERR), + DSI_RDBK_CRC_ERR = BIT(DSI_EINT_RDBK_CRC_ERR), + DSI_RDBK_INCOMPLETE_PKT = BIT(DSI_EINT_RDBK_INCOMPLETE_PKT), + DSI_PERIPH_ERROR_PKT = BIT(DSI_EINT_PERIPH_ERROR_PKT), + DSI_LP_RX_TIMEOUT = BIT(DSI_EINT_LP_RX_TIMEOUT), + DSI_HS_TX_TIMEOUT = BIT(DSI_EINT_HS_TX_TIMEOUT), + DSI_BTA_TIMEOUT = BIT(DSI_EINT_BTA_TIMEOUT), + DSI_PLL_UNLOCK = BIT(DSI_EINT_PLL_UNLOCK), + DSI_DLN0_ESC_ENTRY_ERR = BIT(DSI_EINT_DLN0_ESC_ENTRY_ERR), + DSI_DLN0_ESC_SYNC_ERR = BIT(DSI_EINT_DLN0_ESC_SYNC_ERR), + DSI_DLN0_LP_CONTROL_ERR = BIT(DSI_EINT_DLN0_LP_CONTROL_ERR), + DSI_PENDING_HS_TX_TIMEOUT = BIT(DSI_EINT_PENDING_HS_TX_TIMEOUT), + DSI_INTERLEAVE_OP_CONTENTION = BIT(DSI_EINT_INTERLEAVE_OP_CONTENTION), + DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_DMA_FIFO_UNDERFLOW), + DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_MDP_FIFO_UNDERFLOW), + DSI_DLN0_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_OVERFLOW), + DSI_DLN1_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_OVERFLOW), + DSI_DLN2_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_OVERFLOW), + DSI_DLN3_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_OVERFLOW), + DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_UNDERFLOW), + DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_UNDERFLOW), + DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_UNDERFLOW), + DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_UNDERFLOW), + DSI_DLN0_LP0_CONTENTION = BIT(DSI_EINT_DLN0_LP0_CONTENTION), + DSI_DLN1_LP0_CONTENTION = BIT(DSI_EINT_DLN1_LP0_CONTENTION), + DSI_DLN2_LP0_CONTENTION = BIT(DSI_EINT_DLN2_LP0_CONTENTION), + DSI_DLN3_LP0_CONTENTION = BIT(DSI_EINT_DLN3_LP0_CONTENTION), + DSI_DLN0_LP1_CONTENTION = BIT(DSI_EINT_DLN0_LP1_CONTENTION), + DSI_DLN1_LP1_CONTENTION = BIT(DSI_EINT_DLN1_LP1_CONTENTION), + DSI_DLN2_LP1_CONTENTION = BIT(DSI_EINT_DLN2_LP1_CONTENTION), + DSI_DLN3_LP1_CONTENTION = BIT(DSI_EINT_DLN3_LP1_CONTENTION), + DSI_PANEL_SPECIFIC_ERR = BIT(DSI_EINT_PANEL_SPECIFIC_ERR), }; /** * struct dsi_ctrl_cmd_dma_info - command buffer information * @offset: IOMMU VA for command buffer address. * @length: Length of the command buffer. + * @datatype: Datatype of cmd. * @en_broadcast: Enable broadcast mode if set to true. * @is_master: Is master in broadcast mode. * @use_lpm: Use low power mode for command transmission. @@ -193,6 +304,7 @@ enum dsi_error_int_type { struct dsi_ctrl_cmd_dma_info { u32 offset; u32 length; + u8 datatype; bool en_broadcast; bool is_master; bool use_lpm; @@ -319,7 +431,8 @@ struct dsi_ctrl_hw_ops { void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode, u32 h_stride, - u32 vc_id); + u32 vc_id, + struct dsi_rect *roi); /** * ctrl_en() - enable DSI controller engine @@ -341,6 +454,12 @@ struct dsi_ctrl_hw_ops { */ void (*phy_sw_reset)(struct dsi_ctrl_hw *ctrl); + /** + * debug_bus() - get dsi debug bus status. + * @ctrl: Pointer to the controller host hardware. + */ + void (*debug_bus)(struct dsi_ctrl_hw *ctrl); + /** * soft_reset() - perform a soft reset on DSI controller * @ctrl: Pointer to the controller host hardware. @@ -379,6 +498,25 @@ struct dsi_ctrl_hw_ops { struct dsi_ctrl_cmd_dma_info *cmd, u32 flags); + /** + * kickoff_command_non_embedded_mode() - cmd in non embedded mode + * @ctrl: Pointer to the controller host hardware. + * @cmd: Command information. + * @flags: Modifiers for command transmission. + * + * If command length is greater than DMA FIFO size of 256 bytes we use + * this non- embedded mode. + * The controller hardware is programmed with address and size of the + * command buffer. The transmission is kicked off if + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is + * set, caller should make a separate call to trigger_command_dma() to + * transmit the command. + */ + + void (*kickoff_command_non_embedded_mode)(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags); + /** * kickoff_fifo_command() - transmits a command using FIFO in dsi * hardware. @@ -411,11 +549,23 @@ struct dsi_ctrl_hw_ops { * get_cmd_read_data() - get data read from the peripheral * @ctrl: Pointer to the controller host hardware. * @rd_buf: Buffer where data will be read into. - * @total_read_len: Number of bytes to read. + * @read_offset: Offset from where to read. + * @rx_byte: Number of bytes to be read. + * @pkt_size: Size of response expected. + * @hw_read_cnt: Actual number of bytes read by HW. */ u32 (*get_cmd_read_data)(struct dsi_ctrl_hw *ctrl, u8 *rd_buf, - u32 total_read_len); + u32 read_offset, + u32 rx_byte, + u32 pkt_size, + u32 *hw_read_cnt); + + /** + * get_cont_splash_status() - get continuous splash status + * @ctrl: Pointer to the controller host hardware. + */ + bool (*get_cont_splash_status)(struct dsi_ctrl_hw *ctrl); /** * wait_for_lane_idle() - wait for DSI lanes to go to idle state @@ -572,6 +722,82 @@ struct dsi_ctrl_hw_ops { ssize_t (*reg_dump_to_buffer)(struct dsi_ctrl_hw *ctrl, char *buf, u32 size); + + /** + * setup_misr() - Setup frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + * @enable: Enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + */ + void (*setup_misr)(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode, + bool enable, u32 frame_count); + + /** + * collect_misr() - Read frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + */ + u32 (*collect_misr)(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode); + + /** + * set_timing_db() - enable/disable Timing DB register + * @ctrl: Pointer to controller host hardware. + * @enable: Enable/Disable flag. + * + * Enable or Disabe the Timing DB register. + */ + void (*set_timing_db)(struct dsi_ctrl_hw *ctrl, + bool enable); + /** + * clear_rdbk_register() - Clear and reset read back register + * @ctrl: Pointer to the controller host hardware. + */ + void (*clear_rdbk_register)(struct dsi_ctrl_hw *ctrl); + + /** schedule_dma_cmd() - Schdeule DMA command transfer on a + * particular blanking line. + * @ctrl: Pointer to the controller host hardware. + * @line_no: Blanking line number on whihch DMA command + * needs to be sent. + */ + void (*schedule_dma_cmd)(struct dsi_ctrl_hw *ctrl, int line_no); + + /** + * ctrl_reset() - Reset DSI lanes to recover from DSI errors + * @ctrl: Pointer to the controller host hardware. + * @mask: Indicates the error type. + */ + int (*ctrl_reset)(struct dsi_ctrl_hw *ctrl, int mask); + + /** + * mask_error_int() - Mask/Unmask particular DSI error interrupts + * @ctrl: Pointer to the controller host hardware. + * @idx: Indicates the errors to be masked. + * @en: Bool for mask or unmask of the error + */ + void (*mask_error_intr)(struct dsi_ctrl_hw *ctrl, u32 idx, bool en); + + /** + * error_intr_ctrl() - Mask/Unmask master DSI error interrupt + * @ctrl: Pointer to the controller host hardware. + * @en: Bool for mask or unmask of DSI error + */ + void (*error_intr_ctrl)(struct dsi_ctrl_hw *ctrl, bool en); + + /** + * get_error_mask() - get DSI error interrupt mask status + * @ctrl: Pointer to the controller host hardware. + */ + u32 (*get_error_mask)(struct dsi_ctrl_hw *ctrl); + + /** + * get_hw_version() - get DSI controller hw version + * @ctrl: Pointer to the controller host hardware. + */ + u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl); }; /* @@ -588,6 +814,10 @@ struct dsi_ctrl_hw_ops { * controller. * @supported_interrupts: Number of supported interrupts. * @supported_errors: Number of supported errors. + * @phy_isolation_enabled: A boolean property allows to isolate the phy from + * dsi controller and run only dsi controller. + * @null_insertion_enabled: A boolean property to allow dsi controller to + * insert null packet. */ struct dsi_ctrl_hw { void __iomem *base; @@ -605,6 +835,9 @@ struct dsi_ctrl_hw { /* capabilities */ u32 supported_interrupts; u64 supported_errors; + + bool phy_isolation_enabled; + bool null_insertion_enabled; }; #endif /* _DSI_CTRL_HW_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c index c22849a4fdabfc5fff9523ef3d35e636ffc525ff..6421dc212bccbded60fa43f5ef162554e0d2cddf 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_0.c @@ -156,6 +156,10 @@ ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, DUMP_REG_VALUE(DSI_CMD_MODE_BTA_SW_TRIGGER)); len += snprintf((buf + len), (size - len), DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_CMD_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_VIDEO_CTRL)); len += snprintf((buf + len), (size - len), DUMP_REG_VALUE(DSI_LANE_STATUS)); len += snprintf((buf + len), (size - len), @@ -192,6 +196,12 @@ ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, DUMP_REG_VALUE(DSI_PHY_SW_RESET)); len += snprintf((buf + len), (size - len), DUMP_REG_VALUE(DSI_AXI2AHB_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_CMD_MDP0_32BIT)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_CMD_MDP1_32BIT)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_VIDEO_32BIT)); len += snprintf((buf + len), (size - len), DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2)); len += snprintf((buf + len), (size - len), diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c index 1b1e81165c7e67c984c67512d21d0397ab6e232b..bb0b6030d751fc1cb5d72cbb48d8e9cb513d2fdd 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c @@ -17,10 +17,14 @@ #include "dsi_ctrl_hw.h" #include "dsi_ctrl_reg.h" #include "dsi_hw.h" +#include "dsi_catalog.h" /* Equivalent to register DISP_CC_MISC_CMD */ #define DISP_CC_CLAMP_REG_OFF 0x00 +/* register to configure DMA scheduling */ +#define DSI_DMA_SCHEDULE_CTRL 0x100 + /** * dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps * @ctrl: Pointer to the controller host hardware. @@ -40,3 +44,84 @@ void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl, reg |= BIT(ctrl->index); DSI_DISP_CC_W32(ctrl, DISP_CC_CLAMP_REG_OFF, reg); } + +/** + * dsi_ctrl_hw_22_schedule_dma_cmd() - to schedule DMA command transfer + * @ctrl: Pointer to the controller host hardware. + * @line_no: Line number at which command needs to be sent. + */ +void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_no) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_DMA_SCHEDULE_CTRL); + reg |= BIT(28); + reg |= (line_no & 0xffff); + + DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, reg); +} + +/* + * dsi_ctrl_hw_22_get_cont_splash_status() - to verify whether continuous + * splash is enabled or not + * @ctrl: Pointer to the controller host hardware. + * + * Return: Return Continuous splash status + */ +bool dsi_ctrl_hw_22_get_cont_splash_status(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + + /** + * DSI scratch register 1 is used to notify whether continuous + * splash is enabled or not by bootloader + */ + reg = DSI_R32(ctrl, DSI_SCRATCH_REGISTER_1); + return reg == 0x1 ? true : false; +} + +/* + * dsi_ctrl_hw_kickoff_non_embedded_mode()-Kickoff cmd in non-embedded mode + * @ctrl: - Pointer to the controller host hardware. + * @dsi_ctrl_cmd_dma_info: - command buffer information. + * @flags: - DSI CTRL Flags. + */ +void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL); + + reg &= ~BIT(31);/* disable broadcast */ + reg &= ~BIT(30); + + if (cmd->use_lpm) + reg |= BIT(26); + else + reg &= ~BIT(26); + + /* Select non EMBEDDED_MODE, pick the packet header from register */ + reg &= ~BIT(28); + reg |= BIT(24);/* long packet */ + reg |= BIT(29);/* wc_sel = 1 */ + reg |= (((cmd->datatype) & 0x03f) << 16);/* data type */ + DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); + + /* Enable WRITE_WATERMARK_DISABLE and READ_WATERMARK_DISABLE bits */ + reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL); + reg |= BIT(20); + reg |= BIT(16); + reg |= 0x33;/* Set READ and WRITE watermark levels to maximum */ + DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg); + + DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset); + DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, ((cmd->length) & 0xFFFFFF)); + + /* wait for writes to complete before kick off */ + wmb(); + + if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) + DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); +} diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c index 122a63d02bafafddec30b4653c9fbbe8c1da3c54..594b3f55747372b67f1f670dac2d3b11ad97aa9b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c @@ -16,12 +16,18 @@ #include #include +#include "dsi_catalog.h" #include "dsi_ctrl_hw.h" #include "dsi_ctrl_reg.h" #include "dsi_hw.h" +#include "dsi_panel.h" +#include "dsi_catalog.h" +#include "sde_dbg.h" #define MMSS_MISC_CLAMP_REG_OFF 0x0014 #define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21)) +#define DSI_CTRL_CMD_MISR_ENABLE BIT(28) +#define DSI_CTRL_VIDEO_MISR_ENABLE BIT(16) /* Unsupported formats default to RGB888 */ static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { @@ -75,7 +81,7 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl, DSI_W32(ctrl, DSI_CLK_CTRL, 0x23F); /* Setup DSI control register */ - reg_value = 0; + reg_value = DSI_R32(ctrl, DSI_CTRL); reg_value |= (cfg->en_crc_check ? BIT(24) : 0); reg_value |= (cfg->en_ecc_check ? BIT(20) : 0); reg_value |= BIT(8); /* Clock lane */ @@ -86,6 +92,8 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl, DSI_W32(ctrl, DSI_CTRL, reg_value); + if (ctrl->phy_isolation_enabled) + DSI_W32(ctrl, DSI_DEBUG_CTRL, BIT(28)); pr_debug("[DSI_%d]Host configuration complete\n", ctrl->index); } @@ -147,6 +155,91 @@ void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl) pr_debug("[DSI_%d] ctrl soft reset done\n", ctrl->index); } +/** + * setup_misr() - Setup frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + * @enable: Enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + */ +void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode, + bool enable, + u32 frame_count) +{ + u32 addr; + u32 config = 0; + + if (panel_mode == DSI_OP_CMD_MODE) { + addr = DSI_MISR_CMD_CTRL; + if (enable) + config = DSI_CTRL_CMD_MISR_ENABLE; + } else { + addr = DSI_MISR_VIDEO_CTRL; + if (enable) + config = DSI_CTRL_VIDEO_MISR_ENABLE; + if (frame_count > 255) + frame_count = 255; + config |= frame_count << 8; + } + + pr_debug("[DSI_%d] MISR ctrl: 0x%x\n", ctrl->index, + config); + DSI_W32(ctrl, addr, config); + wmb(); /* make sure MISR is configured */ +} + +/** + * collect_misr() - Read frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + */ +u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode) +{ + u32 addr; + u32 enabled; + u32 misr = 0; + + if (panel_mode == DSI_OP_CMD_MODE) { + addr = DSI_MISR_CMD_MDP0_32BIT; + enabled = DSI_R32(ctrl, DSI_MISR_CMD_CTRL) & + DSI_CTRL_CMD_MISR_ENABLE; + } else { + addr = DSI_MISR_VIDEO_32BIT; + enabled = DSI_R32(ctrl, DSI_MISR_VIDEO_CTRL) & + DSI_CTRL_VIDEO_MISR_ENABLE; + } + + if (enabled) + misr = DSI_R32(ctrl, addr); + + pr_debug("[DSI_%d] MISR enabled %x value: 0x%x\n", ctrl->index, + enabled, misr); + return misr; +} + +/** +* set_timing_db() - enable/disable Timing DB register +* @ctrl: Pointer to controller host hardware. +* @enable: Enable/Disable flag. +* +* Enable or Disabe the Timing DB register. +*/ +void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl, + bool enable) +{ + if (enable) + DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1); + else + DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x0); + + wmb(); /* make sure timing db registers are set */ + pr_debug("[DSI_%d] ctrl timing DB set:%d\n", ctrl->index, + enable); + SDE_EVT32(ctrl->index, enable); +} + /** * set_video_timing() - set up the timing for video frame * @ctrl: Pointer to controller host hardware. @@ -220,6 +313,7 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, DSI_W32(ctrl, DSI_MISR_VIDEO_CTRL, 0x10100); DSI_W32(ctrl, DSI_DSI_TIMING_FLUSH, 0x1); pr_debug("[DSI_%d] ctrl video parameters updated\n", ctrl->index); + SDE_EVT32(v_total, h_total); } /** @@ -234,21 +328,36 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode, u32 h_stride, - u32 vc_id) + u32 vc_id, + struct dsi_rect *roi) { - u32 reg = 0; u32 width_final, stride_final; + u32 height_final; + u32 stream_total = 0, stream_ctrl = 0; + u32 reg_ctrl = 0, reg_ctrl2 = 0, data = 0; + + if (roi && (!roi->w || !roi->h)) + return; if (mode->dsc_enabled && mode->dsc) { + u32 reg = 0; u32 offset = 0; - u32 reg_ctrl, reg_ctrl2; + int pic_width, this_frame_slices, intf_ip_w; + struct msm_display_dsc_info dsc; + + memcpy(&dsc, mode->dsc, sizeof(dsc)); + pic_width = roi ? roi->w : mode->h_active; + this_frame_slices = pic_width / dsc.slice_width; + intf_ip_w = this_frame_slices * dsc.slice_width; + dsi_dsc_pclk_param_calc(&dsc, intf_ip_w); if (vc_id != 0) offset = 16; reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL); reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2); - width_final = mode->dsc->pclk_per_line; - stride_final = width_final * (h_stride / mode->h_active); + width_final = dsc.pclk_per_line; + stride_final = dsc.bytes_per_pkt; + height_final = roi ? roi->h : mode->v_active; reg = 0x39 << 8; /* @@ -258,34 +367,57 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, * 2 == 4 pkt * 3 pkt is not support */ - if (mode->dsc->pkt_per_line == 4) - reg |= (mode->dsc->pkt_per_line - 2) << 6; + if (dsc.pkt_per_line == 4) + reg |= (dsc.pkt_per_line - 2) << 6; else - reg |= (mode->dsc->pkt_per_line - 1) << 6; - reg |= mode->dsc->eol_byte_num << 4; + reg |= (dsc.pkt_per_line - 1) << 6; + reg |= dsc.eol_byte_num << 4; reg |= 1; reg_ctrl &= ~(0xFFFF << offset); reg_ctrl |= (reg << offset); reg_ctrl2 &= ~(0xFFFF << offset); - reg_ctrl2 |= (mode->dsc->bytes_in_slice << offset); - DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); - DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); + reg_ctrl2 |= (dsc.bytes_in_slice << offset); + + pr_debug("ctrl %d reg_ctrl 0x%x reg_ctrl2 0x%x\n", ctrl->index, + reg_ctrl, reg_ctrl2); + } else if (roi) { + width_final = roi->w; + stride_final = roi->w * 3; + height_final = roi->h; } else { width_final = mode->h_active; stride_final = h_stride; + height_final = mode->v_active; } - reg = (stride_final + 1) << 16; - reg |= (vc_id & 0x3) << 8; - reg |= 0x39; /* packet data type */ + /* HS Timer value */ + DSI_W32(ctrl, DSI_HS_TIMER_CTRL, 0x3FD08); + + stream_ctrl = (stride_final + 1) << 16; + stream_ctrl |= (vc_id & 0x3) << 8; + stream_ctrl |= 0x39; /* packet data type */ + + DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); + DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, reg); - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, reg); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, stream_ctrl); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, stream_ctrl); - reg = (mode->v_active << 16) | width_final; - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, reg); - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, reg); + stream_total = (height_final << 16) | width_final; + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, stream_total); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, stream_total); + + if (ctrl->null_insertion_enabled) { + /* enable null packet insertion */ + data = (vc_id << 1); + data |= 0 << 16; + data |= 0x1; + DSI_W32(ctrl, DSI_COMMAND_MODE_NULL_INSERTION_CTRL, data); + } + + pr_debug("ctrl %d stream_ctrl 0x%x stream_total 0x%x\n", ctrl->index, + stream_ctrl, stream_total); } /** @@ -327,6 +459,18 @@ void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl, pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index); } +void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + + DSI_W32(ctrl, DSI_DEBUG_BUS_CTL, 0x181); + + /* make sure that debug test point is enabled */ + wmb(); + reg = DSI_R32(ctrl, DSI_DEBUG_BUS_STATUS); + + pr_err("[DSI_%d] debug bus status:0x%x\n", ctrl->index, reg); +} /** * cmd_engine_setup() - setup dsi host controller for command mode * @ctrl: Pointer to the controller host hardware. @@ -468,9 +612,16 @@ void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl, else reg &= ~BIT(26); - reg |= BIT(28); + reg |= BIT(28);/* Select embedded mode */ + reg &= ~BIT(24);/* packet type */ + reg &= ~BIT(29);/* WC_SEL to 0 */ DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); + reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL); + reg |= BIT(20);/* Disable write watermark*/ + reg |= BIT(16);/* Disable read watermark */ + + DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg); DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset); DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->length & 0xFFFFFF)); @@ -576,6 +727,22 @@ void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl) pr_debug("[DSI_%d] CMD DMA triggered\n", ctrl->index); } +/** + * clear_rdbk_reg() - clear previously read panel data. + * @ctrl: Pointer to the controller host hardware. + * + * This function is called before sending DSI Rx command to + * panel in order to clear if any stale data remaining from + * previous read operation. + */ +void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl) +{ + DSI_W32(ctrl, DSI_RDBK_DATA_CTRL, 0x1); + wmb(); /* ensure read back register is reset */ + DSI_W32(ctrl, DSI_RDBK_DATA_CTRL, 0x0); + wmb(); /* ensure read back register is cleared */ +} + /** * get_cmd_read_data() - get data read from the peripheral * @ctrl: Pointer to the controller host hardware. @@ -587,16 +754,16 @@ void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl) u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, u8 *rd_buf, u32 read_offset, - u32 total_read_len) + u32 rx_byte, + u32 pkt_size, + u32 *hw_read_cnt) { u32 *lp, *temp, data; - int i, j = 0, cnt; + int i, j = 0, cnt, off; u32 read_cnt; - u32 rx_byte = 0; u32 repeated_bytes = 0; u8 reg[16] = {0}; - u32 pkt_size = 0; - int buf_offset = read_offset; + bool ack_err = false; lp = (u32 *)rd_buf; temp = (u32 *)reg; @@ -605,28 +772,49 @@ u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, if (cnt > 4) cnt = 4; - if (rx_byte == 4) - read_cnt = 4; - else - read_cnt = pkt_size + 6; + read_cnt = (DSI_R32(ctrl, DSI_RDBK_DATA_CTRL) >> 16); + ack_err = (rx_byte == 4) ? (read_cnt == 8) : + ((read_cnt - 4) == (pkt_size + 6)); + + if (ack_err) + read_cnt -= 4; + if (!read_cnt) { + pr_err("Panel detected error, no data read\n"); + return 0; + } if (read_cnt > 16) { - int bytes_shifted; + int bytes_shifted, data_lost = 0, rem_header = 0; - bytes_shifted = read_cnt - 16; - repeated_bytes = buf_offset - bytes_shifted; + bytes_shifted = read_cnt - rx_byte; + if (bytes_shifted >= 4) + data_lost = bytes_shifted - 4; /* remove DCS header */ + else + rem_header = 4 - bytes_shifted; /* remaining header */ + + repeated_bytes = (read_offset - 4) - data_lost + rem_header; } - for (i = cnt - 1; i >= 0; i--) { - data = DSI_R32(ctrl, DSI_RDBK_DATA0 + i*4); - *temp++ = ntohl(data); + off = DSI_RDBK_DATA0; + off += ((cnt - 1) * 4); + + for (i = 0; i < cnt; i++) { + data = DSI_R32(ctrl, off); + if (!repeated_bytes) + *lp++ = ntohl(data); + else + *temp++ = ntohl(data); + off -= 4; } - for (i = repeated_bytes; i < 16; i++) - rd_buf[j++] = reg[i]; + if (repeated_bytes) { + for (i = repeated_bytes; i < 16; i++) + rd_buf[j++] = reg[i]; + } - pr_debug("[DSI_%d] Read %d bytes\n", ctrl->index, j); - return j; + *hw_read_cnt = read_cnt; + pr_debug("[DSI_%d] Read %d bytes\n", ctrl->index, rx_byte); + return rx_byte; } /** @@ -664,6 +852,8 @@ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl) ints |= DSI_DYN_REFRESH_DONE; if (reg & BIT(30)) ints |= DSI_DESKEW_DONE; + if (reg & BIT(24)) + ints |= DSI_ERROR; pr_debug("[DSI_%d] Interrupt status = 0x%x, INT_CTRL=0x%x\n", ctrl->index, ints, reg); @@ -679,6 +869,8 @@ void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints) { u32 reg = 0; + reg = DSI_R32(ctrl, DSI_INT_CTRL); + if (ints & DSI_CMD_MODE_DMA_DONE) reg |= BIT(0); if (ints & DSI_CMD_FRAME_DONE) @@ -698,6 +890,12 @@ void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints) if (ints & DSI_DESKEW_DONE) reg |= BIT(30); + /* + * Do not clear error status. + * It will be cleared as part of + * error handler function. + */ + reg &= ~BIT(24); DSI_W32(ctrl, DSI_INT_CTRL, reg); pr_debug("[DSI_%d] Clear interrupts, ints = 0x%x, INT_CTRL=0x%x\n", @@ -764,7 +962,7 @@ u64 dsi_ctrl_hw_cmn_get_error_status(struct dsi_ctrl_hw *ctrl) u32 timeout_errors; u32 clk_error; u32 dsi_status; - u64 errors = 0; + u64 errors = 0, shift = 0x1; dln0_phy_err = DSI_R32(ctrl, DSI_DLN0_PHY_ERR); if (dln0_phy_err & BIT(0)) @@ -811,6 +1009,8 @@ u64 dsi_ctrl_hw_cmn_get_error_status(struct dsi_ctrl_hw *ctrl) errors |= DSI_RDBK_INCOMPLETE_PKT; if (ack_error & BIT(24)) errors |= DSI_PERIPH_ERROR_PKT; + if (ack_error & BIT(15)) + errors |= (shift << DSI_EINT_PANEL_SPECIFIC_ERR); timeout_errors = DSI_R32(ctrl, DSI_TIMEOUT_STATUS); if (timeout_errors & BIT(0)) @@ -848,7 +1048,6 @@ void dsi_ctrl_hw_cmn_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors) u32 timeout_error = 0; u32 clk_error = 0; u32 dsi_status = 0; - u32 int_ctrl = 0; if (errors & DSI_RDBK_SINGLE_ECC_ERR) ack_error |= BIT(16); @@ -860,6 +1059,8 @@ void dsi_ctrl_hw_cmn_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors) ack_error |= BIT(23); if (errors & DSI_PERIPH_ERROR_PKT) ack_error |= BIT(24); + if (errors & DSI_PANEL_SPECIFIC_ERR) + ack_error |= BIT(15); if (errors & DSI_LP_RX_TIMEOUT) timeout_error |= BIT(4); @@ -908,14 +1109,14 @@ void dsi_ctrl_hw_cmn_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors) DSI_W32(ctrl, DSI_DLN0_PHY_ERR, dln0_phy_err); DSI_W32(ctrl, DSI_FIFO_STATUS, fifo_status); + /* Writing of an extra 0 is needed to clear ack error bits */ DSI_W32(ctrl, DSI_ACK_ERR_STATUS, ack_error); + wmb(); /* make sure register is committed */ + DSI_W32(ctrl, DSI_ACK_ERR_STATUS, 0x0); DSI_W32(ctrl, DSI_TIMEOUT_STATUS, timeout_error); DSI_W32(ctrl, DSI_CLK_STATUS, clk_error); DSI_W32(ctrl, DSI_STATUS, dsi_status); - int_ctrl = DSI_R32(ctrl, DSI_INT_CTRL); - int_ctrl |= BIT(24); - DSI_W32(ctrl, DSI_INT_CTRL, int_ctrl); pr_debug("[DSI_%d] clear errors = 0x%llx, phy=0x%x, fifo=0x%x", ctrl->index, errors, dln0_phy_err, fifo_status); pr_debug("[DSI_%d] ack=0x%x, timeout=0x%x, clk=0x%x, dsi=0x%x\n", @@ -1176,3 +1377,102 @@ void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl, DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); } +int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl, + int mask) +{ + int rc = 0; + u32 data; + + pr_debug("DSI CTRL and PHY reset. ctrl-num = %d %d\n", + ctrl->index, mask); + + data = DSI_R32(ctrl, 0x0004); + /* Disable DSI video mode */ + DSI_W32(ctrl, 0x004, (data & ~BIT(1))); + wmb(); /* ensure register committed */ + /* Disable DSI controller */ + DSI_W32(ctrl, 0x004, (data & ~(BIT(0) | BIT(1)))); + wmb(); /* ensure register committed */ + /* "Force On" all dynamic clocks */ + DSI_W32(ctrl, 0x11c, 0x100a00); + + /* DSI_SW_RESET */ + DSI_W32(ctrl, 0x118, 0x1); + wmb(); /* ensure register is committed */ + DSI_W32(ctrl, 0x118, 0x0); + wmb(); /* ensure register is committed */ + + /* Remove "Force On" all dynamic clocks */ + DSI_W32(ctrl, 0x11c, 0x00); + /* Enable DSI controller */ + DSI_W32(ctrl, 0x004, (data & ~BIT(1))); + wmb(); /* ensure register committed */ + + return rc; +} + +void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, bool en) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, 0x10c); + + if (idx & BIT(DSI_FIFO_OVERFLOW)) { + if (en) + reg |= (0xf << 16); + else + reg &= ~(0xf << 16); + } + + if (idx & BIT(DSI_FIFO_UNDERFLOW)) { + if (en) + reg |= (0xf << 26); + else + reg &= ~(0xf << 26); + } + + if (idx & BIT(DSI_LP_Rx_TIMEOUT)) { + if (en) + reg |= (0x7 << 23); + else + reg &= ~(0x7 << 23); + } + + DSI_W32(ctrl, 0x10c, reg); + wmb(); /* ensure error is masked */ +} + +void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en) +{ + u32 reg = 0; + u32 dsi_total_mask = 0x2222AA02; + + reg = DSI_R32(ctrl, 0x110); + reg &= dsi_total_mask; + + if (en) + reg |= (BIT(24) | BIT(25)); + else + reg &= ~BIT(25); + + DSI_W32(ctrl, 0x110, reg); + wmb(); /* ensure error is masked */ +} + +u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, 0x10c); + + return reg; +} + +u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, 0x0); + + return reg; +} diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h index 34e9e729f28a088b64ce74b7823a51e46dab2c48..39ac0214283e2ff0c864033c141529fc2853c0ac 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h @@ -82,6 +82,8 @@ #define DSI_SOFT_RESET (0x0118) #define DSI_CLK_CTRL (0x011C) #define DSI_CLK_STATUS (0x0120) +#define DSI_DEBUG_BUS_CTL (0x0124) +#define DSI_DEBUG_BUS_STATUS (0x0128) #define DSI_PHY_SW_RESET (0x012C) #define DSI_AXI2AHB_CTRL (0x0130) #define DSI_MISR_CMD_MDP0_32BIT (0x0134) @@ -184,6 +186,7 @@ #define DSI_DESKEW_CTRL (0x02BC) #define DSI_DESKEW_DELAY_CTRL (0x02C0) #define DSI_DESKEW_SW_TRIGGER (0x02C4) +#define DSI_DEBUG_CTRL (0x02C8) #define DSI_SECURE_DISPLAY_STATUS (0x02CC) #define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0) #define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h index ee39ec775356667395383210e3365a42b56b9159..d45f8493d29d446da3ffa9a47079e4de51ad881a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h @@ -9,13 +9,13 @@ * 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 _DSI_DEFS_H_ #define _DSI_DEFS_H_ #include +#include #include "msm_drv.h" #define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \ @@ -36,6 +36,7 @@ value;\ }) +#define DSI_DEBUG_NAME_LEN 32 /** * enum dsi_pixel_format - DSI pixel formats * @DSI_PIXEL_FORMAT_RGB565: @@ -75,11 +76,16 @@ enum dsi_op_mode { * @DSI_MODE_FLAG_SEAMLESS: Seamless transition requested by user * @DSI_MODE_FLAG_DFPS: Seamless transition is DynamicFPS * @DSI_MODE_FLAG_VBLANK_PRE_MODESET: Transition needs VBLANK before Modeset + * @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch + * @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS. + * New timing values are sent from DAL. */ enum dsi_mode_flags { DSI_MODE_FLAG_SEAMLESS = BIT(0), DSI_MODE_FLAG_DFPS = BIT(1), - DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2) + DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2), + DSI_MODE_FLAG_DMS = BIT(3), + DSI_MODE_FLAG_VRR = BIT(4), }; /** @@ -213,6 +219,68 @@ enum dsi_dfps_type { DSI_DFPS_MAX }; +/** + * enum dsi_cmd_set_type - DSI command set type + * @DSI_CMD_SET_PRE_ON: Panel pre on + * @DSI_CMD_SET_ON: Panel on + * @DSI_CMD_SET_POST_ON: Panel post on + * @DSI_CMD_SET_PRE_OFF: Panel pre off + * @DSI_CMD_SET_OFF: Panel off + * @DSI_CMD_SET_POST_OFF: Panel post off + * @DSI_CMD_SET_PRE_RES_SWITCH: Pre resolution switch + * @DSI_CMD_SET_RES_SWITCH: Resolution switch + * @DSI_CMD_SET_POST_RES_SWITCH: Post resolution switch + * @DSI_CMD_SET_CMD_TO_VID_SWITCH: Cmd to video mode switch + * @DSI_CMD_SET_POST_CMD_TO_VID_SWITCH: Post cmd to vid switch + * @DSI_CMD_SET_VID_TO_CMD_SWITCH: Video to cmd mode switch + * @DSI_CMD_SET_POST_VID_TO_CMD_SWITCH: Post vid to cmd switch + * @DSI_CMD_SET_PANEL_STATUS: Panel status + * @DSI_CMD_SET_LP1: Low power mode 1 + * @DSI_CMD_SET_LP2: Low power mode 2 + * @DSI_CMD_SET_NOLP: Low power mode disable + * @DSI_CMD_SET_PPS: DSC PPS command + * @DSI_CMD_SET_ROI: Panel ROI update + * @DSI_CMD_SET_TIMING_SWITCH: Timing switch + * @DSI_CMD_SET_POST_TIMING_SWITCH: Post timing switch + * @DSI_CMD_SET_MAX + */ +enum dsi_cmd_set_type { + DSI_CMD_SET_PRE_ON = 0, + DSI_CMD_SET_ON, + DSI_CMD_SET_POST_ON, + DSI_CMD_SET_PRE_OFF, + DSI_CMD_SET_OFF, + DSI_CMD_SET_POST_OFF, + DSI_CMD_SET_PRE_RES_SWITCH, + DSI_CMD_SET_RES_SWITCH, + DSI_CMD_SET_POST_RES_SWITCH, + DSI_CMD_SET_CMD_TO_VID_SWITCH, + DSI_CMD_SET_POST_CMD_TO_VID_SWITCH, + DSI_CMD_SET_VID_TO_CMD_SWITCH, + DSI_CMD_SET_POST_VID_TO_CMD_SWITCH, + DSI_CMD_SET_PANEL_STATUS, + DSI_CMD_SET_LP1, + DSI_CMD_SET_LP2, + DSI_CMD_SET_NOLP, + DSI_CMD_SET_PPS, + DSI_CMD_SET_ROI, + DSI_CMD_SET_TIMING_SWITCH, + DSI_CMD_SET_POST_TIMING_SWITCH, + DSI_CMD_SET_MAX +}; + +/** + * enum dsi_cmd_set_state - command set state + * @DSI_CMD_SET_STATE_LP: dsi low power mode + * @DSI_CMD_SET_STATE_HS: dsi high speed mode + * @DSI_CMD_SET_STATE_MAX + */ +enum dsi_cmd_set_state { + DSI_CMD_SET_STATE_LP = 0, + DSI_CMD_SET_STATE_HS, + DSI_CMD_SET_STATE_MAX +}; + /** * enum dsi_phy_type - DSI phy types * @DSI_PHY_TYPE_DPHY: @@ -245,6 +313,34 @@ enum dsi_video_traffic_mode { DSI_VIDEO_TRAFFIC_BURST_MODE, }; +/** + * struct dsi_cmd_desc - description of a dsi command + * @msg: dsi mipi msg packet + * @last_command: indicates whether the cmd is the last one to send + * @post_wait_ms: post wait duration + */ +struct dsi_cmd_desc { + struct mipi_dsi_msg msg; + bool last_command; + u32 post_wait_ms; +}; + +/** + * struct dsi_panel_cmd_set - command set of the panel + * @type: type of the command + * @state: state of the command + * @count: number of cmds + * @ctrl_idx: index of the dsi control + * @cmds: arry of cmds + */ +struct dsi_panel_cmd_set { + enum dsi_cmd_set_type type; + enum dsi_cmd_set_state state; + u32 count; + u32 ctrl_idx; + struct dsi_cmd_desc *cmds; +}; + /** * struct dsi_mode_info - video mode information dsi frame * @h_active: Active width of one frame in pixels. @@ -259,8 +355,10 @@ enum dsi_video_traffic_mode { * @v_front_porch: Vertical front porch in lines. * @v_sync_polarity: Polarity of VSYNC (false is active low). * @refresh_rate: Refresh rate in Hz. + * @clk_rate_hz: DSI bit clock rate per lane in Hz. * @dsc_enabled: DSC compression enabled. * @dsc: DSC compression configuration. + * @roi_caps: Panel ROI capabilities. */ struct dsi_mode_info { u32 h_active; @@ -277,9 +375,10 @@ struct dsi_mode_info { bool v_sync_polarity; u32 refresh_rate; - + u64 clk_rate_hz; bool dsc_enabled; struct msm_display_dsc_info *dsc; + struct msm_roi_caps roi_caps; }; /** @@ -396,18 +495,106 @@ struct dsi_host_config { struct dsi_lane_map lane_map; }; +/** + * struct dsi_display_mode_priv_info - private mode info that will be attached + * with each drm mode + * @cmd_sets: Command sets of the mode + * @phy_timing_val: Phy timing values + * @phy_timing_len: Phy timing array length + * @panel_jitter: Panel jitter for RSC backoff + * @panel_prefill_lines: Panel prefill lines for RSC + * @clk_rate_hz: DSI bit clock per lane in hz. + * @topology: Topology selected for the panel + * @dsc: DSC compression info + * @dsc_enabled: DSC compression enabled + * @roi_caps: Panel ROI capabilities + */ +struct dsi_display_mode_priv_info { + struct dsi_panel_cmd_set cmd_sets[DSI_CMD_SET_MAX]; + + u32 *phy_timing_val; + u32 phy_timing_len; + + u32 panel_jitter_numer; + u32 panel_jitter_denom; + u32 panel_prefill_lines; + u64 clk_rate_hz; + + struct msm_display_topology topology; + struct msm_display_dsc_info dsc; + bool dsc_enabled; + struct msm_roi_caps roi_caps; +}; + /** * struct dsi_display_mode - specifies mode for dsi display * @timing: Timing parameters for the panel. * @pixel_clk_khz: Pixel clock in Khz. - * @panel_mode: Panel operation mode. * @dsi_mode_flags: Flags to signal other drm components via private flags + * @priv_info: Mode private info */ struct dsi_display_mode { struct dsi_mode_info timing; u32 pixel_clk_khz; - enum dsi_op_mode panel_mode; u32 dsi_mode_flags; + struct dsi_display_mode_priv_info *priv_info; +}; + +/** + * struct dsi_rect - dsi rectangle representation + * Note: sde_rect is also using u16, this must be maintained for memcpy + */ +struct dsi_rect { + u16 x; + u16 y; + u16 w; + u16 h; +}; + +/** + * dsi_rect_intersect - intersect two rectangles + * @r1: first rectangle + * @r2: scissor rectangle + * @result: result rectangle, all 0's on no intersection found + */ +void dsi_rect_intersect(const struct dsi_rect *r1, + const struct dsi_rect *r2, + struct dsi_rect *result); + +/** + * dsi_rect_is_equal - compares two rects + * @r1: rect value to compare + * @r2: rect value to compare + * + * Returns true if the rects are same + */ +static inline bool dsi_rect_is_equal(struct dsi_rect *r1, + struct dsi_rect *r2) +{ + return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && + r1->h == r2->h; +} + +struct dsi_event_cb_info { + uint32_t event_idx; + void *event_usr_ptr; + + int (*event_cb)(void *event_usr_ptr, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); +}; + +/** + * enum dsi_error_status - various dsi errors + * @DSI_FIFO_OVERFLOW: DSI FIFO Overflow error + * @DSI_FIFO_UNDERFLOW: DSI FIFO Underflow error + * @DSI_LP_Rx_TIMEOUT: DSI LP/RX Timeout error + */ +enum dsi_error_status { + DSI_FIFO_OVERFLOW = 1, + DSI_FIFO_UNDERFLOW, + DSI_LP_Rx_TIMEOUT, }; #endif /* _DSI_DEFS_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 106511c447df348742cbe6d423d0bae7a4d068eb..c8edb0962ff4d64bec0ed11f7af50489a04ff25d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,8 +16,11 @@ #include #include +#include #include "msm_drv.h" +#include "sde_connector.h" +#include "msm_mmu.h" #include "dsi_display.h" #include "dsi_panel.h" #include "dsi_ctrl.h" @@ -25,12 +28,22 @@ #include "dsi_drm.h" #include "dsi_clk.h" #include "dsi_pwr.h" +#include "sde_dbg.h" #define to_dsi_display(x) container_of(x, struct dsi_display, host) +#define INT_BASE_10 10 +#define NO_OVERRIDE -1 + +#define MISR_BUFF_SIZE 256 + +#define MAX_NAME_SIZE 64 static DEFINE_MUTEX(dsi_display_list_lock); static LIST_HEAD(dsi_display_list); - +static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; +static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN]; +static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY]; +static struct device_node *default_active_node; static const struct of_device_id dsi_display_dt_match[] = { {.compatible = "qcom,dsi-display"}, {} @@ -38,21 +51,598 @@ static const struct of_device_id dsi_display_dt_match[] = { static struct dsi_display *main_display; +void dsi_rect_intersect(const struct dsi_rect *r1, + const struct dsi_rect *r2, + struct dsi_rect *result) +{ + int l, t, r, b; + + if (!r1 || !r2 || !result) + return; + + l = max(r1->x, r2->x); + t = max(r1->y, r2->y); + r = min((r1->x + r1->w), (r2->x + r2->w)); + b = min((r1->y + r1->h), (r2->y + r2->h)); + + if (r <= l || b <= t) { + memset(result, 0, sizeof(*result)); + } else { + result->x = l; + result->y = t; + result->w = r - l; + result->h = b - t; + } +} + int dsi_display_set_backlight(void *display, u32 bl_lvl) { struct dsi_display *dsi_display = display; struct dsi_panel *panel; + u32 bl_scale, bl_scale_ad; + u64 bl_temp; int rc = 0; - if (dsi_display == NULL) + if (dsi_display == NULL || dsi_display->panel == NULL) return -EINVAL; panel = dsi_display->panel; - rc = dsi_panel_set_backlight(panel, bl_lvl); + if (!dsi_panel_initialized(panel)) + return -EINVAL; + + panel->bl_config.bl_level = bl_lvl; + + /* scale backlight */ + bl_scale = panel->bl_config.bl_scale; + bl_temp = bl_lvl * bl_scale / MAX_BL_SCALE_LEVEL; + + bl_scale_ad = panel->bl_config.bl_scale_ad; + bl_temp = (u32)bl_temp * bl_scale_ad / MAX_AD_BL_SCALE_LEVEL; + + pr_debug("bl_scale = %u, bl_scale_ad = %u, bl_lvl = %u\n", + bl_scale, bl_scale_ad, (u32)bl_temp); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_backlight(panel, (u32)bl_temp); if (rc) pr_err("unable to set backlight\n"); + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + pr_err("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + +error: + return rc; +} + +static int dsi_display_cmd_engine_enable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + mutex_lock(&m_ctrl->ctrl->ctrl_lock); + + if (display->cmd_engine_refcount > 0) { + display->cmd_engine_refcount++; + goto done; + } + + rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON); + if (rc) { + pr_err("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto done; + } + + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_ON); + if (rc) { + pr_err("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto error_disable_master; + } + } + + display->cmd_engine_refcount++; + goto done; +error_disable_master: + (void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); +done: + mutex_unlock(&m_ctrl->ctrl->ctrl_lock); + return rc; +} + +static int dsi_display_cmd_engine_disable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + mutex_lock(&m_ctrl->ctrl->ctrl_lock); + + if (display->cmd_engine_refcount == 0) { + pr_err("[%s] Invalid refcount\n", display->name); + goto done; + } else if (display->cmd_engine_refcount > 1) { + display->cmd_engine_refcount--; + goto done; + } + + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_OFF); + if (rc) + pr_err("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + } + + rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); + if (rc) { + pr_err("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto error; + } + +error: + display->cmd_engine_refcount = 0; +done: + mutex_unlock(&m_ctrl->ctrl->ctrl_lock); + return rc; +} + +static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach) +{ + struct dsi_display *display; + struct dsi_display_ctrl *display_ctrl; + int rc, cnt; + + if (!cb_data) { + pr_err("aspace cb called with invalid cb_data\n"); + return; + } + display = (struct dsi_display *)cb_data; + + /* + * acquire panel_lock to make sure no commands are in-progress + * while detaching the non-secure context banks + */ + dsi_panel_acquire_panel_lock(display->panel); + + if (is_detach) { + /* invalidate the stored iova */ + display->cmd_buffer_iova = 0; + + /* return the virtual address mapping */ + msm_gem_put_vaddr_locked(display->tx_cmd_buf); + msm_gem_vunmap(display->tx_cmd_buf); + + } else { + rc = msm_gem_get_iova_locked(display->tx_cmd_buf, + display->aspace, &(display->cmd_buffer_iova)); + if (rc) { + pr_err("failed to get the iova rc %d\n", rc); + goto end; + } + + display->vaddr = + (void *) msm_gem_get_vaddr_locked(display->tx_cmd_buf); + + if (IS_ERR_OR_NULL(display->vaddr)) { + pr_err("failed to get va rc %d\n", rc); + goto end; + } + } + + for (cnt = 0; cnt < display->ctrl_count; cnt++) { + display_ctrl = &display->ctrl[cnt]; + display_ctrl->ctrl->cmd_buffer_size = display->cmd_buffer_size; + display_ctrl->ctrl->cmd_buffer_iova = display->cmd_buffer_iova; + display_ctrl->ctrl->vaddr = display->vaddr; + display_ctrl->ctrl->secure_mode = is_detach; + } + +end: + /* release panel_lock */ + dsi_panel_release_panel_lock(display->panel); +} + +/* Allocate memory for cmd dma tx buffer */ +static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display) +{ + int rc = 0, cnt = 0; + struct dsi_display_ctrl *display_ctrl; + + mutex_lock(&display->drm_dev->struct_mutex); + display->tx_cmd_buf = msm_gem_new(display->drm_dev, + SZ_4K, + MSM_BO_UNCACHED); + mutex_unlock(&display->drm_dev->struct_mutex); + + if ((display->tx_cmd_buf) == NULL) { + pr_err("Failed to allocate cmd tx buf memory\n"); + rc = -ENOMEM; + goto error; + } + + display->cmd_buffer_size = SZ_4K; + + display->aspace = msm_gem_smmu_address_space_get( + display->drm_dev, MSM_SMMU_DOMAIN_UNSECURE); + if (!display->aspace) { + pr_err("failed to get aspace\n"); + rc = -EINVAL; + goto free_gem; + } + /* register to aspace */ + rc = msm_gem_address_space_register_cb(display->aspace, + dsi_display_aspace_cb_locked, (void *)display); + if (rc) { + pr_err("failed to register callback %d", rc); + goto free_gem; + } + + rc = msm_gem_get_iova(display->tx_cmd_buf, display->aspace, + &(display->cmd_buffer_iova)); + if (rc) { + pr_err("failed to get the iova rc %d\n", rc); + goto free_aspace_cb; + } + + display->vaddr = + (void *) msm_gem_get_vaddr(display->tx_cmd_buf); + if (IS_ERR_OR_NULL(display->vaddr)) { + pr_err("failed to get va rc %d\n", rc); + rc = -EINVAL; + goto put_iova; + } + + for (cnt = 0; cnt < display->ctrl_count; cnt++) { + display_ctrl = &display->ctrl[cnt]; + display_ctrl->ctrl->cmd_buffer_size = SZ_4K; + display_ctrl->ctrl->cmd_buffer_iova = + display->cmd_buffer_iova; + display_ctrl->ctrl->vaddr = display->vaddr; + display_ctrl->ctrl->tx_cmd_buf = display->tx_cmd_buf; + } + + return rc; + +put_iova: + msm_gem_put_iova(display->tx_cmd_buf, display->aspace); +free_aspace_cb: + msm_gem_address_space_unregister_cb(display->aspace, + dsi_display_aspace_cb_locked, display); +free_gem: + mutex_lock(&display->drm_dev->struct_mutex); + msm_gem_free_object(display->tx_cmd_buf); + mutex_unlock(&display->drm_dev->struct_mutex); +error: + return rc; +} + +static bool dsi_display_validate_reg_read(struct dsi_panel *panel) +{ + int i, j = 0; + int len = 0, *lenp; + int group = 0, count = 0; + struct dsi_display_mode *mode; + struct drm_panel_esd_config *config; + + if (!panel) + return false; + + config = &(panel->esd_config); + + lenp = config->status_valid_params ?: config->status_cmds_rlen; + mode = panel->cur_mode; + count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_STATUS].count; + + for (i = 0; i < count; i++) + len += lenp[i]; + + for (i = 0; i < len; i++) + j += len; + + for (j = 0; j < config->groups; ++j) { + for (i = 0; i < len; ++i) { + if (config->return_buf[i] != + config->status_value[group + i]) + break; + } + + if (i == len) + return true; + group += len; + } + + return false; +} + +static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel) +{ + int i, rc = 0, count = 0, start = 0, *lenp; + struct drm_panel_esd_config *config; + struct dsi_cmd_desc *cmds; + u32 flags = 0; + + if (!panel) + return -EINVAL; + + /* acquire panel_lock to make sure no commands are in progress */ + dsi_panel_acquire_panel_lock(panel); + + config = &(panel->esd_config); + lenp = config->status_valid_params ?: config->status_cmds_rlen; + count = config->status_cmd.count; + cmds = config->status_cmd.cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + + for (i = 0; i < count; ++i) { + memset(config->status_buf, 0x0, SZ_4K); + cmds[i].msg.rx_buf = config->status_buf; + cmds[i].msg.rx_len = config->status_cmds_rlen[i]; + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags); + if (rc <= 0) { + pr_err("rx cmd transfer failed rc=%d\n", rc); + goto error; + } + + memcpy(config->return_buf + start, + config->status_buf, lenp[i]); + start += lenp[i]; + } + +error: + /* release panel_lock */ + dsi_panel_release_panel_lock(panel); + return rc; +} + +static int dsi_display_validate_status(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel) +{ + int rc = 0; + + rc = dsi_display_read_status(ctrl, panel); + if (rc <= 0) { + goto exit; + } else { + /* + * panel status read successfully. + * check for validity of the data read back. + */ + rc = dsi_display_validate_reg_read(panel); + if (!rc) { + rc = -EINVAL; + goto exit; + } + } + +exit: + return rc; +} + +static int dsi_display_status_reg_read(struct dsi_display *display) +{ + int rc = 0, i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + pr_debug(" ++\n"); + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + if (display->tx_cmd_buf == NULL) { + rc = dsi_host_alloc_cmd_tx_buffer(display); + if (rc) { + pr_err("failed to allocate cmd tx buffer memory\n"); + goto done; + } + } + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + pr_err("cmd engine enable failed\n"); + return -EPERM; + } + + rc = dsi_display_validate_status(m_ctrl, display->panel); + if (rc <= 0) { + pr_err("[%s] read status failed on master,rc=%d\n", + display->name, rc); + goto exit; + } + + if (!display->panel->sync_broadcast_en) + goto exit; + + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + if (ctrl == m_ctrl) + continue; + + rc = dsi_display_validate_status(ctrl, display->panel); + if (rc <= 0) { + pr_err("[%s] read status failed on master,rc=%d\n", + display->name, rc); + goto exit; + } + } +exit: + dsi_display_cmd_engine_disable(display); +done: + return rc; +} + +static int dsi_display_status_bta_request(struct dsi_display *display) +{ + int rc = 0; + + pr_debug(" ++\n"); + /* TODO: trigger SW BTA and wait for acknowledgment */ + + return rc; +} + +static int dsi_display_status_check_te(struct dsi_display *display) +{ + int rc = 0; + + pr_debug(" ++\n"); + /* TODO: wait for TE interrupt from panel */ + + return rc; +} + +int dsi_display_check_status(void *display) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + u32 status_mode; + int rc = 0x1; + + if (dsi_display == NULL) + return -EINVAL; + + panel = dsi_display->panel; + + status_mode = panel->esd_config.status_mode; + + mutex_lock(&dsi_display->display_lock); + + if (!panel->panel_initialized) { + pr_debug("Panel not initialized\n"); + mutex_unlock(&dsi_display->display_lock); + return rc; + } + + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + if (status_mode == ESD_MODE_REG_READ) { + rc = dsi_display_status_reg_read(dsi_display); + } else if (status_mode == ESD_MODE_SW_BTA) { + rc = dsi_display_status_bta_request(dsi_display); + } else if (status_mode == ESD_MODE_PANEL_TE) { + rc = dsi_display_status_check_te(dsi_display); + } else { + pr_warn("unsupported check status mode\n"); + panel->esd_config.esd_enabled = false; + } + + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + mutex_unlock(&dsi_display->display_lock); + + return rc; +} + +static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, + struct dsi_cmd_desc *cmd, u8 *payload, u32 payload_len) +{ + int i; + + memset(cmd, 0x00, sizeof(*cmd)); + cmd->msg.type = cmd_buf[0]; + cmd->last_command = (cmd_buf[1] == 1 ? true : false); + cmd->msg.channel = cmd_buf[2]; + cmd->msg.flags = cmd_buf[3]; + cmd->msg.ctrl = 0; + cmd->post_wait_ms = cmd_buf[4]; + cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6])); + + if (cmd->msg.tx_len > payload_len) { + pr_err("Incorrect payload length tx_len %ld, payload_len %d\n", + cmd->msg.tx_len, payload_len); + return -EINVAL; + } + + for (i = 0; i < cmd->msg.tx_len; i++) + payload[i] = cmd_buf[7 + i]; + + cmd->msg.tx_buf = payload; + return 0; +} + +static int dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, + bool *state) +{ + struct dsi_display_ctrl *ctrl; + int i, rc = -EINVAL; + + for (i = 0 ; i < dsi_display->ctrl_count; i++) { + ctrl = &dsi_display->ctrl[i]; + rc = dsi_ctrl_get_host_engine_init_state(ctrl->ctrl, state); + if (rc) + break; + } + return rc; +} + +int dsi_display_cmd_transfer(void *display, const char *cmd_buf, + u32 cmd_buf_len) +{ + struct dsi_display *dsi_display = display; + struct dsi_cmd_desc cmd; + u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE]; + int rc = 0; + bool state = false; + + if (!dsi_display || !cmd_buf) { + pr_err("[DSI] invalid params\n"); + return -EINVAL; + } + + pr_debug("[DSI] Display command transfer\n"); + + rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len, + &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE); + if (rc) { + pr_err("[DSI] command prepare failed. rc %d\n", rc); + return rc; + } + + mutex_lock(&dsi_display->display_lock); + rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); + if (rc || !state) { + pr_err("[DSI] Invalid host state %d rc %d\n", + state, rc); + rc = -EPERM; + goto end; + } + + rc = dsi_display->host.ops->transfer(&dsi_display->host, + &cmd.msg); +end: + mutex_unlock(&dsi_display->display_lock); return rc; } @@ -80,9 +670,88 @@ int dsi_display_soft_reset(void *display) return rc; } + +enum dsi_pixel_format dsi_display_get_dst_format(void *display) +{ + enum dsi_pixel_format format = DSI_PIXEL_FORMAT_MAX; + struct dsi_display *dsi_display = (struct dsi_display *)display; + + if (!dsi_display || !dsi_display->panel) { + pr_err("Invalid params(s) dsi_display %pK, panel %pK\n", + dsi_display, + ((dsi_display) ? dsi_display->panel : NULL)); + return format; + } + + format = dsi_display->panel->host_config.dst_format; + return format; +} + +static void _dsi_display_setup_misr(struct dsi_display *display) +{ + int i; + + for (i = 0; i < display->ctrl_count; i++) { + dsi_ctrl_setup_misr(display->ctrl[i].ctrl, + display->misr_enable, + display->misr_frame_count); + } +} + +/** + * dsi_display_get_cont_splash_status - Get continuous splash status. + * @dsi_display: DSI display handle. + * + * Return: boolean to signify whether continuous splash is enabled. + */ +static bool dsi_display_get_cont_splash_status(struct dsi_display *display) +{ + u32 val = 0; + int i; + struct dsi_display_ctrl *ctrl; + struct dsi_ctrl_hw *hw; + + for (i = 0; i < display->ctrl_count ; i++) { + ctrl = &(display->ctrl[i]); + if (!ctrl || !ctrl->ctrl) + continue; + + hw = &(ctrl->ctrl->hw); + val = hw->ops.get_cont_splash_status(hw); + if (!val) + return false; + } + return true; +} + +int dsi_display_set_power(struct drm_connector *connector, + int power_mode, void *disp) +{ + struct dsi_display *display = disp; + int rc = 0; + + if (!display || !display->panel) { + pr_err("invalid display/panel\n"); + return -EINVAL; + } + + switch (power_mode) { + case SDE_MODE_DPMS_LP1: + rc = dsi_panel_set_lp1(display->panel); + break; + case SDE_MODE_DPMS_LP2: + rc = dsi_panel_set_lp2(display->panel); + break; + default: + rc = dsi_panel_set_nolp(display->panel); + break; + } + return rc; +} + static ssize_t debugfs_dump_info_read(struct file *file, - char __user *buff, - size_t count, + char __user *user_buf, + size_t user_len, loff_t *ppos) { struct dsi_display *display = file->private_data; @@ -120,7 +789,7 @@ static ssize_t debugfs_dump_info_read(struct file *file, "\tClock master = %s\n", display->ctrl[display->clk_master_idx].ctrl->name); - if (copy_to_user(buff, buf, len)) { + if (copy_to_user(user_buf, buf, len)) { kfree(buf); return -EFAULT; } @@ -131,16 +800,153 @@ static ssize_t debugfs_dump_info_read(struct file *file, return len; } +static ssize_t debugfs_misr_setup(struct file *file, + const char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char *buf; + int rc = 0; + size_t len; + u32 enable, frame_count; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(MISR_BUFF_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* leave room for termination char */ + len = min_t(size_t, user_len, MISR_BUFF_SIZE - 1); + if (copy_from_user(buf, user_buf, len)) { + rc = -EINVAL; + goto error; + } + + buf[len] = '\0'; /* terminate the string */ + + if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) { + rc = -EINVAL; + goto error; + } + + display->misr_enable = enable; + display->misr_frame_count = frame_count; + + mutex_lock(&display->display_lock); + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto unlock; + } + + _dsi_display_setup_misr(display); + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + pr_err("[%s] failed to disable DSI core clocks, rc=%d\n", + display->name, rc); + goto unlock; + } + + rc = user_len; +unlock: + mutex_unlock(&display->display_lock); +error: + kfree(buf); + return rc; +} + +static ssize_t debugfs_misr_read(struct file *file, + char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char *buf; + u32 len = 0; + int rc = 0; + struct dsi_ctrl *dsi_ctrl; + int i; + u32 misr; + size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE); + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(max_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&display->display_lock); + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto error; + } + + for (i = 0; i < display->ctrl_count; i++) { + dsi_ctrl = display->ctrl[i].ctrl; + misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl); + + len += snprintf((buf + len), max_len - len, + "DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr); + + if (len >= max_len) + break; + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + pr_err("[%s] failed to disable DSI core clocks, rc=%d\n", + display->name, rc); + goto error; + } + + if (copy_to_user(user_buf, buf, len)) { + rc = -EFAULT; + goto error; + } + + *ppos += len; + +error: + mutex_unlock(&display->display_lock); + kfree(buf); + return len; +} static const struct file_operations dump_info_fops = { .open = simple_open, .read = debugfs_dump_info_read, }; +static const struct file_operations misr_data_fops = { + .open = simple_open, + .read = debugfs_misr_read, + .write = debugfs_misr_setup, +}; + static int dsi_display_debugfs_init(struct dsi_display *display) { int rc = 0; - struct dentry *dir, *dump_file; + struct dentry *dir, *dump_file, *misr_data; + char name[MAX_NAME_SIZE]; + int i; dir = debugfs_create_dir(display->name, NULL); if (IS_ERR_OR_NULL(dir)) { @@ -151,17 +957,72 @@ static int dsi_display_debugfs_init(struct dsi_display *display) } dump_file = debugfs_create_file("dump_info", - 0444, + 0400, dir, display, &dump_info_fops); if (IS_ERR_OR_NULL(dump_file)) { rc = PTR_ERR(dump_file); - pr_err("[%s] debugfs create file failed, rc=%d\n", + pr_err("[%s] debugfs create dump info file failed, rc=%d\n", display->name, rc); goto error_remove_dir; } + misr_data = debugfs_create_file("misr_data", + 0600, + dir, + display, + &misr_data_fops); + if (IS_ERR_OR_NULL(misr_data)) { + rc = PTR_ERR(misr_data); + pr_err("[%s] debugfs create misr datafile failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + + for (i = 0; i < display->ctrl_count; i++) { + struct msm_dsi_phy *phy = display->ctrl[i].phy; + + if (!phy || !phy->name) + continue; + + snprintf(name, ARRAY_SIZE(name), + "%s_allow_phy_power_off", phy->name); + dump_file = debugfs_create_bool(name, 0600, dir, + &phy->allow_phy_power_off); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + pr_err("[%s] debugfs create %s failed, rc=%d\n", + display->name, name, rc); + goto error_remove_dir; + } + + snprintf(name, ARRAY_SIZE(name), + "%s_regulator_min_datarate_bps", phy->name); + dump_file = debugfs_create_u32(name, 0600, dir, + &phy->regulator_min_datarate_bps); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + pr_err("[%s] debugfs create %s failed, rc=%d\n", + display->name, name, rc); + goto error_remove_dir; + } + } + + if (!debugfs_create_bool("ulps_enable", 0600, dir, + &display->panel->ulps_enabled)) { + pr_err("[%s] debugfs create ulps enable file failed\n", + display->name); + goto error_remove_dir; + } + + if (!debugfs_create_bool("ulps_suspend_enable", 0600, dir, + &display->panel->ulps_suspend_enabled)) { + pr_err("[%s] debugfs create ulps-suspend enable file failed\n", + display->name); + goto error_remove_dir; + } + display->root = dir; return rc; error_remove_dir: @@ -198,12 +1059,17 @@ static int dsi_display_is_ulps_req_valid(struct dsi_display *display, pr_debug("checking ulps req validity\n"); - if (!dsi_panel_ulps_feature_enabled(display->panel)) + if (!dsi_panel_ulps_feature_enabled(display->panel) && + !display->panel->ulps_suspend_enabled) { + pr_debug("%s: ULPS feature is not enabled\n", __func__); return false; + } - /* TODO: ULPS during suspend */ - if (!dsi_panel_initialized(display->panel)) + if (!dsi_panel_initialized(display->panel) && + !display->panel->ulps_suspend_enabled) { + pr_debug("%s: panel not yet initialized\n", __func__); return false; + } if (enable && display->ulps_enabled) { pr_debug("ULPS already enabled\n"); @@ -379,7 +1245,7 @@ static int dsi_display_phy_enable(struct dsi_display *display); /** * dsi_display_phy_idle_on() - enable DSI PHY while coming out of idle screen. * @dsi_display: DSI display handle. - * @enable: enable/disable DSI PHY. + * @mmss_clamp: True if clamp is enabled. * * Return: error code. */ @@ -426,7 +1292,6 @@ static int dsi_display_phy_idle_on(struct dsi_display *display, /** * dsi_display_phy_idle_off() - disable DSI PHY while going to idle screen. * @dsi_display: DSI display handle. - * @enable: enable/disable DSI PHY. * * Return: error code. */ @@ -441,9 +1306,16 @@ static int dsi_display_phy_idle_off(struct dsi_display *display) return -EINVAL; } - if (!display->panel->allow_phy_power_off) { - pr_debug("panel doesn't support this feature\n"); - return 0; + for (i = 0; i < display->ctrl_count; i++) { + struct msm_dsi_phy *phy = display->ctrl[i].phy; + + if (!phy) + continue; + + if (!phy->allow_phy_power_off) { + pr_debug("phy doesn't support this feature\n"); + return 0; + } } m_ctrl = &display->ctrl[display->cmd_master_idx]; @@ -470,7 +1342,76 @@ static int dsi_display_phy_idle_off(struct dsi_display *display) return 0; } +void dsi_display_enable_event(struct dsi_display *display, + uint32_t event_idx, struct dsi_event_cb_info *event_info, + bool enable) +{ + uint32_t irq_status_idx = DSI_STATUS_INTERRUPT_COUNT; + int i; + + if (!display) { + pr_err("invalid display\n"); + return; + } + + if (event_info) + event_info->event_idx = event_idx; + + switch (event_idx) { + case SDE_CONN_EVENT_VID_DONE: + irq_status_idx = DSI_SINT_VIDEO_MODE_FRAME_DONE; + break; + case SDE_CONN_EVENT_CMD_DONE: + irq_status_idx = DSI_SINT_CMD_FRAME_DONE; + break; + case SDE_CONN_EVENT_VID_FIFO_OVERFLOW: + case SDE_CONN_EVENT_CMD_FIFO_UNDERFLOW: + if (event_info) { + for (i = 0; i < display->ctrl_count; i++) + display->ctrl[i].ctrl->recovery_cb = + *event_info; + } + default: + /* nothing to do */ + pr_debug("[%s] unhandled event %d\n", display->name, event_idx); + return; + } + + if (enable) { + for (i = 0; i < display->ctrl_count; i++) + dsi_ctrl_enable_status_interrupt( + display->ctrl[i].ctrl, irq_status_idx, + event_info); + } else { + for (i = 0; i < display->ctrl_count; i++) + dsi_ctrl_disable_status_interrupt( + display->ctrl[i].ctrl, irq_status_idx); + } +} + +/** + * dsi_config_host_engine_state_for_cont_splash()- update host engine state + * during continuous splash. + * @display: Handle to dsi display + * + */ +static void dsi_config_host_engine_state_for_cont_splash + (struct dsi_display *display) +{ + int i; + struct dsi_display_ctrl *ctrl; + enum dsi_engine_state host_state = DSI_CTRL_ENGINE_ON; + + /* Sequence does not matter for split dsi usecases */ + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + dsi_ctrl_update_host_engine_state_for_cont_splash(ctrl->ctrl, + host_state); + } +} static int dsi_display_ctrl_power_on(struct dsi_display *display) { @@ -529,6 +1470,201 @@ static int dsi_display_ctrl_power_off(struct dsi_display *display) return rc; } +static void dsi_display_parse_cmdline_topology(struct dsi_display *display, + unsigned int display_type) +{ + char *boot_str = NULL; + char *str = NULL; + unsigned long value; + + if (display_type >= MAX_DSI_ACTIVE_DISPLAY) { + pr_err("display_type=%d not supported\n", display_type); + return; + } + + if (display_type == DSI_PRIMARY) + boot_str = dsi_display_primary; + else + boot_str = dsi_display_secondary; + + str = strnstr(boot_str, ":config", strlen(boot_str)); + if (!str) + return; + + if (kstrtol(str + strlen(":config"), INT_BASE_10, + (unsigned long *)&value)) { + pr_err("invalid config index override: %s\n", boot_str); + return; + } + display->cmdline_topology = value; + + str = strnstr(boot_str, ":timing", strlen(boot_str)); + if (!str) + return; + + if (kstrtol(str + strlen(":timing"), INT_BASE_10, + (unsigned long *)&value)) { + pr_err("invalid timing index override: %s. resetting both timing and config\n", + boot_str); + display->cmdline_topology = NO_OVERRIDE; + return; + } + display->cmdline_timing = value; +} + +/** + * dsi_display_name_compare()- compare whether DSI display name matches. + * @node: Pointer to device node structure + * @display_name: Name of display to validate + * + * Return: returns a bool specifying whether given display is active + */ +static bool dsi_display_name_compare(struct device_node *node, + const char *display_name, int index) +{ + if (index >= MAX_DSI_ACTIVE_DISPLAY) { + pr_err("Invalid Index\n"); + return false; + } + + if (boot_displays[index].boot_disp_en) { + if (!(strcmp(&boot_displays[index].name[0], display_name))) { + boot_displays[index].node = node; + return true; + } + } + return false; +} + +/** + * dsi_display_parse_boot_display_selection()- Parse DSI boot display name + * + * Return: returns error status + */ +static int dsi_display_parse_boot_display_selection(void) +{ + char *pos = NULL; + char disp_buf[MAX_CMDLINE_PARAM_LEN] = {'\0'}; + int i, j, num_displays; + + if (strlen(dsi_display_primary) == 0) + return -EINVAL; + + if ((strlen(dsi_display_secondary) > 0)) + num_displays = MAX_DSI_ACTIVE_DISPLAY; + else { + /* + * Initialize secondary dsi variables + * for the senario where dsi_display1 + * is null but dsi_display0 is valid + */ + + /* Max number of displays will be one->only Primary */ + num_displays = 1; + boot_displays[DSI_SECONDARY].is_primary = false; + boot_displays[DSI_SECONDARY].name[0] = '\0'; + } + + for (i = 0; i < num_displays; i++) { + boot_displays[i].is_primary = false; + if (i == DSI_PRIMARY) { + strlcpy(disp_buf, &dsi_display_primary[0], + sizeof(dsi_display_primary)); + pos = strnstr(disp_buf, ":", + sizeof(dsi_display_primary)); + } else { + strlcpy(disp_buf, &dsi_display_secondary[0], + sizeof(dsi_display_secondary)); + pos = strnstr(disp_buf, ":", + sizeof(dsi_display_secondary)); + } + /* Use ':' as a delimiter to retrieve the display name */ + if (!pos) { + pr_debug("display name[%s]is not valid\n", disp_buf); + continue; + } + + for (j = 0; (disp_buf + j) < pos; j++) + boot_displays[i].name[j] = *(disp_buf + j); + boot_displays[i].name[j] = '\0'; + + if (i == DSI_PRIMARY) { + boot_displays[i].is_primary = true; + /* Currently, secondary DSI display is not supported */ + boot_displays[i].boot_disp_en = true; + } + } + return 0; +} + +/** + * validate_dsi_display_selection()- validate boot DSI display selection + * + * Return: returns true when both displays have unique configurations + */ +static bool validate_dsi_display_selection(void) +{ + int i, j; + int rc = 0; + int phy_count = 0; + int ctrl_count = 0; + int index = 0; + bool ctrl_flags[MAX_DSI_ACTIVE_DISPLAY] = {false, false}; + bool phy_flags[MAX_DSI_ACTIVE_DISPLAY] = {false, false}; + struct device_node *node, *ctrl_node, *phy_node; + + for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) { + node = boot_displays[i].node; + ctrl_count = of_count_phandle_with_args(node, "qcom,dsi-ctrl", + NULL); + + for (j = 0; j < ctrl_count; j++) { + ctrl_node = of_parse_phandle(node, "qcom,dsi-ctrl", j); + rc = of_property_read_u32(ctrl_node, "cell-index", + &index); + of_node_put(ctrl_node); + if (rc) { + pr_err("cell index not set for ctrl_nodes\n"); + return false; + } + if (ctrl_flags[index]) + return false; + ctrl_flags[index] = true; + } + + phy_count = of_count_phandle_with_args(node, "qcom,dsi-phy", + NULL); + for (j = 0; j < phy_count; j++) { + phy_node = of_parse_phandle(node, "qcom,dsi-phy", j); + rc = of_property_read_u32(phy_node, "cell-index", + &index); + of_node_put(phy_node); + if (rc) { + pr_err("cell index not set phy_nodes\n"); + return false; + } + if (phy_flags[index]) + return false; + phy_flags[index] = true; + } + } + return true; +} + +struct device_node *dsi_display_get_boot_display(int index) +{ + + pr_err("index = %d\n", index); + + if (boot_displays[index].node) + return boot_displays[index].node; + else if ((index == (MAX_DSI_ACTIVE_DISPLAY - 1)) + && (default_active_node)) + return default_active_node; + else + return NULL; +} + static int dsi_display_phy_power_on(struct dsi_display *display) { int rc = 0; @@ -640,7 +1776,7 @@ static int dsi_display_phy_reset_config(struct dsi_display *display, return 0; } -static int dsi_display_ctrl_init(struct dsi_display *display) +static int dsi_display_ctrl_update(struct dsi_display *display) { int rc = 0; int i; @@ -648,10 +1784,10 @@ static int dsi_display_ctrl_init(struct dsi_display *display) for (i = 0 ; i < display->ctrl_count; i++) { ctrl = &display->ctrl[i]; - rc = dsi_ctrl_host_init(ctrl->ctrl); + rc = dsi_ctrl_host_timing_update(ctrl->ctrl); if (rc) { - pr_err("[%s] failed to init host_%d, rc=%d\n", - display->name, i, rc); + pr_err("[%s] failed to update host_%d, rc=%d\n", + display->name, i, rc); goto error_host_deinit; } } @@ -662,10 +1798,11 @@ static int dsi_display_ctrl_init(struct dsi_display *display) ctrl = &display->ctrl[i]; (void)dsi_ctrl_host_deinit(ctrl->ctrl); } + return rc; } -static int dsi_display_ctrl_deinit(struct dsi_display *display) +static int dsi_display_ctrl_init(struct dsi_display *display) { int rc = 0; int i; @@ -673,103 +1810,56 @@ static int dsi_display_ctrl_deinit(struct dsi_display *display) for (i = 0 ; i < display->ctrl_count; i++) { ctrl = &display->ctrl[i]; - rc = dsi_ctrl_host_deinit(ctrl->ctrl); + rc = dsi_ctrl_host_init(ctrl->ctrl, + display->is_cont_splash_enabled); if (rc) { - pr_err("[%s] failed to deinit host_%d, rc=%d\n", + pr_err("[%s] failed to init host_%d, rc=%d\n", display->name, i, rc); + goto error_host_deinit; } } + return 0; +error_host_deinit: + for (i = i - 1; i >= 0; i--) { + ctrl = &display->ctrl[i]; + (void)dsi_ctrl_host_deinit(ctrl->ctrl); + } return rc; } -static int dsi_display_cmd_engine_enable(struct dsi_display *display) +static int dsi_display_ctrl_deinit(struct dsi_display *display) { int rc = 0; int i; - struct dsi_display_ctrl *m_ctrl, *ctrl; - - if (display->cmd_engine_refcount > 0) { - display->cmd_engine_refcount++; - return 0; - } - - m_ctrl = &display->ctrl[display->cmd_master_idx]; - - rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON); - if (rc) { - pr_err("[%s] failed to enable cmd engine, rc=%d\n", - display->name, rc); - goto error; - } + struct dsi_display_ctrl *ctrl; - for (i = 0; i < display->ctrl_count; i++) { + for (i = 0 ; i < display->ctrl_count; i++) { ctrl = &display->ctrl[i]; - if (!ctrl->ctrl || (ctrl == m_ctrl)) - continue; - - rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl, - DSI_CTRL_ENGINE_ON); + rc = dsi_ctrl_host_deinit(ctrl->ctrl); if (rc) { - pr_err("[%s] failed to enable cmd engine, rc=%d\n", - display->name, rc); - goto error_disable_master; + pr_err("[%s] failed to deinit host_%d, rc=%d\n", + display->name, i, rc); } } - display->cmd_engine_refcount++; - return rc; -error_disable_master: - (void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); -error: return rc; } -static int dsi_display_cmd_engine_disable(struct dsi_display *display) +static int dsi_display_ctrl_host_enable(struct dsi_display *display) { int rc = 0; int i; struct dsi_display_ctrl *m_ctrl, *ctrl; - if (display->cmd_engine_refcount == 0) { - pr_err("[%s] Invalid refcount\n", display->name); - return 0; - } else if (display->cmd_engine_refcount > 1) { - display->cmd_engine_refcount--; + /* Host engine states are already taken care for + * continuous splash case + */ + if (display->is_cont_splash_enabled) { + pr_debug("cont splash enabled, host enable not required\n"); return 0; } - m_ctrl = &display->ctrl[display->cmd_master_idx]; - for (i = 0; i < display->ctrl_count; i++) { - ctrl = &display->ctrl[i]; - if (!ctrl->ctrl || (ctrl == m_ctrl)) - continue; - - rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl, - DSI_CTRL_ENGINE_OFF); - if (rc) - pr_err("[%s] failed to enable cmd engine, rc=%d\n", - display->name, rc); - } - - rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); - if (rc) { - pr_err("[%s] failed to enable cmd engine, rc=%d\n", - display->name, rc); - goto error; - } - -error: - display->cmd_engine_refcount = 0; - return rc; -} - -static int dsi_display_ctrl_host_enable(struct dsi_display *display) -{ - int rc = 0; - int i; - struct dsi_display_ctrl *m_ctrl, *ctrl; - m_ctrl = &display->ctrl[display->cmd_master_idx]; rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON); @@ -908,7 +1998,8 @@ static int dsi_display_phy_enable(struct dsi_display *display) rc = dsi_phy_enable(m_ctrl->phy, &display->config, m_src, - true); + true, + display->is_cont_splash_enabled); if (rc) { pr_err("[%s] failed to enable DSI PHY, rc=%d\n", display->name, rc); @@ -923,7 +2014,8 @@ static int dsi_display_phy_enable(struct dsi_display *display) rc = dsi_phy_enable(ctrl->phy, &display->config, DSI_PLL_SOURCE_NON_NATIVE, - true); + true, + display->is_cont_splash_enabled); if (rc) { pr_err("[%s] failed to enable DSI PHY, rc=%d\n", display->name, rc); @@ -980,10 +2072,14 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, int i; m_flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_BROADCAST_MASTER | - DSI_CTRL_CMD_DEFER_TRIGGER | DSI_CTRL_CMD_FIFO_STORE); + DSI_CTRL_CMD_DEFER_TRIGGER | DSI_CTRL_CMD_FETCH_MEMORY); flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_DEFER_TRIGGER | - DSI_CTRL_CMD_FIFO_STORE); + DSI_CTRL_CMD_FETCH_MEMORY); + if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) { + flags |= DSI_CTRL_CMD_LAST_COMMAND; + m_flags |= DSI_CTRL_CMD_LAST_COMMAND; + } /* * 1. Setup commands in FIFO * 2. Trigger commands @@ -1008,8 +2104,7 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, goto error; } - rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl, - DSI_CTRL_CMD_BROADCAST); + rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl, flags); if (rc) { pr_err("[%s] cmd trigger failed, rc=%d\n", display->name, rc); @@ -1017,9 +2112,7 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display, } } - rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl, - (DSI_CTRL_CMD_BROADCAST_MASTER | - DSI_CTRL_CMD_BROADCAST)); + rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl, m_flags); if (rc) { pr_err("[%s] cmd trigger failed for master, rc=%d\n", display->name, rc); @@ -1036,6 +2129,14 @@ static int dsi_display_phy_sw_reset(struct dsi_display *display) int i; struct dsi_display_ctrl *m_ctrl, *ctrl; + /* For continuous splash use case ctrl states are updated + * separately and hence we do an early return + */ + if (display->is_cont_splash_enabled) { + pr_debug("cont splash enabled, phy sw reset not required\n"); + return 0; + } + m_ctrl = &display->ctrl[display->cmd_master_idx]; rc = dsi_ctrl_phy_sw_reset(m_ctrl->ctrl); @@ -1077,7 +2178,6 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) { struct dsi_display *display = to_dsi_display(host); - int rc = 0; if (!host || !msg) { @@ -1107,6 +2207,14 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, goto error_disable_clks; } + if (display->tx_cmd_buf == NULL) { + rc = dsi_host_alloc_cmd_tx_buffer(display); + if (rc) { + pr_err("failed to allocate cmd tx buffer memory\n"); + goto error_disable_cmd_engine; + } + } + if (display->ctrl_count > 1 && !(msg->flags & MIPI_DSI_MSG_UNICAST)) { rc = dsi_display_broadcast_cmd(display, msg); if (rc) { @@ -1119,20 +2227,21 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, msg->ctrl : 0; rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg, - DSI_CTRL_CMD_FIFO_STORE); + DSI_CTRL_CMD_FETCH_MEMORY); if (rc) { pr_err("[%s] cmd transfer failed, rc=%d\n", display->name, rc); goto error_disable_cmd_engine; } } + error_disable_cmd_engine: (void)dsi_display_cmd_engine_disable(display); error_disable_clks: rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); if (rc) { - pr_err("[%s] failed to enable all DSI clocks, rc=%d\n", + pr_err("[%s] failed to disable all DSI clocks, rc=%d\n", display->name, rc); } error: @@ -1243,7 +2352,7 @@ static int dsi_display_clocks_init(struct dsi_display *display) mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk"); if (IS_ERR_OR_NULL(mux->byte_clk)) { rc = PTR_ERR(mux->byte_clk); - pr_err("failed to get mux_byte_clk, rc=%d\n", rc); + pr_debug("failed to get mux_byte_clk, rc=%d\n", rc); mux->byte_clk = NULL; /* * Skip getting rest of clocks since one failed. This is a @@ -1258,7 +2367,7 @@ static int dsi_display_clocks_init(struct dsi_display *display) if (IS_ERR_OR_NULL(mux->pixel_clk)) { rc = PTR_ERR(mux->pixel_clk); mux->pixel_clk = NULL; - pr_err("failed to get mux_pixel_clk, rc=%d\n", rc); + pr_debug("failed to get mux_pixel_clk, rc=%d\n", rc); /* * Skip getting rest of clocks since one failed. This is a * non-critical failure since these clocks are requied only for @@ -1342,6 +2451,40 @@ static int dsi_display_clk_ctrl_cb(void *priv, return 0; } +static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + for (i = 0; (i < display->ctrl_count) && + (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + dsi_ctrl_isr_configure(ctrl->ctrl, en); + } +} + +static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + for (i = 0; (i < display->ctrl_count) && + (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + dsi_ctrl_irq_update(ctrl->ctrl, en); + } +} + int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk, enum dsi_clk_state new_state) @@ -1352,27 +2495,37 @@ int dsi_pre_clkoff_cb(void *priv, if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) { /* * If ULPS feature is enabled, enter ULPS first. + * However, when blanking the panel, we should enter ULPS + * only if ULPS during suspend feature is enabled. */ - if (dsi_panel_initialized(display->panel) && - dsi_panel_ulps_feature_enabled(display->panel)) { + if (!dsi_panel_initialized(display->panel)) { + if (display->panel->ulps_suspend_enabled) + rc = dsi_display_set_ulps(display, true); + } else if (dsi_panel_ulps_feature_enabled(display->panel)) { rc = dsi_display_set_ulps(display, true); - if (rc) { - pr_err("%s: failed enable ulps, rc = %d\n", - __func__, rc); - } } + if (rc) + pr_err("%s: failed enable ulps, rc = %d\n", + __func__, rc); } if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) { /* - * Enable DSI clamps only if entering idle power collapse. + * Enable DSI clamps only if entering idle power collapse or + * when ULPS during suspend is enabled.. */ - if (dsi_panel_initialized(display->panel)) { + if (dsi_panel_initialized(display->panel) || + display->panel->ulps_suspend_enabled) { dsi_display_phy_idle_off(display); rc = dsi_display_set_clamp(display, true); if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); + + rc = dsi_display_phy_reset_config(display, false); + if (rc) + pr_err("%s: Failed to reset phy, rc=%d\n", + __func__, rc); } else { /* Make sure that controller is not in ULPS state when * the DSI link is not active. @@ -1428,6 +2581,13 @@ int dsi_post_clkon_cb(void *priv, } } + rc = dsi_display_phy_reset_config(display, true); + if (rc) { + pr_err("%s: Failed to reset phy, rc=%d\n", + __func__, rc); + goto error; + } + rc = dsi_display_set_clamp(display, false); if (rc) { pr_err("%s: Failed to disable dsi clamps. rc=%d\n", @@ -1441,6 +2601,9 @@ int dsi_post_clkon_cb(void *priv, */ if (display->phy_idle_power_off || mmss_clamp) dsi_display_phy_idle_on(display, mmss_clamp); + + /* enable dsi to serve irqs */ + dsi_display_ctrl_irq_update(display, true); } if (clk & DSI_LINK_CLK) { if (display->ulps_enabled) { @@ -1470,6 +2633,8 @@ int dsi_post_clkoff_cb(void *priv, if ((clk_type & DSI_CORE_CLK) && (curr_state == DSI_CLK_OFF)) { + /* dsi will not be able to serve irqs from here */ + dsi_display_ctrl_irq_update(display, false); rc = dsi_display_phy_power_off(display); if (rc) @@ -1507,6 +2672,7 @@ int dsi_pre_clkon_cb(void *priv, * not be changed during static screen. */ + pr_debug("updating power states for ctrl and phy\n"); rc = dsi_display_ctrl_power_on(display); if (rc) { pr_err("[%s] failed to power on dsi controllers, rc=%d\n", @@ -1558,7 +2724,7 @@ static int dsi_display_parse_lane_map(struct dsi_display *display) display->lane_map.lane_map_v2[i] = BIT(temp[i]); return 0; } else if (rc != EINVAL) { - pr_warn("Incorrect mapping, configure default\n"); + pr_debug("Incorrect mapping, configure default\n"); goto set_default; } @@ -1718,7 +2884,8 @@ static int dsi_display_res_init(struct dsi_display *display) } } - display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of); + display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of, + display->cmdline_topology); if (IS_ERR_OR_NULL(display->panel)) { rc = PTR_ERR(display->panel); pr_err("failed to get panel, rc=%d\n", rc); @@ -1726,17 +2893,6 @@ static int dsi_display_res_init(struct dsi_display *display) goto error_ctrl_put; } - if (display->panel->phy_timing_len) { - for (i = 0; i < display->ctrl_count; i++) { - ctrl = &display->ctrl[i]; - rc = dsi_phy_set_timing_params(ctrl->phy, - display->panel->phy_timing_val, - display->panel->phy_timing_len); - if (rc) - pr_err("failed to add DSI PHY timing params"); - } - } - rc = dsi_display_parse_lane_map(display); if (rc) { pr_err("Lane map not found, rc=%d\n", rc); @@ -1775,6 +2931,9 @@ static int dsi_display_res_deinit(struct dsi_display *display) dsi_ctrl_put(ctrl->ctrl); } + if (display->panel) + dsi_panel_put(display->panel); + return rc; } @@ -1813,12 +2972,12 @@ static bool dsi_display_is_seamless_dfps_possible( { struct dsi_display_mode *cur; - if (!display || !tgt) { + if (!display || !tgt || !display->panel) { pr_err("Invalid params\n"); return false; } - cur = &display->panel->mode; + cur = display->panel->cur_mode; if (cur->timing.h_active != tgt->timing.h_active) { pr_debug("timing.h_active differs %d %d\n", @@ -1897,12 +3056,6 @@ static bool dsi_display_is_seamless_dfps_possible( pr_debug("pixel_clk_khz differs %d %d\n", cur->pixel_clk_khz, tgt->pixel_clk_khz); - if (cur->panel_mode != tgt->panel_mode) { - pr_debug("panel_mode differs %d %d\n", - cur->panel_mode, tgt->panel_mode); - return false; - } - if (cur->dsi_mode_flags != tgt->dsi_mode_flags) pr_debug("flags differs %d %d\n", cur->dsi_mode_flags, tgt->dsi_mode_flags); @@ -1920,7 +3073,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, int rc = 0; int i = 0; - if (!display || !dsi_mode) { + if (!display || !dsi_mode || !display->panel) { pr_err("Invalid params\n"); return -EINVAL; } @@ -1963,7 +3116,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, } } - panel_mode = &display->panel->mode; + panel_mode = display->panel->cur_mode; memcpy(panel_mode, dsi_mode, sizeof(*panel_mode)); /* * dsi_mode_flags flags are used to communicate with other drm driver @@ -1978,7 +3131,7 @@ static int dsi_display_dfps_update(struct dsi_display *display, } static int dsi_display_dfps_calc_front_porch( - u64 clk_hz, + u32 old_fps, u32 new_fps, u32 a_total, u32 b_total, @@ -1986,6 +3139,7 @@ static int dsi_display_dfps_calc_front_porch( u32 *b_fp_out) { s32 b_fp_new; + int add_porches, diff; if (!b_fp_out) { pr_err("Invalid params"); @@ -1997,15 +3151,22 @@ static int dsi_display_dfps_calc_front_porch( return -EINVAL; } - /** + /* * Keep clock, other porches constant, use new fps, calc front porch - * clk = (hor * ver * fps) - * hfront = clk / (vtotal * fps)) - hactive - hback - hsync + * new_vtotal = old_vtotal * (old_fps / new_fps ) + * new_vfp - old_vfp = new_vtotal - old_vtotal + * new_vfp = old_vfp + old_vtotal * ((old_fps - new_fps)/ new_fps) */ - b_fp_new = (clk_hz / (a_total * new_fps)) - (b_total - b_fp); + diff = abs(old_fps - new_fps); + add_porches = mult_frac(b_total, diff, new_fps); + + if (old_fps > new_fps) + b_fp_new = b_fp + add_porches; + else + b_fp_new = b_fp - add_porches; - pr_debug("clk %llu fps %u a %u b %u b_fp %u new_fp %d\n", - clk_hz, new_fps, a_total, b_total, b_fp, b_fp_new); + pr_debug("fps %u a %u b %u b_fp %u new_fp %d\n", + new_fps, a_total, b_total, b_fp, b_fp_new); if (b_fp_new < 0) { pr_err("Invalid new_hfp calcluated%d\n", b_fp_new); @@ -2021,14 +3182,25 @@ static int dsi_display_dfps_calc_front_porch( return 0; } +/** + * dsi_display_get_dfps_timing() - Get the new dfps values. + * @display: DSI display handle. + * @adj_mode: Mode value structure to be changed. + * It contains old timing values and latest fps value. + * New timing values are updated based on new fps. + * @curr_refresh_rate: Current fps rate. + * If zero , current fps rate is taken from + * display->panel->cur_mode. + * Return: error code. + */ static int dsi_display_get_dfps_timing(struct dsi_display *display, - struct dsi_display_mode *adj_mode) + struct dsi_display_mode *adj_mode, + u32 curr_refresh_rate) { struct dsi_dfps_capabilities dfps_caps; struct dsi_display_mode per_ctrl_mode; struct dsi_mode_info *timing; struct dsi_ctrl *m_ctrl; - u64 clk_hz; int rc = 0; @@ -2047,20 +3219,27 @@ static int dsi_display_get_dfps_timing(struct dsi_display *display, per_ctrl_mode = *adj_mode; adjust_timing_by_ctrl_count(display, &per_ctrl_mode); - if (!dsi_display_is_seamless_dfps_possible(display, - &per_ctrl_mode, dfps_caps.type)) { - pr_err("seamless dynamic fps not supported for mode\n"); - return -EINVAL; + if (!curr_refresh_rate) { + if (!dsi_display_is_seamless_dfps_possible(display, + &per_ctrl_mode, dfps_caps.type)) { + pr_err("seamless dynamic fps not supported for mode\n"); + return -EINVAL; + } + if (display->panel->cur_mode) { + curr_refresh_rate = + display->panel->cur_mode->timing.refresh_rate; + } else { + pr_err("cur_mode is not initialized\n"); + return -EINVAL; + } } - /* TODO: Remove this direct reference to the dsi_ctrl */ - clk_hz = m_ctrl->clk_freq.pix_clk_rate; timing = &per_ctrl_mode.timing; switch (dfps_caps.type) { case DSI_DFPS_IMMEDIATE_VFP: rc = dsi_display_dfps_calc_front_porch( - clk_hz, + curr_refresh_rate, timing->refresh_rate, DSI_H_TOTAL(timing), DSI_V_TOTAL(timing), @@ -2070,7 +3249,7 @@ static int dsi_display_get_dfps_timing(struct dsi_display *display, case DSI_DFPS_IMMEDIATE_HFP: rc = dsi_display_dfps_calc_front_porch( - clk_hz, + curr_refresh_rate, timing->refresh_rate, DSI_V_TOTAL(timing), DSI_H_TOTAL(timing), @@ -2099,7 +3278,7 @@ static bool dsi_display_validate_mode_seamless(struct dsi_display *display, } /* Currently the only seamless transition is dynamic fps */ - rc = dsi_display_get_dfps_timing(display, adj_mode); + rc = dsi_display_get_dfps_timing(display, adj_mode, 0); if (rc) { pr_debug("Dynamic FPS not supported for seamless\n"); } else { @@ -2118,6 +3297,14 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, int rc = 0; int i; struct dsi_display_ctrl *ctrl; + struct dsi_display_mode_priv_info *priv_info; + + priv_info = mode->priv_info; + if (!priv_info) { + pr_err("[%s] failed to get private info of the display mode", + display->name); + return -EINVAL; + } rc = dsi_panel_get_host_cfg_for_mode(display->panel, mode, @@ -2131,7 +3318,8 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, memcpy(&display->config.lane_map, &display->lane_map, sizeof(display->lane_map)); - if (mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) { + if (mode->dsi_mode_flags & + (DSI_MODE_FLAG_DFPS | DSI_MODE_FLAG_VRR)) { rc = dsi_display_dfps_update(display, mode); if (rc) { pr_err("[%s]DSI dfps update failed, rc=%d\n", @@ -2150,6 +3338,17 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, goto error; } } + + if (priv_info->phy_timing_len) { + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + rc = dsi_phy_set_timing_params(ctrl->phy, + priv_info->phy_timing_val, + priv_info->phy_timing_len); + if (rc) + pr_err("failed to add DSI PHY timing params"); + } + } error: return rc; } @@ -2216,6 +3415,110 @@ static int _dsi_display_dev_deinit(struct dsi_display *display) return rc; } +/** + * dsi_display_splash_res_init() - Initialize resources for continuous splash + * @display: Pointer to dsi display + * Returns: Zero on success + */ +static int dsi_display_splash_res_init(struct dsi_display *display) +{ + int rc = 0; + + /* Vote for gdsc required to read register address space */ + + display->cont_splash_client = sde_power_client_create(display->phandle, + "cont_splash_client"); + rc = sde_power_resource_enable(display->phandle, + display->cont_splash_client, true); + if (rc) { + pr_err("failed to vote gdsc for continuous splash, rc=%d\n", + rc); + return -EINVAL; + } + + /* Verify whether continuous splash is enabled or not */ + display->is_cont_splash_enabled = + dsi_display_get_cont_splash_status(display); + if (!display->is_cont_splash_enabled) { + pr_err("Continuous splash is not enabled\n"); + goto splash_disabled; + } + + /* Update splash status for clock manager */ + dsi_display_clk_mngr_update_splash_status(display->clk_mngr, + display->is_cont_splash_enabled); + + /* Vote for Core clk and link clk. Votes on ctrl and phy + * regulator are inplicit from pre clk on callback + */ + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + pr_err("[%s] failed to enable DSI link clocks, rc=%d\n", + display->name, rc); + goto clk_manager_update; + } + + /* Vote on panel regulator will be removed during suspend path */ + rc = dsi_pwr_enable_regulator(&display->panel->power_info, true); + if (rc) { + pr_err("[%s] failed to enable vregs, rc=%d\n", + display->panel->name, rc); + goto clks_disabled; + } + + dsi_config_host_engine_state_for_cont_splash(display); + + return rc; + +clks_disabled: + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + +clk_manager_update: + /* Update splash status for clock manager */ + dsi_display_clk_mngr_update_splash_status(display->clk_mngr, + false); + +splash_disabled: + (void)sde_power_resource_enable(display->phandle, + display->cont_splash_client, false); + display->is_cont_splash_enabled = false; + return rc; +} + +/** + * dsi_display_splash_res_cleanup() - cleanup for continuous splash + * @display: Pointer to dsi display + * Returns: Zero on success + */ +int dsi_display_splash_res_cleanup(struct dsi_display *display) +{ + int rc = 0; + + if (!display->is_cont_splash_enabled) + return 0; + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) + pr_err("[%s] failed to disable DSI link clocks, rc=%d\n", + display->name, rc); + + rc = sde_power_resource_enable(display->phandle, + display->cont_splash_client, false); + if (rc) + pr_err("failed to remove vote on gdsc for continuous splash, rc=%d\n", + rc); + + display->is_cont_splash_enabled = false; + /* Update splash status for clock manager */ + dsi_display_clk_mngr_update_splash_status(display->clk_mngr, + display->is_cont_splash_enabled); + + return rc; +} + /** * dsi_display_bind - bind dsi device with controlling device * @dev: Pointer to base of platform device @@ -2273,6 +3576,7 @@ static int dsi_display_bind(struct device *dev, display->name, i, rc); goto error_ctrl_deinit; } + display_ctrl->ctrl->horiz_index = i; rc = dsi_phy_drv_init(display_ctrl->phy); if (rc) { @@ -2301,6 +3605,7 @@ static int dsi_display_bind(struct device *dev, } } + display->phandle = &priv->phandle; info.pre_clkoff_cb = dsi_pre_clkoff_cb; info.pre_clkon_cb = dsi_pre_clkon_cb; info.post_clkoff_cb = dsi_post_clkoff_cb; @@ -2375,18 +3680,31 @@ static int dsi_display_bind(struct device *dev, goto error_host_deinit; } - rc = dsi_panel_get_mode_count(display->panel, &display->num_of_modes); - if (rc) { - pr_err("[%s] failed to get mode count, rc=%d\n", - display->name, rc); - goto error_panel_deinit; + pr_info("Successfully bind display panel '%s'\n", display->name); + display->drm_dev = drm; + + for (i = 0; i < display->ctrl_count; i++) { + display_ctrl = &display->ctrl[i]; + + if (!display_ctrl->phy || !display_ctrl->ctrl) + continue; + + rc = dsi_phy_set_clk_freq(display_ctrl->phy, + &display_ctrl->ctrl->clk_freq); + if (rc) { + pr_err("[%s] failed to set phy clk freq, rc=%d\n", + display->name, rc); + goto error; + } } - display->drm_dev = drm; + /* Initialize resources for continuous splash */ + rc = dsi_display_splash_res_init(display); + if (rc) + pr_err("Continuous splash resource init failed, rc=%d\n", rc); + goto error; -error_panel_deinit: - (void)dsi_panel_drv_deinit(display->panel); error_host_deinit: (void)dsi_display_mipi_host_deinit(display); error_clk_client_deinit: @@ -2479,6 +3797,9 @@ int dsi_display_dev_probe(struct platform_device *pdev) { int rc = 0; struct dsi_display *display; + static bool display_from_cmdline, boot_displays_parsed; + static bool comp_add_success; + static struct device_node *primary_np, *secondary_np; if (!pdev || !pdev->dev.of_node) { pr_err("pdev not found\n"); @@ -2490,10 +3811,73 @@ int dsi_display_dev_probe(struct platform_device *pdev) return -ENOMEM; display->name = of_get_property(pdev->dev.of_node, "label", NULL); + if (!display->name) + display->name = "unknown"; + + if (!boot_displays_parsed) { + boot_displays[DSI_PRIMARY].boot_disp_en = false; + boot_displays[DSI_SECONDARY].boot_disp_en = false; + if (dsi_display_parse_boot_display_selection()) + pr_debug("Display Boot param not valid/available\n"); + + boot_displays_parsed = true; + } + + /* use default topology of every mode if not overridden */ + display->cmdline_topology = NO_OVERRIDE; + display->cmdline_timing = 0; + + if ((!display_from_cmdline) && + (boot_displays[DSI_PRIMARY].boot_disp_en)) { + display->is_active = dsi_display_name_compare(pdev->dev.of_node, + display->name, DSI_PRIMARY); + if (display->is_active) { + if (comp_add_success) { + (void)_dsi_display_dev_deinit(main_display); + component_del(&main_display->pdev->dev, + &dsi_display_comp_ops); + mutex_lock(&dsi_display_list_lock); + list_del(&main_display->list); + mutex_unlock(&dsi_display_list_lock); + comp_add_success = false; + default_active_node = NULL; + pr_debug("removed the existing comp ops\n"); + } + /* + * Need to add component for + * the secondary DSI display + * when more than one DSI display + * is supported. + */ + pr_debug("cmdline primary dsi: %s\n", + display->name); + display_from_cmdline = true; + dsi_display_parse_cmdline_topology(display, + DSI_PRIMARY); + primary_np = pdev->dev.of_node; + } + } - display->is_active = of_property_read_bool(pdev->dev.of_node, - "qcom,dsi-display-active"); - + if (boot_displays[DSI_SECONDARY].boot_disp_en) { + if (!secondary_np) { + if (dsi_display_name_compare(pdev->dev.of_node, + display->name, DSI_SECONDARY)) { + pr_debug("cmdline secondary dsi: %s\n", + display->name); + secondary_np = pdev->dev.of_node; + if (primary_np) { + if (validate_dsi_display_selection()) { + display->is_active = true; + dsi_display_parse_cmdline_topology + (display, DSI_SECONDARY); + } else { + boot_displays[DSI_SECONDARY] + .boot_disp_en = false; + } + } + } + } + } display->display_type = of_get_property(pdev->dev.of_node, "qcom,display-type", NULL); if (!display->display_type) @@ -2506,6 +3890,10 @@ int dsi_display_dev_probe(struct platform_device *pdev) list_add(&display->list, &dsi_display_list); mutex_unlock(&dsi_display_list_lock); + if (!display_from_cmdline) + display->is_active = of_property_read_bool(pdev->dev.of_node, + "qcom,dsi-display-active"); + if (display->is_active) { main_display = display; rc = _dsi_display_dev_init(display); @@ -2517,6 +3905,11 @@ int dsi_display_dev_probe(struct platform_device *pdev) rc = component_add(&pdev->dev, &dsi_display_comp_ops); if (rc) pr_err("component add failed, rc=%d\n", rc); + + comp_add_success = true; + pr_debug("Component_add success: %s\n", display->name); + if (!display_from_cmdline) + default_active_node = pdev->dev.of_node; } return rc; } @@ -2675,134 +4068,362 @@ int dsi_display_drm_bridge_deinit(struct dsi_display *display) int dsi_display_get_info(struct msm_display_info *info, void *disp) { - struct dsi_display *display; - struct dsi_panel_phy_props phy_props; - struct dsi_mode_info *timing; - int i, rc; + struct dsi_display *display; + struct dsi_panel_phy_props phy_props; + int i, rc; + + if (!info || !disp) { + pr_err("invalid params\n"); + return -EINVAL; + } + + display = disp; + if (!display->panel) { + pr_err("invalid display panel\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + rc = dsi_panel_get_phy_props(display->panel, &phy_props); + if (rc) { + pr_err("[%s] failed to get panel phy props, rc=%d\n", + display->name, rc); + goto error; + } + + memset(info, 0, sizeof(struct msm_display_info)); + info->intf_type = DRM_MODE_CONNECTOR_DSI; + info->num_of_h_tiles = display->ctrl_count; + for (i = 0; i < info->num_of_h_tiles; i++) + info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index; + + info->is_connected = true; + info->is_primary = true; + info->width_mm = phy_props.panel_width_mm; + info->height_mm = phy_props.panel_height_mm; + info->max_width = 1920; + info->max_height = 1080; + + switch (display->panel->panel_mode) { + case DSI_OP_VIDEO_MODE: + info->capabilities |= MSM_DISPLAY_CAP_VID_MODE; + break; + case DSI_OP_CMD_MODE: + info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE; + info->is_te_using_watchdog_timer = + display->panel->te_using_watchdog_timer; + break; + default: + pr_err("unknwown dsi panel mode %d\n", + display->panel->panel_mode); + break; + } + + if (display->panel->esd_config.esd_enabled) + info->capabilities |= MSM_DISPLAY_ESD_ENABLED; + +error: + mutex_unlock(&display->display_lock); + return rc; +} + +static int dsi_display_get_mode_count_no_lock(struct dsi_display *display, + u32 *count) +{ + struct dsi_dfps_capabilities dfps_caps; + int num_dfps_rates, rc = 0; + + if (!display || !display->panel) { + pr_err("invalid display:%d panel:%d\n", display != NULL, + display ? display->panel != NULL : 0); + return -EINVAL; + } + + *count = display->panel->num_timing_nodes; + + rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + if (rc) { + pr_err("[%s] failed to get dfps caps from panel\n", + display->name); + return rc; + } + + num_dfps_rates = !dfps_caps.dfps_support ? 1 : + dfps_caps.max_refresh_rate - + dfps_caps.min_refresh_rate + 1; + + /* Inflate num_of_modes by fps in dfps */ + *count = display->panel->num_timing_nodes * num_dfps_rates; + + return 0; +} + +int dsi_display_get_mode_count(struct dsi_display *display, + u32 *count) +{ + int rc; + + if (!display || !display->panel) { + pr_err("invalid display:%d panel:%d\n", display != NULL, + display ? display->panel != NULL : 0); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + rc = dsi_display_get_mode_count_no_lock(display, count); + mutex_unlock(&display->display_lock); + + return 0; +} + +void dsi_display_put_mode(struct dsi_display *display, + struct dsi_display_mode *mode) +{ + dsi_panel_put_mode(mode); +} + +int dsi_display_get_modes(struct dsi_display *display, + struct dsi_display_mode **out_modes) +{ + struct dsi_dfps_capabilities dfps_caps; + u32 num_dfps_rates, panel_mode_count, total_mode_count; + u32 mode_idx, array_idx = 0; + int i, rc = -EINVAL; + + if (!display || !out_modes) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + *out_modes = NULL; + + mutex_lock(&display->display_lock); + + rc = dsi_display_get_mode_count_no_lock(display, &total_mode_count); + if (rc) + goto error; + + /* free any previously probed modes */ + kfree(display->modes); + + display->modes = kcalloc(total_mode_count, sizeof(*display->modes), + GFP_KERNEL); + if (!display->modes) { + rc = -ENOMEM; + goto error; + } + + rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + if (rc) { + pr_err("[%s] failed to get dfps caps from panel\n", + display->name); + goto error; + } + + num_dfps_rates = !dfps_caps.dfps_support ? 1 : + dfps_caps.max_refresh_rate - + dfps_caps.min_refresh_rate + 1; + + panel_mode_count = display->panel->num_timing_nodes; + + for (mode_idx = 0; mode_idx < panel_mode_count; mode_idx++) { + struct dsi_display_mode panel_mode; + int topology_override = NO_OVERRIDE; + + if (display->cmdline_timing == mode_idx) + topology_override = display->cmdline_topology; + + memset(&panel_mode, 0, sizeof(panel_mode)); + + rc = dsi_panel_get_mode(display->panel, mode_idx, + &panel_mode, topology_override); + if (rc) { + pr_err("[%s] failed to get mode idx %d from panel\n", + display->name, mode_idx); + goto error; + } + + if (display->ctrl_count > 1) { /* TODO: remove if */ + panel_mode.timing.h_active *= display->ctrl_count; + panel_mode.timing.h_front_porch *= display->ctrl_count; + panel_mode.timing.h_sync_width *= display->ctrl_count; + panel_mode.timing.h_back_porch *= display->ctrl_count; + panel_mode.timing.h_skew *= display->ctrl_count; + panel_mode.pixel_clk_khz *= display->ctrl_count; + } + + for (i = 0; i < num_dfps_rates; i++) { + struct dsi_display_mode *sub_mode = + &display->modes[array_idx]; + u32 curr_refresh_rate; + + if (!sub_mode) { + pr_err("invalid mode data\n"); + rc = -EFAULT; + goto error; + } + + memcpy(sub_mode, &panel_mode, sizeof(panel_mode)); + + if (dfps_caps.dfps_support) { + curr_refresh_rate = + sub_mode->timing.refresh_rate; + sub_mode->timing.refresh_rate = + dfps_caps.min_refresh_rate + + (i % num_dfps_rates); + + dsi_display_get_dfps_timing(display, + sub_mode, curr_refresh_rate); + + sub_mode->pixel_clk_khz = + (DSI_H_TOTAL(&sub_mode->timing) * + DSI_V_TOTAL(&sub_mode->timing) * + sub_mode->timing.refresh_rate) / 1000; + } + array_idx++; + } + } + + *out_modes = display->modes; + rc = 0; + +error: + if (rc) + kfree(display->modes); + + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_find_mode(struct dsi_display *display, + const struct dsi_display_mode *cmp, + struct dsi_display_mode **out_mode) +{ + u32 count, i; + int rc; - if (!info || !disp) { - pr_err("invalid params\n"); + if (!display || !out_mode) return -EINVAL; - } - display = disp; - if (!display->panel) { - pr_err("invalid display panel\n"); - return -EINVAL; - } + *out_mode = NULL; + + rc = dsi_display_get_mode_count(display, &count); + if (rc) + return rc; mutex_lock(&display->display_lock); - rc = dsi_panel_get_phy_props(display->panel, &phy_props); - if (rc) { - pr_err("[%s] failed to get panel phy props, rc=%d\n", - display->name, rc); - goto error; + for (i = 0; i < count; i++) { + struct dsi_display_mode *m = &display->modes[i]; + + if (cmp->timing.v_active == m->timing.v_active && + cmp->timing.h_active == m->timing.h_active && + cmp->timing.refresh_rate == m->timing.refresh_rate) { + *out_mode = m; + rc = 0; + break; + } } + mutex_unlock(&display->display_lock); - info->intf_type = DRM_MODE_CONNECTOR_DSI; - timing = &display->panel->mode.timing; - - info->num_of_h_tiles = display->ctrl_count; - for (i = 0; i < info->num_of_h_tiles; i++) - info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index; - - info->is_connected = true; - info->is_primary = true; - info->frame_rate = timing->refresh_rate; - info->vtotal = DSI_V_TOTAL(timing); - info->prefill_lines = display->panel->panel_prefill_lines; - info->jitter = display->panel->panel_jitter; - info->width_mm = phy_props.panel_width_mm; - info->height_mm = phy_props.panel_height_mm; - info->max_width = 1920; - info->max_height = 1080; - info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; - - if (display->panel->dsc_enabled) { - info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; - memcpy(&info->comp_info.dsc_info, &display->panel->dsc, - sizeof(struct msm_display_dsc_info)); + if (!*out_mode) { + pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n", + display->name, cmp->timing.v_active, + cmp->timing.h_active, cmp->timing.refresh_rate); + rc = -ENOENT; } - switch (display->panel->mode.panel_mode) { - case DSI_OP_VIDEO_MODE: - info->capabilities |= MSM_DISPLAY_CAP_VID_MODE; - break; - case DSI_OP_CMD_MODE: - info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE; - break; - default: - pr_err("unknwown dsi panel mode %d\n", - display->panel->mode.panel_mode); - break; - } -error: - mutex_unlock(&display->display_lock); return rc; } -int dsi_display_get_modes(struct dsi_display *display, - struct dsi_display_mode *modes, - u32 *count) +/** + * dsi_display_validate_mode_vrr() - Validate if varaible refresh case. + * @display: DSI display handle. + * @cur_dsi_mode: Current DSI mode. + * @mode: Mode value structure to be validated. + * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there + * is change in fps but vactive and hactive are same. + * Return: error code. + */ +int dsi_display_validate_mode_vrr(struct dsi_display *display, + struct dsi_display_mode *cur_dsi_mode, + struct dsi_display_mode *mode) { int rc = 0; - int i; + struct dsi_display_mode adj_mode, cur_mode; struct dsi_dfps_capabilities dfps_caps; - int num_dfps_rates; + u32 curr_refresh_rate; - if (!display || !count) { + if (!display || !mode) { pr_err("Invalid params\n"); return -EINVAL; } - mutex_lock(&display->display_lock); - - rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); - if (rc) { - pr_err("[%s] failed to get dfps caps from panel\n", - display->name); - goto error; + if (!display->panel || !display->panel->cur_mode) { + pr_debug("Current panel mode not set\n"); + return rc; } - num_dfps_rates = !dfps_caps.dfps_support ? 1 : - dfps_caps.max_refresh_rate - - dfps_caps.min_refresh_rate + 1; + mutex_lock(&display->display_lock); - if (!modes) { - /* Inflate num_of_modes by fps in dfps */ - *count = display->num_of_modes * num_dfps_rates; - goto error; - } + adj_mode = *mode; + cur_mode = *cur_dsi_mode; - for (i = 0; i < *count; i++) { - /* Insert the dfps "sub-modes" between main panel modes */ - int panel_mode_idx = i / num_dfps_rates; + if ((cur_mode.timing.refresh_rate != adj_mode.timing.refresh_rate) && + (cur_mode.timing.v_active == adj_mode.timing.v_active) && + (cur_mode.timing.h_active == adj_mode.timing.h_active)) { - rc = dsi_panel_get_mode(display->panel, panel_mode_idx, modes); + curr_refresh_rate = cur_mode.timing.refresh_rate; + rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (rc) { - pr_err("[%s] failed to get mode from panel\n", - display->name); + pr_err("[%s] failed to get dfps caps from panel\n", + display->name); goto error; } - if (dfps_caps.dfps_support) { - modes->timing.refresh_rate = dfps_caps.min_refresh_rate - + (i % num_dfps_rates); - modes->pixel_clk_khz = (DSI_H_TOTAL(&modes->timing) * - DSI_V_TOTAL(&modes->timing) * - modes->timing.refresh_rate) / 1000; + cur_mode.timing.refresh_rate = + adj_mode.timing.refresh_rate; + + rc = dsi_display_get_dfps_timing(display, + &cur_mode, curr_refresh_rate); + if (rc) { + pr_err("[%s] seamless vrr not possible rc=%d\n", + display->name, rc); + goto error; } + switch (dfps_caps.type) { + /* + * Ignore any round off factors in porch calculation. + * Worse case is set to 5. + */ + case DSI_DFPS_IMMEDIATE_VFP: + if (abs(DSI_V_TOTAL(&cur_mode.timing) - + DSI_V_TOTAL(&adj_mode.timing)) > 5) + pr_err("Mismatch vfp fps:%d new:%d given:%d\n", + adj_mode.timing.refresh_rate, + cur_mode.timing.v_front_porch, + adj_mode.timing.v_front_porch); + break; - if (display->ctrl_count > 1) { /* TODO: remove if */ - modes->timing.h_active *= display->ctrl_count; - modes->timing.h_front_porch *= display->ctrl_count; - modes->timing.h_sync_width *= display->ctrl_count; - modes->timing.h_back_porch *= display->ctrl_count; - modes->timing.h_skew *= display->ctrl_count; - modes->pixel_clk_khz *= display->ctrl_count; + case DSI_DFPS_IMMEDIATE_HFP: + if (abs(DSI_H_TOTAL(&cur_mode.timing) - + DSI_H_TOTAL(&adj_mode.timing)) > 5) + pr_err("Mismatch hfp fps:%d new:%d given:%d\n", + adj_mode.timing.refresh_rate, + cur_mode.timing.h_front_porch, + adj_mode.timing.h_front_porch); + break; + + default: + pr_err("Unsupported DFPS mode %d\n", + dfps_caps.type); + rc = -ENOTSUPP; } - modes++; + pr_debug("Mode switch is seamless variable refresh\n"); + mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; + SDE_EVT32(curr_refresh_rate, adj_mode.timing.refresh_rate, + cur_mode.timing.h_front_porch, + adj_mode.timing.h_front_porch); } error: @@ -2868,83 +4489,394 @@ int dsi_display_validate_mode(struct dsi_display *display, return rc; } -int dsi_display_set_mode(struct dsi_display *display, - struct dsi_display_mode *mode, - u32 flags) +int dsi_display_set_mode(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags) +{ + int rc = 0; + struct dsi_display_mode adj_mode; + + if (!display || !mode || !display->panel) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + adj_mode = *mode; + adjust_timing_by_ctrl_count(display, &adj_mode); + + rc = dsi_display_validate_mode_set(display, &adj_mode, flags); + if (rc) { + pr_err("[%s] mode cannot be set\n", display->name); + goto error; + } + + rc = dsi_display_set_mode_sub(display, &adj_mode, flags); + if (rc) { + pr_err("[%s] failed to set mode\n", display->name); + goto error; + } + + if (!display->panel->cur_mode) { + display->panel->cur_mode = + kzalloc(sizeof(struct dsi_display_mode), GFP_KERNEL); + if (!display->panel->cur_mode) { + rc = -ENOMEM; + goto error; + } + } + + memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode)); +error: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_set_tpg_state(struct dsi_display *display, bool enable) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_set_tpg_state(ctrl->ctrl, enable); + if (rc) { + pr_err("[%s] failed to set tpg state for host_%d\n", + display->name, i); + goto error; + } + } + + display->is_tpg_enabled = enable; +error: + return rc; +} + +static int dsi_display_pre_switch(struct dsi_display *display) +{ + int rc = 0; + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto error; + } + + rc = dsi_display_ctrl_update(display); + if (rc) { + pr_err("[%s] failed to update DSI controller, rc=%d\n", + display->name, rc); + goto error_ctrl_clk_off; + } + + rc = dsi_display_set_clk_src(display); + if (rc) { + pr_err("[%s] failed to set DSI link clock source, rc=%d\n", + display->name, rc); + goto error_ctrl_deinit; + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_LINK_CLK, DSI_CLK_ON); + if (rc) { + pr_err("[%s] failed to enable DSI link clocks, rc=%d\n", + display->name, rc); + goto error_ctrl_deinit; + } + + goto error; + +error_ctrl_deinit: + (void)dsi_display_ctrl_deinit(display); +error_ctrl_clk_off: + (void)dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); +error: + return rc; +} + +static void dsi_display_handle_fifo_underflow(struct work_struct *work) +{ + struct dsi_display *display = NULL; + + display = container_of(work, struct dsi_display, fifo_underflow_work); + if (!display) + return; + pr_debug("handle DSI FIFO underflow error\n"); + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + dsi_display_soft_reset(display); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); +} + +static void dsi_display_handle_fifo_overflow(struct work_struct *work) +{ + struct dsi_display *display = NULL; + struct dsi_display_ctrl *ctrl; + int i, rc; + int mask = BIT(20); /* clock lane */ + int (*cb_func)(void *event_usr_ptr, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + void *data; + u32 version = 0; + + display = container_of(work, struct dsi_display, fifo_overflow_work); + if (!display || !display->panel || + (display->panel->panel_mode != DSI_OP_VIDEO_MODE)) + return; + + pr_debug("handle DSI FIFO overflow error\n"); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + /* + * below recovery sequence is not applicable to + * hw version 2.0.0, 2.1.0 and 2.2.0, so return early. + */ + ctrl = &display->ctrl[display->clk_master_idx]; + version = dsi_ctrl_get_hw_version(ctrl->ctrl); + if (!version || (version < 0x20020001)) + goto end; + + /* reset ctrl and lanes */ + for (i = 0 ; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_reset(ctrl->ctrl, mask); + rc = dsi_phy_lane_reset(ctrl->phy); + } + + /* wait for display line count to be in active area */ + ctrl = &display->ctrl[display->clk_master_idx]; + if (ctrl->ctrl->recovery_cb.event_cb) { + cb_func = ctrl->ctrl->recovery_cb.event_cb; + data = ctrl->ctrl->recovery_cb.event_usr_ptr; + rc = cb_func(data, SDE_CONN_EVENT_VID_FIFO_OVERFLOW, + display->clk_master_idx, 0, 0, 0, 0); + if (rc < 0) { + pr_debug("sde callback failed\n"); + goto end; + } + } + + /* Enable Video mode for DSI controller */ + for (i = 0 ; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + dsi_ctrl_vid_engine_en(ctrl->ctrl, true); + } + /* + * Add sufficient delay to make sure + * pixel transmission has started + */ + udelay(200); +end: + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); +} + +static void dsi_display_handle_lp_rx_timeout(struct work_struct *work) +{ + struct dsi_display *display = NULL; + struct dsi_display_ctrl *ctrl; + int i, rc; + int mask = (BIT(20) | (0xF << 16)); /* clock lane and 4 data lane */ + int (*cb_func)(void *event_usr_ptr, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + void *data; + u32 version = 0; + + display = container_of(work, struct dsi_display, lp_rx_timeout_work); + if (!display || !display->panel || + (display->panel->panel_mode != DSI_OP_VIDEO_MODE)) + return; + pr_debug("handle DSI LP RX Timeout error\n"); + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + /* + * below recovery sequence is not applicable to + * hw version 2.0.0, 2.1.0 and 2.2.0, so return early. + */ + ctrl = &display->ctrl[display->clk_master_idx]; + version = dsi_ctrl_get_hw_version(ctrl->ctrl); + if (!version || (version < 0x20020001)) + goto end; + + /* reset ctrl and lanes */ + for (i = 0 ; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_reset(ctrl->ctrl, mask); + rc = dsi_phy_lane_reset(ctrl->phy); + } + + ctrl = &display->ctrl[display->clk_master_idx]; + if (ctrl->ctrl->recovery_cb.event_cb) { + cb_func = ctrl->ctrl->recovery_cb.event_cb; + data = ctrl->ctrl->recovery_cb.event_usr_ptr; + rc = cb_func(data, SDE_CONN_EVENT_VID_FIFO_OVERFLOW, + display->clk_master_idx, 0, 0, 0, 0); + if (rc < 0) { + pr_debug("Target is in suspend/shutdown\n"); + goto end; + } + } + + /* Enable Video mode for DSI controller */ + for (i = 0 ; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + dsi_ctrl_vid_engine_en(ctrl->ctrl, true); + } + + /* + * Add sufficient delay to make sure + * pixel transmission as started + */ + udelay(200); +end: + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); +} + +static int dsi_display_cb_error_handler(void *data, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3) +{ + struct dsi_display *display = data; + + if (!display) + return -EINVAL; + + switch (event_idx) { + case DSI_FIFO_UNDERFLOW: + queue_work(display->err_workq, &display->fifo_underflow_work); + break; + case DSI_FIFO_OVERFLOW: + queue_work(display->err_workq, &display->fifo_overflow_work); + break; + case DSI_LP_Rx_TIMEOUT: + queue_work(display->err_workq, &display->lp_rx_timeout_work); + break; + default: + pr_warn("unhandled error interrupt: %d\n", event_idx); + break; + } + + return 0; +} + +static void dsi_display_register_error_handler(struct dsi_display *display) { - int rc = 0; - struct dsi_display_mode adj_mode; + int i = 0; + struct dsi_display_ctrl *ctrl; + struct dsi_event_cb_info event_info; - if (!display || !mode) { - pr_err("Invalid params\n"); - return -EINVAL; + if (!display) + return; + + display->err_workq = create_singlethread_workqueue("dsi_err_workq"); + if (!display->err_workq) { + pr_err("failed to create dsi workq!\n"); + return; } - mutex_lock(&display->display_lock); + INIT_WORK(&display->fifo_underflow_work, + dsi_display_handle_fifo_underflow); + INIT_WORK(&display->fifo_overflow_work, + dsi_display_handle_fifo_overflow); + INIT_WORK(&display->lp_rx_timeout_work, + dsi_display_handle_lp_rx_timeout); - adj_mode = *mode; - adjust_timing_by_ctrl_count(display, &adj_mode); + memset(&event_info, 0, sizeof(event_info)); - rc = dsi_display_validate_mode_set(display, &adj_mode, flags); - if (rc) { - pr_err("[%s] mode cannot be set\n", display->name); - goto error; - } + event_info.event_cb = dsi_display_cb_error_handler; + event_info.event_usr_ptr = display; - rc = dsi_display_set_mode_sub(display, &adj_mode, flags); - if (rc) { - pr_err("[%s] failed to set mode\n", display->name); - goto error; + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + ctrl->ctrl->irq_info.irq_err_cb = event_info; } -error: - mutex_unlock(&display->display_lock); - return rc; } -int dsi_display_set_tpg_state(struct dsi_display *display, bool enable) +static void dsi_display_unregister_error_handler(struct dsi_display *display) { - int rc = 0; - int i; + int i = 0; struct dsi_display_ctrl *ctrl; - if (!display) { - pr_err("Invalid params\n"); - return -EINVAL; - } + if (!display) + return; for (i = 0; i < display->ctrl_count; i++) { ctrl = &display->ctrl[i]; - rc = dsi_ctrl_set_tpg_state(ctrl->ctrl, enable); - if (rc) { - pr_err("[%s] failed to set tpg state for host_%d\n", - display->name, i); - goto error; - } + memset(&ctrl->ctrl->irq_info.irq_err_cb, + 0, sizeof(struct dsi_event_cb_info)); } - display->is_tpg_enabled = enable; -error: - return rc; + if (display->err_workq) + destroy_workqueue(display->err_workq); } int dsi_display_prepare(struct dsi_display *display) { int rc = 0; + struct dsi_display_mode *mode; if (!display) { pr_err("Invalid params\n"); return -EINVAL; } + if (!display->panel->cur_mode) { + pr_err("no valid mode set for the display"); + return -EINVAL; + } + mutex_lock(&display->display_lock); - rc = dsi_panel_pre_prepare(display->panel); - if (rc) { - pr_err("[%s] panel pre-prepare failed, rc=%d\n", - display->name, rc); + mode = display->panel->cur_mode; + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { + /* update dsi ctrl for new mode */ + rc = dsi_display_pre_switch(display); + if (rc) + pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n", + display->name, rc); + goto error; } + if (!display->is_cont_splash_enabled) { + /* + * For continuous splash usecase we skip panel + * pre prepare since the regulator vote is already + * taken care in splash resource init + */ + rc = dsi_panel_pre_prepare(display->panel); + if (rc) { + pr_err("[%s] panel pre-prepare failed, rc=%d\n", + display->name, rc); + goto error; + } + } + + /* Set up ctrl isr before enabling core clk */ + dsi_display_ctrl_isr_configure(display, true); + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_ON); if (rc) { @@ -2953,17 +4885,34 @@ int dsi_display_prepare(struct dsi_display *display) goto error_panel_post_unprep; } - rc = dsi_display_phy_sw_reset(display); - if (rc) { - pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc); - goto error_ctrl_clk_off; + /* + * If ULPS during suspend feature is enabled, then DSI PHY was + * left on during suspend. In this case, we do not need to reset/init + * PHY. This would have already been done when the CORE clocks are + * turned on. However, if cont splash is disabled, the first time DSI + * is powered on, phy init needs to be done unconditionally. + */ + if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) { + rc = dsi_display_phy_sw_reset(display); + if (rc) { + pr_err("[%s] failed to reset phy, rc=%d\n", + display->name, rc); + goto error_ctrl_clk_off; + } + + rc = dsi_display_phy_enable(display); + if (rc) { + pr_err("[%s] failed to enable DSI PHY, rc=%d\n", + display->name, rc); + goto error_ctrl_clk_off; + } } - rc = dsi_display_phy_enable(display); + rc = dsi_display_set_clk_src(display); if (rc) { - pr_err("[%s] failed to enable DSI PHY, rc=%d\n", - display->name, rc); - goto error_ctrl_clk_off; + pr_err("[%s] failed to set DSI link clock source, rc=%d\n", + display->name, rc); + goto error_phy_disable; } rc = dsi_display_ctrl_init(display); @@ -2972,51 +4921,50 @@ int dsi_display_prepare(struct dsi_display *display) display->name, rc); goto error_phy_disable; } + /* Set up DSI ERROR event callback */ + dsi_display_register_error_handler(display); - rc = dsi_display_phy_reset_config(display, true); + rc = dsi_display_ctrl_host_enable(display); if (rc) { - pr_err("[%s] failed to setup DSI controller, rc=%d\n", + pr_err("[%s] failed to enable DSI host, rc=%d\n", display->name, rc); goto error_ctrl_deinit; } - rc = dsi_display_set_clk_src(display); - if (rc) { - pr_err("[%s] failed to set DSI link clock source, rc=%d\n", - display->name, rc); - goto error_phy_reset_off; - } - rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_LINK_CLK, DSI_CLK_ON); if (rc) { pr_err("[%s] failed to enable DSI link clocks, rc=%d\n", display->name, rc); - goto error_phy_reset_off; + goto error_host_engine_off; } - rc = dsi_display_ctrl_host_enable(display); + rc = dsi_display_soft_reset(display); if (rc) { - pr_err("[%s] failed to enable DSI host, rc=%d\n", - display->name, rc); + pr_err("[%s] failed soft reset, rc=%d\n", display->name, rc); goto error_ctrl_link_off; } - rc = dsi_panel_prepare(display->panel); - if (rc) { - pr_err("[%s] panel prepare failed, rc=%d\n", display->name, rc); - goto error_host_engine_off; + if (!display->is_cont_splash_enabled) { + /* + * For continuous splash usecase we skip panel + * prepare since the pnael is already in + * active state and panel on commands are not needed + */ + rc = dsi_panel_prepare(display->panel); + if (rc) { + pr_err("[%s] panel prepare failed, rc=%d\n", + display->name, rc); + goto error_ctrl_link_off; + } } - goto error; -error_host_engine_off: - (void)dsi_display_ctrl_host_disable(display); error_ctrl_link_off: (void)dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_LINK_CLK, DSI_CLK_OFF); -error_phy_reset_off: - (void)dsi_display_phy_reset_config(display, false); +error_host_engine_off: + (void)dsi_display_ctrl_host_disable(display); error_ctrl_deinit: (void)dsi_display_ctrl_deinit(display); error_phy_disable: @@ -3031,32 +4979,226 @@ int dsi_display_prepare(struct dsi_display *display) return rc; } +static int dsi_display_calc_ctrl_roi(const struct dsi_display *display, + const struct dsi_display_ctrl *ctrl, + const struct msm_roi_list *req_rois, + struct dsi_rect *out_roi) +{ + const struct dsi_rect *bounds = &ctrl->ctrl->mode_bounds; + struct dsi_display_mode *cur_mode; + struct msm_roi_caps *roi_caps; + struct dsi_rect req_roi = { 0 }; + int rc = 0; + + cur_mode = display->panel->cur_mode; + if (!cur_mode) + return 0; + + roi_caps = &cur_mode->priv_info->roi_caps; + if (req_rois->num_rects > roi_caps->num_roi) { + pr_err("request for %d rois greater than max %d\n", + req_rois->num_rects, + roi_caps->num_roi); + rc = -EINVAL; + goto exit; + } + + /** + * if no rois, user wants to reset back to full resolution + * note: h_active is already divided by ctrl_count + */ + if (!req_rois->num_rects) { + *out_roi = *bounds; + goto exit; + } + + /* intersect with the bounds */ + req_roi.x = req_rois->roi[0].x1; + req_roi.y = req_rois->roi[0].y1; + req_roi.w = req_rois->roi[0].x2 - req_rois->roi[0].x1; + req_roi.h = req_rois->roi[0].y2 - req_rois->roi[0].y1; + dsi_rect_intersect(&req_roi, bounds, out_roi); + +exit: + /* adjust the ctrl origin to be top left within the ctrl */ + out_roi->x = out_roi->x - bounds->x; + + pr_debug("ctrl%d:%d: req (%d,%d,%d,%d) bnd (%d,%d,%d,%d) out (%d,%d,%d,%d)\n", + ctrl->dsi_ctrl_idx, ctrl->ctrl->cell_index, + req_roi.x, req_roi.y, req_roi.w, req_roi.h, + bounds->x, bounds->y, bounds->w, bounds->h, + out_roi->x, out_roi->y, out_roi->w, out_roi->h); + + return rc; +} + +static int dsi_display_set_roi(struct dsi_display *display, + struct msm_roi_list *rois) +{ + struct dsi_display_mode *cur_mode; + struct msm_roi_caps *roi_caps; + int rc = 0; + int i; + + if (!display || !rois || !display->panel) + return -EINVAL; + + cur_mode = display->panel->cur_mode; + if (!cur_mode) + return 0; + + roi_caps = &cur_mode->priv_info->roi_caps; + if (!roi_caps->enabled) + return 0; + + for (i = 0; i < display->ctrl_count; i++) { + struct dsi_display_ctrl *ctrl = &display->ctrl[i]; + struct dsi_rect ctrl_roi; + bool changed = false; + + rc = dsi_display_calc_ctrl_roi(display, ctrl, rois, &ctrl_roi); + if (rc) { + pr_err("dsi_display_calc_ctrl_roi failed rc %d\n", rc); + return rc; + } + + rc = dsi_ctrl_set_roi(ctrl->ctrl, &ctrl_roi, &changed); + if (rc) { + pr_err("dsi_ctrl_set_roi failed rc %d\n", rc); + return rc; + } + + if (!changed) + continue; + + /* send the new roi to the panel via dcs commands */ + rc = dsi_panel_send_roi_dcs(display->panel, i, &ctrl_roi); + if (rc) { + pr_err("dsi_panel_set_roi failed rc %d\n", rc); + return rc; + } + + /* re-program the ctrl with the timing based on the new roi */ + rc = dsi_ctrl_setup(ctrl->ctrl); + if (rc) { + pr_err("dsi_ctrl_setup failed rc %d\n", rc); + return rc; + } + } + + return rc; +} + int dsi_display_pre_kickoff(struct dsi_display *display, struct msm_display_kickoff_params *params) { - return 0; + int rc = 0; + + /* check and setup MISR */ + if (display->misr_enable) + _dsi_display_setup_misr(display); + + rc = dsi_display_set_roi(display, params->rois); + + return rc; +} + +int dsi_display_config_ctrl_for_cont_splash(struct dsi_display *display) +{ + int rc = 0; + + if (!display || !display->panel) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + if (!display->panel->cur_mode) { + pr_err("no valid mode set for the display"); + return -EINVAL; + } + + if (!display->is_cont_splash_enabled) + return 0; + + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { + rc = dsi_display_vid_engine_enable(display); + if (rc) { + pr_err("[%s]failed to enable DSI video engine, rc=%d\n", + display->name, rc); + goto error_out; + } + } else if (display->config.panel_mode == DSI_OP_CMD_MODE) { + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n", + display->name, rc); + goto error_out; + } + } else { + pr_err("[%s] Invalid configuration\n", display->name); + rc = -EINVAL; + } + +error_out: + return rc; } int dsi_display_enable(struct dsi_display *display) { int rc = 0; + struct dsi_display_mode *mode; - if (!display) { + if (!display || !display->panel) { pr_err("Invalid params\n"); return -EINVAL; } + if (!display->panel->cur_mode) { + pr_err("no valid mode set for the display"); + return -EINVAL; + } + + /* Engine states and panel states are populated during splash + * resource init and hence we return early + */ + if (display->is_cont_splash_enabled) { + + dsi_display_config_ctrl_for_cont_splash(display); + + rc = dsi_display_splash_res_cleanup(display); + if (rc) { + pr_err("Continuous splash res cleanup failed, rc=%d\n", + rc); + return -EINVAL; + } + + display->panel->panel_initialized = true; + pr_debug("cont splash enabled, display enable not required\n"); + return 0; + } + mutex_lock(&display->display_lock); - rc = dsi_panel_enable(display->panel); - if (rc) { - pr_err("[%s] failed to enable DSI panel, rc=%d\n", - display->name, rc); - goto error; + mode = display->panel->cur_mode; + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { + rc = dsi_panel_post_switch(display->panel); + if (rc) { + pr_err("[%s] failed to switch DSI panel mode, rc=%d\n", + display->name, rc); + goto error; + } + } else { + rc = dsi_panel_enable(display->panel); + if (rc) { + pr_err("[%s] failed to enable DSI panel, rc=%d\n", + display->name, rc); + goto error; + } } - if (display->panel->dsc_enabled) { - display->panel->dsc.pic_width *= display->ctrl_count; + if (mode->priv_info->dsc_enabled) { + mode->priv_info->dsc.pic_width *= display->ctrl_count; rc = dsi_panel_update_pps(display->panel); if (rc) { pr_err("[%s] panel pps cmd update failed, rc=%d\n", @@ -3065,6 +5207,15 @@ int dsi_display_enable(struct dsi_display *display) } } + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { + rc = dsi_panel_switch(display->panel); + if (rc) + pr_err("[%s] failed to switch DSI panel mode, rc=%d\n", + display->name, rc); + + goto error; + } + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { rc = dsi_display_vid_engine_enable(display); if (rc) { @@ -3110,6 +5261,11 @@ int dsi_display_post_enable(struct dsi_display *display) pr_err("[%s] panel post-enable failed, rc=%d\n", display->name, rc); + /* remove the clk vote for CMD mode panels */ + if (display->config.panel_mode == DSI_OP_CMD_MODE) + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + mutex_unlock(&display->display_lock); return rc; } @@ -3125,6 +5281,11 @@ int dsi_display_pre_disable(struct dsi_display *display) mutex_lock(&display->display_lock); + /* enable the clk vote for CMD mode panels */ + if (display->config.panel_mode == DSI_OP_CMD_MODE) + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + rc = dsi_panel_pre_disable(display->panel); if (rc) pr_err("[%s] panel pre-disable failed, rc=%d\n", @@ -3223,20 +5384,20 @@ int dsi_display_unprepare(struct dsi_display *display) pr_err("[%s] failed to disable Link clocks, rc=%d\n", display->name, rc); + /* Free up DSI ERROR event callback */ + dsi_display_unregister_error_handler(display); + rc = dsi_display_ctrl_deinit(display); if (rc) pr_err("[%s] failed to deinit controller, rc=%d\n", display->name, rc); - rc = dsi_display_phy_disable(display); - if (rc) - pr_err("[%s] failed to disable DSI PHY, rc=%d\n", - display->name, rc); - - rc = dsi_display_phy_reset_config(display, false); - if (rc) - pr_err("[%s] failed to disable DSI PHY reset config, rc=%d\n", - display->name, rc); + if (!display->panel->ulps_suspend_enabled) { + rc = dsi_display_phy_disable(display); + if (rc) + pr_err("[%s] failed to disable DSI PHY, rc=%d\n", + display->name, rc); + } rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); @@ -3244,6 +5405,9 @@ int dsi_display_unprepare(struct dsi_display *display) pr_err("[%s] failed to disable DSI clocks, rc=%d\n", display->name, rc); + /* destrory dsi isr set up */ + dsi_display_ctrl_isr_configure(display, false); + rc = dsi_panel_post_unprepare(display->panel); if (rc) pr_err("[%s] panel post-unprepare failed, rc=%d\n", @@ -3266,6 +5430,13 @@ static void __exit dsi_display_unregister(void) dsi_ctrl_drv_unregister(); dsi_phy_drv_unregister(); } - +module_param_string(dsi_display0, dsi_display_primary, MAX_CMDLINE_PARAM_LEN, + 0600); +MODULE_PARM_DESC(dsi_display0, + "msm_drm.dsi_display0=: where is 'primary dsi display node name' and where x represents index in the topology list"); +module_param_string(dsi_display1, dsi_display_secondary, MAX_CMDLINE_PARAM_LEN, + 0600); +MODULE_PARM_DESC(dsi_display1, + "msm_drm.dsi_display1=: where is 'secondary dsi display node name' and where x represents index in the topology list"); module_init(dsi_display_register); module_exit(dsi_display_unregister); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index d2bc7d8daafacb0c9a8e0f12313efcc7f9f9b81a..4cfd4a9ef787247939d2bad241e2624107770a8c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2017, 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 @@ -30,12 +30,26 @@ #define MAX_DSI_CTRLS_PER_DISPLAY 2 #define DSI_CLIENT_NAME_SIZE 20 +#define MAX_CMDLINE_PARAM_LEN 512 +#define MAX_CMD_PAYLOAD_SIZE 256 /* * DSI Validate Mode modifiers * @DSI_VALIDATE_FLAG_ALLOW_ADJUST: Allow mode validation to also do fixup */ #define DSI_VALIDATE_FLAG_ALLOW_ADJUST 0x1 +/** + * enum dsi_display_selection_type - enumerates DSI display selection types + * @DSI_PRIMARY: primary DSI display selected from module parameter + * @DSI_SECONDARY: Secondary DSI display selected from module parameter + * @MAX_DSI_ACTIVE_DISPLAY: Maximum acive displays that can be selected + */ +enum dsi_display_selection_type { + DSI_PRIMARY = 0, + DSI_SECONDARY, + MAX_DSI_ACTIVE_DISPLAY, +}; + /** * enum dsi_display_type - enumerates DSI display types * @DSI_DISPLAY_SINGLE: A panel connected on a single DSI interface. @@ -78,6 +92,22 @@ struct dsi_display_ctrl { bool phy_enabled; }; +/** + * struct dsi_display_boot_param - defines DSI boot display selection + * @name:Name of DSI display selected as a boot param. + * @boot_disp_en:bool to indicate dtsi availability of display node + * @is_primary:bool to indicate whether current display is primary display + * @length:length of DSI display. + * @cmdline_topology: Display topology shared from kernel command line. + */ +struct dsi_display_boot_param { + char name[MAX_CMDLINE_PARAM_LEN]; + bool boot_disp_en; + bool is_primary; + int length; + struct device_node *node; + int cmdline_topology; +}; /** * struct dsi_display_clk_info - dsi display clock source information @@ -95,15 +125,18 @@ struct dsi_display_clk_info { * struct dsi_display - dsi display information * @pdev: Pointer to platform device. * @drm_dev: DRM device associated with the display. + * @drm_conn: Pointer to DRM connector associated with the display * @name: Name of the display. * @display_type: Display type as defined in device tree. * @list: List pointer. * @is_active: Is display active. + * @is_cont_splash_enabled: Is continuous splash enabled * @display_lock: Mutex for dsi_display interface. * @ctrl_count: Number of DSI interfaces required by panel. * @ctrl: Controller information for DSI display. * @panel: Handle to DSI panel. * @panel_of: pHandle to DSI panel. + * @modes: Array of probed DSI modes * @type: DSI display type. * @clk_master_idx: The master controller for controlling clocks. This is an * index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array. @@ -112,7 +145,8 @@ struct dsi_display_clk_info { * @clock_info: Clock sourcing for DSI display. * @config: DSI host configuration information. * @lane_map: Lane mapping between DSI host and Panel. - * @num_of_modes: Number of modes supported by display. + * @cmdline_topology: Display topology shared from kernel command line. + * @cmdline_timing: Display timing shared from kernel command line. * @is_tpg_enabled: TPG state. * @ulps_enabled: ulps state. * @clamp_enabled: clamp state. @@ -124,15 +158,19 @@ struct dsi_display_clk_info { * @dsi_clk_handle: DSI clock handle. * @mdp_clk_handle: MDP clock handle. * @root: Debugfs root directory + * @misr_enable Frame MISR enable/disable + * @misr_frame_count Number of frames to accumulate the MISR value */ struct dsi_display { struct platform_device *pdev; struct drm_device *drm_dev; + struct drm_connector *drm_conn; const char *name; const char *display_type; struct list_head list; bool is_active; + bool is_cont_splash_enabled; struct mutex display_lock; u32 ctrl_count; @@ -142,6 +180,8 @@ struct dsi_display { struct dsi_panel *panel; struct device_node *panel_of; + struct dsi_display_mode *modes; + enum dsi_display_type type; u32 clk_master_idx; u32 cmd_master_idx; @@ -150,22 +190,39 @@ struct dsi_display { struct dsi_display_clk_info clock_info; struct dsi_host_config config; struct dsi_lane_map lane_map; - u32 num_of_modes; + int cmdline_topology; + int cmdline_timing; bool is_tpg_enabled; bool ulps_enabled; bool clamp_enabled; bool phy_idle_power_off; + struct drm_gem_object *tx_cmd_buf; + u32 cmd_buffer_size; + u32 cmd_buffer_iova; + void *vaddr; + struct msm_gem_address_space *aspace; struct mipi_dsi_host host; struct dsi_bridge *bridge; u32 cmd_engine_refcount; + struct sde_power_handle *phandle; + struct sde_power_client *cont_splash_client; + void *clk_mngr; void *dsi_clk_handle; void *mdp_clk_handle; /* DEBUG FS */ struct dentry *root; + + bool misr_enable; + u32 misr_frame_count; + /* multiple dsi error handlers */ + struct workqueue_struct *err_workq; + struct work_struct fifo_underflow_work; + struct work_struct fifo_overflow_work; + struct work_struct lp_rx_timeout_work; }; int dsi_display_dev_probe(struct platform_device *pdev); @@ -188,9 +245,17 @@ int dsi_display_get_num_of_displays(void); int dsi_display_get_active_displays(void **display_array, u32 max_display_count); +/** + * dsi_display_get_boot_display()- get DSI boot display name + * @index: index of display selection + * + * Return: returns the display node pointer + */ +struct device_node *dsi_display_get_boot_display(int index); + /** * dsi_display_get_display_by_name()- finds display by name - * @index: name of the display. + * @name: name of the display. * * Return: handle to the display or error code. */ @@ -231,23 +296,47 @@ int dsi_display_drm_bridge_deinit(struct dsi_display *display); */ int dsi_display_get_info(struct msm_display_info *info, void *disp); +/** + * dsi_display_get_mode_count() - get number of modes supported by the display + * @display: Handle to display. + * @count: Number of modes supported + * + * Return: error code. + */ +int dsi_display_get_mode_count(struct dsi_display *display, u32 *count); + /** * dsi_display_get_modes() - get modes supported by display * @display: Handle to display. - * @modes; Pointer to array of modes. Memory allocated should be - * big enough to store (count * struct dsi_display_mode) - * elements. If modes pointer is NULL, number of modes will - * be stored in the memory pointed to by count. - * @count: If modes is NULL, number of modes will be stored. If - * not, mode information will be copied (number of modes - * copied will be equal to *count). + * @modes; Output param, list of DSI modes. Number of modes matches + * count returned by dsi_display_get_mode_count * * Return: error code. */ int dsi_display_get_modes(struct dsi_display *display, - struct dsi_display_mode *modes, - u32 *count); + struct dsi_display_mode **modes); + +/** + * dsi_display_put_mode() - free up mode created for the display + * @display: Handle to display. + * @mode: Display mode to be freed up + * + * Return: error code. + */ +void dsi_display_put_mode(struct dsi_display *display, + struct dsi_display_mode *mode); +/** + * dsi_display_find_mode() - retrieve cached DSI mode given relevant params + * @display: Handle to display. + * @cmp: Mode to use as comparison to find original + * @out_mode: Output parameter, pointer to retrieved mode + * + * Return: error code. + */ +int dsi_display_find_mode(struct dsi_display *display, + const struct dsi_display_mode *cmp, + struct dsi_display_mode **out_mode); /** * dsi_display_validate_mode() - validates if mode is supported by display * @display: Handle to display. @@ -260,6 +349,17 @@ int dsi_display_validate_mode(struct dsi_display *display, struct dsi_display_mode *mode, u32 flags); +/** + * dsi_display_validate_mode_vrr() - validates mode if variable refresh case + * @display: Handle to display. + * @mode: Mode to be validated.. + * + * Return: 0 if error code. + */ +int dsi_display_validate_mode_vrr(struct dsi_display *display, + struct dsi_display_mode *cur_dsi_mode, + struct dsi_display_mode *mode); + /** * dsi_display_set_mode() - Set mode on the display. * @display: Handle to display. @@ -284,6 +384,22 @@ int dsi_display_set_mode(struct dsi_display *display, */ int dsi_display_prepare(struct dsi_display *display); +/** + * dsi_display_splash_res_cleanup() - cleanup for continuous splash + * @display: Pointer to dsi display + * Returns: Zero on success + */ +int dsi_display_splash_res_cleanup(struct dsi_display *display); + +/** + * dsi_display_config_ctrl_for_cont_splash()- Enable engine modes for DSI + * controller during continuous splash + * @display: Handle to DSI display + * + * Return: returns error code + */ +int dsi_display_config_ctrl_for_cont_splash(struct dsi_display *display); + /** * dsi_display_enable() - enable display * @display: Handle to display. @@ -401,8 +517,34 @@ int dsi_display_set_tpg_state(struct dsi_display *display, bool enable); int dsi_display_clock_gate(struct dsi_display *display, bool enable); int dsi_dispaly_static_frame(struct dsi_display *display, bool enable); +/** + * dsi_display_enable_event() - enable interrupt based connector event + * @display: Handle to display. + * @event_idx: Event index. + * @event_info: Event callback definition. + * @enable: Whether to enable/disable the event interrupt. + */ +void dsi_display_enable_event(struct dsi_display *display, + uint32_t event_idx, struct dsi_event_cb_info *event_info, + bool enable); + int dsi_display_set_backlight(void *display, u32 bl_lvl); +/** + * dsi_display_check_status() - check if panel is dead or alive + * @display: Handle to display. + */ +int dsi_display_check_status(void *display); + +/** + * dsi_display_cmd_transfer() - transfer command to the panel + * @display: Handle to display. + * @cmd_buf: Command buffer + * @cmd_buf_len: Command buffer length in bytes + */ +int dsi_display_cmd_transfer(void *display, const char *cmd_buffer, + u32 cmd_buf_len); + /** * dsi_display_soft_reset() - perform a soft reset on DSI controller * @display: Handle to display @@ -418,6 +560,22 @@ int dsi_display_set_backlight(void *display, u32 bl_lvl); */ int dsi_display_soft_reset(void *display); +/** + * dsi_display_set_power - update power/dpms setting + * @connector: Pointer to drm connector structure + * @power_mode: One of the following, + * SDE_MODE_DPMS_ON + * SDE_MODE_DPMS_LP1 + * SDE_MODE_DPMS_LP2 + * SDE_MODE_DPMS_STANDBY + * SDE_MODE_DPMS_SUSPEND + * SDE_MODE_DPMS_OFF + * @display: Pointer to private display structure + * Returns: Zero on success + */ +int dsi_display_set_power(struct drm_connector *connector, + int power_mode, void *display); + /* * dsi_display_pre_kickoff - program kickoff-time features * @display: Pointer to private display structure @@ -426,5 +584,12 @@ int dsi_display_soft_reset(void *display); */ int dsi_display_pre_kickoff(struct dsi_display *display, struct msm_display_kickoff_params *params); +/** + * dsi_display_get_dst_format() - get dst_format from DSI display + * @display: Handle to display + * + * Return: enum dsi_pixel_format type + */ +enum dsi_pixel_format dsi_display_get_dst_format(void *display); #endif /* _DSI_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c index 93fb041399e26a82061fbba7f7873a5aafb93116..1cec9e1c2a36f1eb71ca66bd1679be17aa3d8520 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 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 @@ -28,26 +28,18 @@ static void dsi_display_test_work(struct work_struct *work) struct dsi_display *display; struct dsi_display_mode *modes; u32 count = 0; - u32 size = 0; int rc = 0; test = container_of(work, struct dsi_display_test, test_work); display = test->display; - rc = dsi_display_get_modes(display, NULL, &count); + rc = dsi_display_get_mode_count(display, &count); if (rc) { pr_err("failed to get modes count, rc=%d\n", rc); goto test_fail; } - size = count * sizeof(*modes); - modes = kzalloc(size, GFP_KERNEL); - if (!modes) { - rc = -ENOMEM; - goto test_fail; - } - - rc = dsi_display_get_modes(display, modes, &count); + rc = dsi_display_get_modes(display, &modes); if (rc) { pr_err("failed to get modes, rc=%d\n", rc); goto test_fail_free_modes; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c index 556c0d8b7b337446c5eddc1c60b1648d1ccd31f6..a1e468563fa8f3a740ff80c4d1239f11bf5f02e9 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c @@ -20,6 +20,7 @@ #include "msm_kms.h" #include "sde_connector.h" #include "dsi_drm.h" +#include "sde_trace.h" #define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) #define to_dsi_state(x) container_of((x), struct dsi_connector_state, base) @@ -48,7 +49,9 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, dsi_mode->timing.refresh_rate = drm_mode->vrefresh; dsi_mode->pixel_clk_khz = drm_mode->clock; - dsi_mode->panel_mode = 0; /* TODO: Panel Mode */ + + dsi_mode->priv_info = + (struct dsi_display_mode_priv_info *)drm_mode->private; if (msm_is_mode_seamless(drm_mode)) dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS; @@ -56,9 +59,13 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS; if (msm_needs_vblank_pre_modeset(drm_mode)) dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET; + if (msm_is_mode_seamless_dms(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS; + if (msm_is_mode_seamless_vrr(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; } -static void convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, +void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, struct drm_display_mode *drm_mode) { memset(drm_mode, 0, sizeof(*drm_mode)); @@ -81,12 +88,18 @@ static void convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, drm_mode->vrefresh = dsi_mode->timing.refresh_rate; drm_mode->clock = dsi_mode->pixel_clk_khz; + drm_mode->private = (int *)dsi_mode->priv_info; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) drm_mode->flags |= DRM_MODE_FLAG_SEAMLESS; if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS; if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VBLANK_PRE_MODESET) drm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR; drm_mode_set_name(drm_mode); } @@ -116,6 +129,9 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge) return; } + if (!c_bridge || !c_bridge->display) + pr_err("Incorrect bridge details\n"); + /* By this point mode should have been validated through mode_fixup */ rc = dsi_display_set_mode(c_bridge->display, &(c_bridge->dsi_mode), 0x0); @@ -125,24 +141,35 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge) return; } - if (c_bridge->dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) { + if (c_bridge->dsi_mode.dsi_mode_flags & + (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) { pr_debug("[%d] seamless pre-enable\n", c_bridge->id); return; } + SDE_ATRACE_BEGIN("dsi_bridge_pre_enable"); rc = dsi_display_prepare(c_bridge->display); if (rc) { pr_err("[%d] DSI display prepare failed, rc=%d\n", c_bridge->id, rc); + SDE_ATRACE_END("dsi_bridge_pre_enable"); return; } + SDE_ATRACE_BEGIN("dsi_display_enable"); rc = dsi_display_enable(c_bridge->display); if (rc) { pr_err("[%d] DSI display enable failed, rc=%d\n", - c_bridge->id, rc); + c_bridge->id, rc); (void)dsi_display_unprepare(c_bridge->display); } + SDE_ATRACE_END("dsi_display_enable"); + SDE_ATRACE_END("dsi_bridge_pre_enable"); + + rc = dsi_display_splash_res_cleanup(c_bridge->display); + if (rc) + pr_err("Continuous splash pipeline cleanup failed, rc=%d\n", + rc); } static void dsi_bridge_enable(struct drm_bridge *bridge) @@ -155,7 +182,8 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) return; } - if (c_bridge->dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) { + if (c_bridge->dsi_mode.dsi_mode_flags & + (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) { pr_debug("[%d] seamless enable\n", c_bridge->id); return; } @@ -169,12 +197,17 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) static void dsi_bridge_disable(struct drm_bridge *bridge) { int rc = 0; + struct dsi_display *display; struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); if (!bridge) { pr_err("Invalid params\n"); return; } + display = c_bridge->display; + + if (display && display->drm_conn) + sde_connector_helper_bridge_disable(display->drm_conn); rc = dsi_display_pre_disable(c_bridge->display); if (rc) { @@ -193,19 +226,25 @@ static void dsi_bridge_post_disable(struct drm_bridge *bridge) return; } + SDE_ATRACE_BEGIN("dsi_bridge_post_disable"); + SDE_ATRACE_BEGIN("dsi_display_disable"); rc = dsi_display_disable(c_bridge->display); if (rc) { pr_err("[%d] DSI display disable failed, rc=%d\n", c_bridge->id, rc); + SDE_ATRACE_END("dsi_display_disable"); return; } + SDE_ATRACE_END("dsi_display_disable"); rc = dsi_display_unprepare(c_bridge->display); if (rc) { pr_err("[%d] DSI display unprepare failed, rc=%d\n", c_bridge->id, rc); + SDE_ATRACE_END("dsi_bridge_post_disable"); return; } + SDE_ATRACE_END("dsi_bridge_post_disable"); } static void dsi_bridge_mode_set(struct drm_bridge *bridge, @@ -221,10 +260,6 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode)); convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode)); - - pr_debug("note: using panel cmd/vid mode instead of user val\n"); - c_bridge->dsi_mode.panel_mode = - c_bridge->display->panel->mode.panel_mode; } static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, @@ -232,27 +267,114 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, struct drm_display_mode *adjusted_mode) { int rc = 0; - bool ret = true; struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); - struct dsi_display_mode dsi_mode; + struct dsi_display *display; + struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode; + struct drm_display_mode cur_mode; + struct drm_crtc_state *crtc_state; + + crtc_state = container_of(mode, struct drm_crtc_state, mode); if (!bridge || !mode || !adjusted_mode) { pr_err("Invalid params\n"); return false; } + display = c_bridge->display; + if (!display) { + pr_err("Invalid params\n"); + return false; + } + convert_to_dsi_mode(mode, &dsi_mode); + /* + * retrieve dsi mode from dsi driver's cache since not safe to take + * the drm mode config mutex in all paths + */ + rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode); + if (rc) + return rc; + + /* propagate the private info to the adjusted_mode derived dsi mode */ + dsi_mode.priv_info = panel_dsi_mode->priv_info; + dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags; + rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode, DSI_VALIDATE_FLAG_ALLOW_ADJUST); if (rc) { pr_err("[%d] mode is not valid, rc=%d\n", c_bridge->id, rc); - ret = false; - } else { - convert_to_drm_mode(&dsi_mode, adjusted_mode); + return false; } - return ret; + if (bridge->encoder && bridge->encoder->crtc && + crtc_state->crtc) { + + convert_to_dsi_mode(&crtc_state->crtc->state->mode, + &cur_dsi_mode); + rc = dsi_display_validate_mode_vrr(c_bridge->display, + &cur_dsi_mode, &dsi_mode); + if (rc) + pr_debug("[%s] vrr mode mismatch failure rc=%d\n", + c_bridge->display->name, rc); + + cur_mode = crtc_state->crtc->mode; + + /* No DMS/VRR when drm pipeline is changing */ + if (!drm_mode_equal(&cur_mode, adjusted_mode) && + (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) && + (!crtc_state->active_changed || + display->is_cont_splash_enabled)) + dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS; + } + + /* convert back to drm mode, propagating the private info & flags */ + dsi_convert_to_drm_mode(&dsi_mode, adjusted_mode); + + return true; +} + +int dsi_conn_get_mode_info(const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + u32 max_mixer_width, void *display) +{ + struct dsi_display_mode dsi_mode; + struct dsi_mode_info *timing; + + if (!drm_mode || !mode_info) + return -EINVAL; + + convert_to_dsi_mode(drm_mode, &dsi_mode); + + if (!dsi_mode.priv_info) + return -EINVAL; + + memset(mode_info, 0, sizeof(*mode_info)); + + timing = &dsi_mode.timing; + mode_info->frame_rate = dsi_mode.timing.refresh_rate; + mode_info->vtotal = DSI_V_TOTAL(timing); + mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines; + mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer; + mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom; + mode_info->clk_rate = dsi_mode.priv_info->clk_rate_hz; + + memcpy(&mode_info->topology, &dsi_mode.priv_info->topology, + sizeof(struct msm_display_topology)); + + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; + if (dsi_mode.priv_info->dsc_enabled) { + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; + memcpy(&mode_info->comp_info.dsc_info, &dsi_mode.priv_info->dsc, + sizeof(dsi_mode.priv_info->dsc)); + } + + if (dsi_mode.priv_info->roi_caps.enabled) { + memcpy(&mode_info->roi_caps, &dsi_mode.priv_info->roi_caps, + sizeof(dsi_mode.priv_info->roi_caps)); + } + + return 0; } static const struct drm_bridge_funcs dsi_bridge_ops = { @@ -265,9 +387,8 @@ static const struct drm_bridge_funcs dsi_bridge_ops = { .mode_set = dsi_bridge_mode_set, }; -int dsi_conn_post_init(struct drm_connector *connector, - void *info, - void *display) +int dsi_conn_set_info_blob(struct drm_connector *connector, + void *info, void *display, struct msm_mode_info *mode_info) { struct dsi_display *dsi_display = display; struct dsi_panel *panel; @@ -275,6 +396,8 @@ int dsi_conn_post_init(struct drm_connector *connector, if (!info || !dsi_display) return -EINVAL; + dsi_display->drm_conn = connector; + sde_kms_info_add_keystr(info, "display type", dsi_display->display_type); @@ -307,7 +430,7 @@ int dsi_conn_post_init(struct drm_connector *connector, panel = dsi_display->panel; sde_kms_info_add_keystr(info, "panel name", panel->name); - switch (panel->mode.panel_mode) { + switch (panel->panel_mode) { case DSI_OP_VIDEO_MODE: sde_kms_info_add_keystr(info, "panel mode", "video"); break; @@ -317,12 +440,19 @@ int dsi_conn_post_init(struct drm_connector *connector, panel->cmd_config.mdp_transfer_time_us); break; default: - pr_debug("invalid panel type:%d\n", panel->mode.panel_mode); + pr_debug("invalid panel type:%d\n", panel->panel_mode); break; } sde_kms_info_add_keystr(info, "dfps support", panel->dfps_caps.dfps_support ? "true" : "false"); + if (panel->dfps_caps.dfps_support) { + sde_kms_info_add_keyint(info, "min_fps", + panel->dfps_caps.min_refresh_rate); + sde_kms_info_add_keyint(info, "max_fps", + panel->dfps_caps.max_refresh_rate); + } + switch (panel->phy_props.rotation) { case DSI_PANEL_ROTATE_NONE: sde_kms_info_add_keystr(info, "panel orientation", "none"); @@ -333,6 +463,10 @@ int dsi_conn_post_init(struct drm_connector *connector, case DSI_PANEL_ROTATE_V_FLIP: sde_kms_info_add_keystr(info, "panel orientation", "vert flip"); break; + case DSI_PANEL_ROTATE_HV_FLIP: + sde_kms_info_add_keystr(info, "panel orientation", + "horz & vert flip"); + break; default: pr_debug("invalid panel rotation:%d\n", panel->phy_props.rotation); @@ -355,6 +489,25 @@ int dsi_conn_post_init(struct drm_connector *connector, break; } + if (mode_info && mode_info->roi_caps.enabled) { + sde_kms_info_add_keyint(info, "partial_update_num_roi", + mode_info->roi_caps.num_roi); + sde_kms_info_add_keyint(info, "partial_update_xstart", + mode_info->roi_caps.align.xstart_pix_align); + sde_kms_info_add_keyint(info, "partial_update_walign", + mode_info->roi_caps.align.width_pix_align); + sde_kms_info_add_keyint(info, "partial_update_wmin", + mode_info->roi_caps.align.min_width); + sde_kms_info_add_keyint(info, "partial_update_ystart", + mode_info->roi_caps.align.ystart_pix_align); + sde_kms_info_add_keyint(info, "partial_update_halign", + mode_info->roi_caps.align.height_pix_align); + sde_kms_info_add_keyint(info, "partial_update_hmin", + mode_info->roi_caps.align.min_height); + sde_kms_info_add_keyint(info, "partial_update_roimerge", + mode_info->roi_caps.merge_rois); + } + end: return 0; } @@ -390,11 +543,25 @@ enum drm_connector_status dsi_conn_detect(struct drm_connector *conn, return status; } +void dsi_connector_put_modes(struct drm_connector *connector, + void *display) +{ + struct drm_display_mode *drm_mode; + struct dsi_display_mode dsi_mode; + + if (!connector || !display) + return; + + list_for_each_entry(drm_mode, &connector->modes, head) { + convert_to_dsi_mode(drm_mode, &dsi_mode); + dsi_display_put_mode(display, &dsi_mode); + } +} + int dsi_connector_get_modes(struct drm_connector *connector, void *display) { u32 count = 0; - u32 size = 0; struct dsi_display_mode *modes = NULL; struct drm_display_mode drm_mode; int rc, i; @@ -407,45 +574,36 @@ int dsi_connector_get_modes(struct drm_connector *connector, */ goto end; } - rc = dsi_display_get_modes(display, NULL, &count); + rc = dsi_display_get_mode_count(display, &count); if (rc) { pr_err("failed to get num of modes, rc=%d\n", rc); - goto error; - } - - size = count * sizeof(*modes); - modes = kzalloc(size, GFP_KERNEL); - if (!modes) { - count = 0; goto end; } - rc = dsi_display_get_modes(display, modes, &count); + rc = dsi_display_get_modes(display, &modes); if (rc) { pr_err("failed to get modes, rc=%d\n", rc); count = 0; - goto error; + goto end; } for (i = 0; i < count; i++) { struct drm_display_mode *m; memset(&drm_mode, 0x0, sizeof(drm_mode)); - convert_to_drm_mode(&modes[i], &drm_mode); + dsi_convert_to_drm_mode(&modes[i], &drm_mode); m = drm_mode_duplicate(connector->dev, &drm_mode); if (!m) { pr_err("failed to add mode %ux%u\n", drm_mode.hdisplay, drm_mode.vdisplay); count = -ENOMEM; - goto error; + goto end; } m->width_mm = connector->display_info.width_mm; m->height_mm = connector->display_info.height_mm; drm_mode_probed_add(connector, m); } -error: - kfree(modes); end: pr_debug("MODE COUNT =%d\n\n", count); return count; @@ -487,6 +645,72 @@ int dsi_conn_pre_kickoff(struct drm_connector *connector, return dsi_display_pre_kickoff(display, params); } +void dsi_conn_enable_event(struct drm_connector *connector, + uint32_t event_idx, bool enable, void *display) +{ + struct dsi_event_cb_info event_info; + + memset(&event_info, 0, sizeof(event_info)); + + event_info.event_cb = sde_connector_trigger_event; + event_info.event_usr_ptr = connector; + + dsi_display_enable_event(display, event_idx, &event_info, enable); +} + +int dsi_conn_post_kickoff(struct drm_connector *connector) +{ + struct drm_encoder *encoder; + struct dsi_bridge *c_bridge; + struct dsi_display_mode adj_mode; + struct dsi_display *display; + struct dsi_display_ctrl *m_ctrl, *ctrl; + int i, rc = 0; + + if (!connector || !connector->state) { + pr_err("invalid connector or connector state"); + return -EINVAL; + } + + encoder = connector->state->best_encoder; + if (!encoder) { + pr_debug("best encoder is not available"); + return 0; + } + + c_bridge = to_dsi_bridge(encoder->bridge); + adj_mode = c_bridge->dsi_mode; + display = c_bridge->display; + + if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) { + m_ctrl = &display->ctrl[display->clk_master_idx]; + rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false); + if (rc) { + pr_err("[%s] failed to dfps update rc=%d\n", + display->name, rc); + return -EINVAL; + } + + /* Update the rest of the controllers */ + for (i = 0; i < display->ctrl_count; i++) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_timing_db_update(ctrl->ctrl, false); + if (rc) { + pr_err("[%s] failed to dfps update rc=%d\n", + display->name, rc); + return -EINVAL; + } + } + + c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR; + } + + return 0; +} + struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display, struct drm_device *dev, struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h index 4339a11ec1c441049cde32f0b5b075d12a954350..ec58479d7b4ab0c39302cc03e9fe7800eb9a641e 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h @@ -33,15 +33,17 @@ struct dsi_bridge { }; /** - * dsi_conn_post_init - callback to perform additional initialization steps + * dsi_conn_set_info_blob - callback to perform info blob initialization * @connector: Pointer to drm connector structure * @info: Pointer to sde connector info structure * @display: Pointer to private display handle + * @mode_info: Pointer to mode info structure * Returns: Zero on success */ -int dsi_conn_post_init(struct drm_connector *connector, +int dsi_conn_set_info_blob(struct drm_connector *connector, void *info, - void *display); + void *display, + struct msm_mode_info *mode_info); /** * dsi_conn_detect - callback to determine if connector is connected @@ -63,6 +65,26 @@ enum drm_connector_status dsi_conn_detect(struct drm_connector *conn, int dsi_connector_get_modes(struct drm_connector *connector, void *display); +/** + * dsi_connector_put_modes - callback to free up drm modes of the connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + */ +void dsi_connector_put_modes(struct drm_connector *connector, + void *display); + +/** + * dsi_conn_get_mode_info - retrieve information on the mode selected + * @drm_mode: Display mode set for the display + * @mode_info: Out parameter. information of the mode. + * @max_mixer_width: max width supported by HW layer mixer + * @display: Pointer to private display structure + * Returns: Zero on success + */ +int dsi_conn_get_mode_info(const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, u32 max_mixer_width, + void *display); + /** * dsi_conn_mode_valid - callback to determine if specified mode is valid * @connector: Pointer to drm connector structure @@ -74,6 +96,16 @@ enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode, void *display); +/** + * dsi_conn_enable_event - callback to notify DSI driver of event registeration + * @connector: Pointer to drm connector structure + * @event_idx: Connector event index + * @enable: Whether or not the event is enabled + * @display: Pointer to private display handle + */ +void dsi_conn_enable_event(struct drm_connector *connector, + uint32_t event_idx, bool enable, void *display); + struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display, struct drm_device *dev, struct drm_encoder *encoder); @@ -91,4 +123,19 @@ int dsi_conn_pre_kickoff(struct drm_connector *connector, void *display, struct msm_display_kickoff_params *params); +/** + * dsi_display_post_kickoff - program post kickoff-time features + * @connector: Pointer to drm connector structure + * Returns: Zero on success + */ +int dsi_conn_post_kickoff(struct drm_connector *connector); + +/** + * dsi_convert_to_drm_mode - Update drm mode with dsi mode information + * @dsi_mode: input parameter. structure having dsi mode information. + * @drm_mode: output parameter. DRM mode set for the display + */ +void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, + struct drm_display_mode *drm_mode); + #endif /* _DSI_DRM_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h index 8250da3af0e41ab4830f6f269bf93e8617737a83..174be9f0d8f252e73576a05b8edb6330a2c2424e 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h @@ -37,7 +37,7 @@ readl_relaxed((dsi_hw)->disp_cc_base + (off)) #define DSI_DISP_CC_W32(dsi_hw, off, val) \ do {\ - pr_err("[DSI_%d][%s] - [0x%08x]\n", \ + pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ (dsi_hw)->index, #off, val); \ writel_relaxed((val), (dsi_hw)->disp_cc_base + (off)); \ } while (0) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index b814eb8750f381251e7713cfcdc79b3b04c9a2d0..0ffece38c3bc72dc847bb7d2f03b33427c873308 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -12,32 +12,89 @@ * */ +#define pr_fmt(fmt) "msm-dsi-panel:[%s:%d] " fmt, __func__, __LINE__ #include #include #include #include +#include